From 7e2e7661c325718982387c3355d4f929e4025ec7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Sep 2007 23:46:14 +0200 Subject: add avahi browsing support --- Makefile | 6 +- lassi-avahi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lassi-avahi.h | 29 ++++++++ lassi-osd.c | 3 +- lassi-osd.h | 3 +- lassi-server.c | 43 +++++------ lassi-server.h | 5 ++ 7 files changed, 289 insertions(+), 29 deletions(-) create mode 100644 lassi-avahi.c create mode 100644 lassi-avahi.h diff --git a/Makefile b/Makefile index c21ca57..d4f9749 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -CFLAGS=-Wall -Wextra -W -O0 -g -pipe -Wno-unused-parameter `pkg-config --cflags dbus-glib-1 glib-2.0 gtk+-2.0 xtst` -LIBS=`pkg-config --libs dbus-glib-1 glib-2.0 gtk+-2.0 xtst` +CFLAGS=-Wall -Wextra -W -O0 -g -pipe -Wno-unused-parameter `pkg-config --cflags dbus-glib-1 glib-2.0 gtk+-2.0 xtst avahi-glib avahi-client avahi-ui` +LIBS=`pkg-config --libs dbus-glib-1 glib-2.0 gtk+-2.0 xtst avahi-glib avahi-client avahi-ui` -mango-lassi: lassi-server.o lassi-grab.o lassi-osd.o lassi-order.o lassi-clipboard.o *.h +mango-lassi: lassi-server.o lassi-grab.o lassi-osd.o lassi-order.o lassi-clipboard.o lassi-avahi.o *.h $(CC) $^ -o $@ $(LIBS) $(CFLAGS) clean: diff --git a/lassi-avahi.c b/lassi-avahi.c new file mode 100644 index 0000000..9fb81c9 --- /dev/null +++ b/lassi-avahi.c @@ -0,0 +1,229 @@ +#include + +#include +#include +#include + +#include "lassi-avahi.h" + +#define SERVICE_TYPE "_mango-lassi._tcp" + +/* FIXME: Error and collision handling is suboptimal */ + +static void resolve_cb( + AvahiServiceResolver *r, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void* userdata) { + + LassiAvahiInfo *i = userdata; + + g_assert(r); + g_assert(i); + + /* Called whenever a service has been resolved successfully or timed out */ + + switch (event) { + case AVAHI_RESOLVER_FOUND: { + char a[AVAHI_ADDRESS_STR_MAX], *t; + + avahi_address_snprint(a, sizeof(a), address); + t = g_strdup_printf("tcp:port=%u,host=%s", port, a); + lassi_server_connect(i->server, t); + g_free(t); + break; + } + + case AVAHI_RESOLVER_FAILURE: + g_message("Failed to resolve service '%s' of type '%s' in domain '%s': %s", name, type, domain, avahi_strerror(avahi_client_errno(i->client))); + break; + + } + + avahi_service_resolver_free(r); + } + +static void browse_cb( + AvahiServiceBrowser *b, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AvahiLookupResultFlags flags, + void* userdata) { + + LassiAvahiInfo *i = userdata; + + g_assert(b); + g_assert(i); + + switch (event) { + case AVAHI_BROWSER_NEW: + + if (!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN)) + if (!(avahi_service_resolver_new(i->client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_cb, i))) + g_message("Failed to resolve service '%s': %s", name, avahi_strerror(avahi_client_errno(i->client))); + break; + + case AVAHI_BROWSER_REMOVE: + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; + + case AVAHI_BROWSER_FAILURE: + g_message("Browsing failed: %s", avahi_strerror(avahi_client_errno(i->client))); + break; + } +} + + +static void create_service(LassiAvahiInfo *i); + +static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { + LassiAvahiInfo *i = userdata; + + g_assert(g); + g_assert(i); + + i->group = g; + + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + g_message("Service '%s' successfully established.", i->service_name); + break; + + case AVAHI_ENTRY_GROUP_COLLISION : { + char *n; + + n = avahi_alternative_service_name(i->service_name); + avahi_free(i->service_name); + i->service_name = n; + + g_message("Service name collision, renaming service to '%s'", n); + + /* And recreate the services */ + create_service(i); + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE : + g_message("Entry group failure: %s", avahi_strerror(avahi_client_errno(i->client))); + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + } +} + +static void create_service(LassiAvahiInfo *i) { + g_assert(i); + + if (!i->group) + if (!(i->group = avahi_entry_group_new(i->client, entry_group_callback, i))) { + g_message("avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(i->client))); + return; + } + + if (avahi_entry_group_is_empty(i->group)) { + int ret; + + if (!i->service_name) + i->service_name = g_strdup(i->server->id); + + if ((ret = avahi_entry_group_add_service(i->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, i->service_name, SERVICE_TYPE, NULL, NULL, i->server->port, NULL)) < 0) { + g_message("Failed to add service: %s", avahi_strerror(ret)); + return; + } + + if ((ret = avahi_entry_group_commit(i->group)) < 0) { + g_message("Failed to commit entry group: %s", avahi_strerror(ret)); + return; + } + } +} + +static void client_cb(AvahiClient *client, AvahiClientState state, void *userdata) { + LassiAvahiInfo *i = userdata; + + i->client = client; + + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + if (!i->group) + create_service(i); + break; + + case AVAHI_CLIENT_FAILURE: + g_message("Client failure: %s", avahi_strerror(avahi_client_errno(client))); + break; + + case AVAHI_CLIENT_S_COLLISION: + case AVAHI_CLIENT_S_REGISTERING: + if (i->group) + avahi_entry_group_reset(i->group); + + break; + + case AVAHI_CLIENT_CONNECTING: + ; + } +} + +int lassi_avahi_init(LassiAvahiInfo *i, LassiServer *server) { + int error; + + g_assert(i); + g_assert(server); + + memset(i, 0, sizeof(*i)); + i->server = server; + + avahi_set_allocator(avahi_glib_allocator()); + + if (!(i->poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT))) { + g_message("avahi_glib_poll_new() failed."); + goto fail; + } + + if (!(i->client = avahi_client_new(avahi_glib_poll_get(i->poll), 0, client_cb, i, &error))) { + g_message("avahi_client_new() failed: %s", avahi_strerror(error)); + goto fail; + } + + if (!(i->browser = avahi_service_browser_new(i->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, SERVICE_TYPE, NULL, 0, browse_cb, i))) { + g_message("avahi_service_browser_new(): %s", avahi_strerror(avahi_client_errno(i->client))); + goto fail; + } + + return 0; + +fail: + lassi_avahi_done(i); + return -1; +} + +void lassi_avahi_done(LassiAvahiInfo *i) { + g_assert(i); + + if (i->client) + avahi_client_free(i->client); + + if (i->poll) + avahi_glib_poll_free(i->poll); + + g_free(i->service_name); + + memset(i, 0, sizeof(*i)); +} diff --git a/lassi-avahi.h b/lassi-avahi.h new file mode 100644 index 0000000..34484db --- /dev/null +++ b/lassi-avahi.h @@ -0,0 +1,29 @@ +#ifndef foolassiavahihfoo +#define foolassiavahihfoo + +#include +#include +#include +#include + +typedef struct LassiAvahiInfo LassiAvahiInfo; +struct LassiServer; + +struct LassiAvahiInfo { + struct LassiServer *server; + + AvahiGLibPoll *poll; + AvahiClient *client; + + AvahiEntryGroup *group; + char *service_name; + + AvahiServiceBrowser *browser; +}; + +#include "lassi-server.h" + +int lassi_avahi_init(LassiAvahiInfo *i, LassiServer *server); +void lassi_avahi_done(LassiAvahiInfo *i); + +#endif diff --git a/lassi-osd.c b/lassi-osd.c index f5824a6..ae9a21c 100644 --- a/lassi-osd.c +++ b/lassi-osd.c @@ -7,7 +7,7 @@ #include "lassi-osd.h" -void lassi_osd_init(LassiOsdInfo *osd) { +int lassi_osd_init(LassiOsdInfo *osd) { GtkWidget *hbox; GdkColor color; guint32 cardinal; @@ -66,6 +66,7 @@ void lassi_osd_init(LassiOsdInfo *osd) { g_debug("WINDOW=%p", osd->window); + return 0; } void lassi_osd_done(LassiOsdInfo *osd) { diff --git a/lassi-osd.h b/lassi-osd.h index 4f3fc1b..2a792eb 100644 --- a/lassi-osd.h +++ b/lassi-osd.h @@ -9,11 +9,10 @@ struct LassiOsdInfo { GtkWidget *window, *label, *left_icon, *right_icon; }; -void lassi_osd_init(LassiOsdInfo *osd); +int lassi_osd_init(LassiOsdInfo *osd); void lassi_osd_done(LassiOsdInfo *osd); void lassi_osd_set_text(LassiOsdInfo *osd, const char *text, const char *icon_name_left, const char *icon_name_right); void lassi_osd_hide(LassiOsdInfo *osd); - #endif diff --git a/lassi-server.c b/lassi-server.c index 7a6f56c..7584d95 100644 --- a/lassi-server.c +++ b/lassi-server.c @@ -16,16 +16,16 @@ #include "lassi-grab.h" #include "lassi-order.h" #include "lassi-clipboard.h" +#include "lassi-avahi.h" #define LASSI_INTERFACE "org.gnome.MangoLassi" -#define PORT_MIN 4000 -#define PORT_MAX 4050 +#define PORT_MIN 7421 +#define PORT_MAX (PORT_MIN + 50) #define CONNECTIONS_MAX 16 static void server_disconnect_all(LassiServer *ls); -static LassiConnection* server_connect(LassiServer *ls, const char *a); static void server_send_update_grab(LassiServer *ls, int y); static void server_broadcast(LassiServer *ls, DBusMessage *m, LassiConnection *except) { @@ -720,7 +720,7 @@ static int signal_node_added(LassiConnection *lc, DBusMessage *m) { if (g_hash_table_lookup(lc->server->connections_by_id, id)) return 0; - if (!(server_connect(lc->server, address))) { + if (!(lassi_server_connect(lc->server, address))) { DBusMessage *n; dbus_bool_t b; @@ -1308,8 +1308,10 @@ static int server_init(LassiServer *ls) { ls->dbus_server = dbus_server_listen(t, &e); g_free(t); - if (ls->dbus_server) + if (ls->dbus_server) { + ls->port = port; break; + } if (!dbus_error_has_name(&e, DBUS_ERROR_ADDRESS_IN_USE)) { g_warning("Failed to create D-Bus server: %s %s", e.message, e.name); @@ -1331,13 +1333,21 @@ static int server_init(LassiServer *ls) { ls->connections_by_id = g_hash_table_new(g_str_hash, g_str_equal); - ls->id = g_strdup_printf("%u", getpid()); + ls->id = g_strdup_printf("%s's desktop on %s", g_get_user_name(), g_get_host_name()); ls->address = dbus_server_get_address(ls->dbus_server); ls->order = g_list_prepend(NULL, g_strdup(ls->id)); - lassi_grab_init(&ls->grab_info, ls); - lassi_osd_init(&ls->osd_info); - lassi_clipboard_init(&ls->clipboard_info, ls); + if (lassi_grab_init(&ls->grab_info, ls) < 0) + goto finish; + + if (lassi_osd_init(&ls->osd_info) < 0) + goto finish; + + if (lassi_clipboard_init(&ls->clipboard_info, ls) < 0) + goto finish; + + if (lassi_avahi_init(&ls->avahi_info, ls) < 0) + goto finish; r = 0; @@ -1378,7 +1388,7 @@ static void server_done(LassiServer *ls) { memset(ls, 0, sizeof(*ls)); } -static LassiConnection* server_connect(LassiServer *ls, const char *a) { +LassiConnection* lassi_server_connect(LassiServer *ls, const char *a) { DBusError e; DBusConnection *c; LassiConnection *lc = NULL; @@ -1414,19 +1424,6 @@ int main(int argc, char *argv[]) { if (server_init(&ls) < 0) goto fail; - server_connect(&ls, "tcp:port=4000,host=lambda.local"); - server_connect(&ls, "tcp:port=4001,host=lambda.local"); - server_connect(&ls, "tcp:port=4002,host=lambda.local"); - server_connect(&ls, "tcp:port=4003,host=lambda.local"); - server_connect(&ls, "tcp:port=4000,host=ecstasy.local"); - server_connect(&ls, "tcp:port=4001,host=ecstasy.local"); - server_connect(&ls, "tcp:port=4002,host=ecstasy.local"); - server_connect(&ls, "tcp:port=4003,host=ecstasy.local"); - server_connect(&ls, "tcp:port=4000,host=127.0.0.1"); - server_connect(&ls, "tcp:port=4001,host=127.0.0.1"); - server_connect(&ls, "tcp:port=4002,host=127.0.0.1"); - server_connect(&ls, "tcp:port=4003,host=127.0.0.1"); - gtk_main(); fail: diff --git a/lassi-server.h b/lassi-server.h index b8f7dc4..b6117ae 100644 --- a/lassi-server.h +++ b/lassi-server.h @@ -10,11 +10,13 @@ typedef struct LassiConnection LassiConnection; #include "lassi-grab.h" #include "lassi-osd.h" #include "lassi-clipboard.h" +#include "lassi-avahi.h" struct LassiServer { DBusServer *dbus_server; char *id, *address; + uint16_t port; /* All connections */ GList *connections; @@ -45,6 +47,7 @@ struct LassiServer { LassiGrabInfo grab_info; LassiOsdInfo osd_info; LassiClipboardInfo clipboard_info; + LassiAvahiInfo avahi_info; }; struct LassiConnection { @@ -67,4 +70,6 @@ int lassi_server_acquire_clipboard(LassiServer *ls, gboolean primary, char**targ int lassi_server_return_clipboard(LassiServer *ls, gboolean primary); int lassi_server_get_clipboard(LassiServer *ls, gboolean primary, const char *t, int *f, gpointer *p, int *l); +LassiConnection* lassi_server_connect(LassiServer *ls, const char *a); + #endif -- cgit