From aa458a0a13d18882354f33c07b0a4e8e82e7a424 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 9 Aug 2005 00:32:32 +0000 Subject: * Update HACKING * Change DBUS API: txt record lists are now coded as "aay" instead of "as". Unfortunately this triggers this bug: https://bugs.freedesktop.org/show_bug.cgi?id=4023 If you want to use avahi-publish-service you need to apply the included patch. * change avahi-bookmarks to listen on 127.0.0.1 only * add ftp and https browsing support to avahi-bookmarks, but disable it due to python-dbus bugs * update avahi module for python to provide functions to convert between tring lists and lists of lists of bytes * add avahi_strlst_add_anonymous() git-svn-id: file:///home/lennart/svn/public/avahi/trunk@281 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-common/strlst.c | 17 ++++++-- avahi-common/strlst.h | 10 ++++- avahi-daemon/EntryGroup.introspect | 2 +- avahi-daemon/Server.introspect | 2 +- avahi-daemon/dbus-protocol.c | 81 +++++++++++++++++++++++++++++------- avahi-utils/avahi-bookmarks.in | 25 +++++++---- avahi-utils/avahi-browse.in | 2 +- avahi-utils/avahi-discover.in | 4 +- avahi-utils/avahi-publish-service.in | 3 +- avahi-utils/avahi/__init__.py | 39 ++++++++++++++++- docs/HACKING | 11 +++++ docs/TODO | 3 +- 12 files changed, 162 insertions(+), 37 deletions(-) diff --git a/avahi-common/strlst.c b/avahi-common/strlst.c index d4d67da..46ed852 100644 --- a/avahi-common/strlst.c +++ b/avahi-common/strlst.c @@ -28,14 +28,25 @@ #include "strlst.h" +AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, guint size) { + AvahiStringList *n; + + n = g_malloc(sizeof(AvahiStringList) + size); + n->next = l; + n->size = size; + + return n; +} + AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const guint8*text, guint size) { AvahiStringList *n; g_assert(text); - n = g_malloc(sizeof(AvahiStringList) + size); - n->next = l; - memcpy(n->text, text, n->size = size); + n = avahi_string_list_add_anonymous(l, size); + + if (size > 0) + memcpy(n->text, text, size); return n; } diff --git a/avahi-common/strlst.h b/avahi-common/strlst.h index 99a9d2a..a4a4202 100644 --- a/avahi-common/strlst.h +++ b/avahi-common/strlst.h @@ -62,10 +62,17 @@ void avahi_string_list_free(AvahiStringList *l); * start. */ AvahiStringList *avahi_string_list_add(AvahiStringList *l, const gchar *text); -/** Append am arbitrary length byte string to the list. Returns the +/** Append an arbitrary length byte string to the list. Returns the * new list start. */ AvahiStringList *avahi_string_list_add_arbitrary(AvahiStringList *l, const guint8 *text, guint size); +/** Append a new entry to the string list. The string is not filled +with data. The caller should fill in string data afterwards by writing +it to l->text, where l is the pointer returned by this function. This +function exists solely to optimize a few operations where otherwise +superfluous string copying would be necessary. */ +AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, guint size); + /** Same as avahi_string_list_add(), but takes a variable number of * NUL terminated strings. The argument list must be terminated by a * NULL pointer. Returns the new list start. */ @@ -99,6 +106,7 @@ AvahiStringList* avahi_string_list_reverse(AvahiStringList *l); /** Return the number of elements in the string list */ guint avahi_string_list_length(const AvahiStringList *l); + AVAHI_C_DECL_END #endif diff --git a/avahi-daemon/EntryGroup.introspect b/avahi-daemon/EntryGroup.introspect index a33f338..40ddf3a 100644 --- a/avahi-daemon/EntryGroup.introspect +++ b/avahi-daemon/EntryGroup.introspect @@ -35,7 +35,7 @@ - + diff --git a/avahi-daemon/Server.introspect b/avahi-daemon/Server.introspect index 4fa7d5e..4a93906 100644 --- a/avahi-daemon/Server.introspect +++ b/avahi-daemon/Server.introspect @@ -94,7 +94,7 @@ - + diff --git a/avahi-daemon/dbus-protocol.c b/avahi-daemon/dbus-protocol.c index 7fe6bf9..3653f4e 100644 --- a/avahi-daemon/dbus-protocol.c +++ b/avahi-daemon/dbus-protocol.c @@ -56,6 +56,8 @@ typedef struct ServiceResolverInfo ServiceResolverInfo; #define MAX_OBJECTS_PER_CLIENT 50 #define MAX_ENTRIES_PER_ENTRY_GROUP 20 +#define VALGRIND_WORKAROUND + struct EntryGroupInfo { guint id; Client *client; @@ -600,6 +602,8 @@ static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m, gchar **txt = NULL; gint txt_len; AvahiStringList *strlst; + DBusMessageIter iter, sub; + int j; if (!dbus_message_get_args( m, &error, @@ -610,21 +614,53 @@ static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m, DBUS_TYPE_STRING, &domain, DBUS_TYPE_STRING, &host, DBUS_TYPE_UINT16, &port, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &txt, &txt_len, DBUS_TYPE_INVALID) || !type || !name) { avahi_log_warn("Error parsing EntryGroup::AddService message"); goto fail; } + dbus_message_iter_init(m, &iter); + + for (j = 0; j < 7; j++) + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_ARRAY) { + avahi_log_warn("Error parsing EntryGroup::AddService message 2"); + goto fail; + } + + strlst = NULL; + dbus_message_iter_recurse(&iter, &sub); + + for (;;) { + DBusMessageIter sub2; + int at, n; + guint8 *k; + + if ((at = dbus_message_iter_get_arg_type(&sub)) == DBUS_TYPE_INVALID) + break; + + g_assert(at == DBUS_TYPE_ARRAY); + + if (dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_BYTE) { + avahi_log_warn("Error parsing EntryGroup::AddService message"); + goto fail; + } + + dbus_message_iter_recurse(&sub, &sub2); + dbus_message_iter_get_fixed_array(&sub2, &k, &n); + strlst = avahi_string_list_add_arbitrary(strlst, k, n); + + dbus_message_iter_next(&sub); + } + if (i->n_entries >= MAX_ENTRIES_PER_ENTRY_GROUP) { + avahi_string_list_free(strlst); avahi_log_warn("Too many entries per entry group, client request failed."); - dbus_free_string_array(txt); return respond_error(c, m, AVAHI_ERR_TOO_MANY_ENTRIES, NULL); } - strlst = avahi_string_list_new_from_array((const gchar**) txt, txt_len); - dbus_free_string_array(txt); - if (domain && !*domain) domain = NULL; @@ -994,10 +1030,10 @@ static void service_resolver_callback( if (event == AVAHI_RESOLVER_FOUND) { char t[256], *pt = t; gint32 i_interface, i_protocol, i_aprotocol; - gchar **array; guint n, j; AvahiStringList *p; DBusMessage *reply; + DBusMessageIter iter, sub; g_assert(host_name); @@ -1008,12 +1044,6 @@ static void service_resolver_callback( i_protocol = (gint32) protocol; i_aprotocol = (gint32) a->family; - array = g_new(gchar*, (n = avahi_string_list_length(txt))); - - /** FIXME: DBUS doesn't support strings that include NUL bytes (?) */ - for (p = txt, j = n-1; p; p = p->next, j--) - array[j] = g_strndup((gchar*) p->text, p->size); - reply = dbus_message_new_method_return(i->message); dbus_message_append_args( reply, @@ -1026,12 +1056,22 @@ static void service_resolver_callback( DBUS_TYPE_INT32, &i_aprotocol, DBUS_TYPE_STRING, &pt, DBUS_TYPE_UINT16, &port, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, n, DBUS_TYPE_INVALID); - for (j = 0; j < n; j++) - g_free(array[j]); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "ay", &sub); + + for (p = txt, j = n-1; p; p = p->next, j--) { + DBusMessageIter sub2; + const guint8 *data = p->text; + + dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2); + dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size); + dbus_message_iter_close_container(&sub, &sub2); + } + dbus_message_iter_close_container(&iter, &sub); + dbus_connection_send(server->bus, reply, NULL); dbus_message_unref(reply); } else { @@ -1111,6 +1151,10 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void goto fail; } +#ifdef VALGRIND_WORKAROUND + return respond_string(c, m, "blah"); +#else + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { gchar txt[256]; g_snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno)); @@ -1130,7 +1174,8 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void close(fd); return respond_string(c, m, ifr.ifr_name); - +#endif + } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceIndexByName")) { gchar *n; int fd; @@ -1141,6 +1186,9 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void goto fail; } +#ifdef VALGRIND_WORKAROUND + return respond_int32(c, m, 1); +#else if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { gchar txt[256]; g_snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno)); @@ -1160,6 +1208,7 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void close(fd); return respond_int32(c, m, ifr.ifr_ifindex); +#endif } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetAlternativeHostName")) { gchar *n, * t; diff --git a/avahi-utils/avahi-bookmarks.in b/avahi-utils/avahi-bookmarks.in index 72f8e44..953020a 100755 --- a/avahi-utils/avahi-bookmarks.in +++ b/avahi-utils/avahi-bookmarks.in @@ -41,6 +41,8 @@ except ImportError: print "Sorry, to use this tool you need to install twisted." sys.exit(1) +urlproto = { "_http._tcp" : "http", "_https._tcp" : "https", "_ftp._tcp" : "ftp" } + class AvahiBookmarks(resource.Resource): isLeaf = True @@ -49,20 +51,28 @@ class AvahiBookmarks(resource.Resource): def __init__(self): resource.Resource.__init__(self) - self.bus = dbus.SystemBus() self.server = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) self.version_string = self.server.GetVersionString() - self.browser = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "_http._tcp", "local")), avahi.DBUS_INTERFACE_SERVICE_BROWSER) + self.browse_service_type("_http._tcp") + + # Hurrah! if I enable one of the following lines, python segfaults. + #self.browse_service_type("_shttp._tcp") + #self.browse_service_type("_ftp._tcp") - self.browser.connect_to_signal('ItemNew', self.new_service) - self.browser.connect_to_signal('ItemRemove', self.remove_service) + def browse_service_type(self, stype): + + browser = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, stype, "local")), avahi.DBUS_INTERFACE_SERVICE_BROWSER) + browser.connect_to_signal('ItemNew', self.new_service) + browser.connect_to_signal('ItemRemove', self.remove_service) def find_path(self, txt): - for k in txt: + l = avahi.txt_array_to_string_array(txt) + + for k in l: if k[:5] == "path=": return k[5:] @@ -86,8 +96,7 @@ class AvahiBookmarks(resource.Resource): path = self.find_path(v[4]) - - t += '
  • %s
  • ' % (v[2], port, path, k[2]) + t += '
  • %s
  • ' % (urlproto[k[3]], v[2], port, path, k[2]) t += '' @@ -110,7 +119,7 @@ port = 8080 if __name__ == '__main__': site = server.Site(AvahiBookmarks()) - reactor.listenTCP(port, site) + reactor.listenTCP(port, site, interface="127.0.0.1") print "Now point your web browser to http://localhost:%u/!" % port diff --git a/avahi-utils/avahi-browse.in b/avahi-utils/avahi-browse.in index 69a8bfd..3507b41 100755 --- a/avahi-utils/avahi-browse.in +++ b/avahi-utils/avahi-browse.in @@ -80,7 +80,7 @@ def siocgifname(interface): def service_resolved(interface, protocol, name, type, domain, host, aprotocol, address, port, txt): print "Service data for service '%s' of type '%s' in domain '%s' on %s.%i:" % (name, type, domain, siocgifname(interface), protocol) - print "\tHost %s (%s), port %i, TXT data: %s" % (host, address, port, str(txt)) + print "\tHost %s (%s), port %i, TXT data: %s" % (host, address, port, avahi.txt_array_to_string_array(txt)) def print_error(err): print "Error:", str(err) diff --git a/avahi-utils/avahi-discover.in b/avahi-utils/avahi-discover.in index 6c78c51..d869761 100755 --- a/avahi-utils/avahi-discover.in +++ b/avahi-utils/avahi-discover.in @@ -68,8 +68,8 @@ class Main_window(SimpleGladeApp): def service_resolved(self, interface, protocol, name, type, domain, host, aprotocol, address, port, txt): print "Service data for service '%s' of type '%s' in domain '%s' on %i.%i:" % (name, type, domain, interface, protocol) - print "\tHost %s (%s), port %i, TXT data: %s" % (host, address, port, str(txt)) - self.update_label(interface, protocol, name, type, domain, host, aprotocol, address, port, str(txt)) + print "\tHost %s (%s), port %i, TXT data: %s" % (host, address, port, str(avahi.txt_array_to_string_array(txt))) + self.update_label(interface, protocol, name, type, domain, host, aprotocol, address, port, str(avahi.txt_array_to_string_array(txt))) def print_error(err): print "Error:", str(err) diff --git a/avahi-utils/avahi-publish-service.in b/avahi-utils/avahi-publish-service.in index 50b1908..0f278eb 100755 --- a/avahi-utils/avahi-publish-service.in +++ b/avahi-utils/avahi-publish-service.in @@ -88,7 +88,8 @@ def add_service(): print "Adding service '%s' of type '%s' ..." % (name, stype) group.connect_to_signal('StateChanged', entry_group_state_changed) - group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, name, stype, domain, host, dbus.UInt16(port), txt) + + group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, name, stype, domain, host, dbus.UInt16(port), avahi.string_array_to_txt_array(txt)) group.Commit() def entry_group_state_changed(state): diff --git a/avahi-utils/avahi/__init__.py b/avahi-utils/avahi/__init__.py index c68e177..90d2b76 100644 --- a/avahi-utils/avahi/__init__.py +++ b/avahi-utils/avahi/__init__.py @@ -18,7 +18,7 @@ # USA. # Some definitions matching those in core.h -import socket +import socket, dbus SERVER_INVALID, SERVER_REGISTERING, SERVER_RUNNING, SERVER_COLLISION = range(-1, 3) @@ -37,3 +37,40 @@ DBUS_INTERFACE_ENTRY_GROUP = DBUS_NAME + ".EntryGroup" DBUS_INTERFACE_DOMAIN_BROWSER = DBUS_NAME + ".DomainBrowser" DBUS_INTERFACE_SERVICE_TYPE_BROWSER = DBUS_NAME + ".ServiceTypeBrowser" DBUS_INTERFACE_SERVICE_BROWSER = DBUS_NAME + ".ServiceBrowser" + +def byte_array_to_string(s): + r = "" + + for c in s: + + if c >= 32 and c < 127: + r += "%c" % c + else: + r += "." + + return r + +def txt_array_to_string_array(t): + l = [] + + for s in t: + l.append(byte_array_to_string(s)) + + return l + + +def string_to_byte_array(s): + r = [] + + for c in s: + r.append(dbus.Byte(ord(c))) + + return r + +def string_array_to_txt_array(t): + l = [] + + for s in t: + l.append(string_to_byte_array(s)) + + return l diff --git a/docs/HACKING b/docs/HACKING index a31878d..46504da 100644 --- a/docs/HACKING +++ b/docs/HACKING @@ -25,6 +25,17 @@ Please comply with the following rules when hacking on Avahi: * Never forget that Avahi should be buildable without DBUS, GTK or python! + * Before commiting, test your code! In case of C consider running it + a few times through valgrind, to make sure that you got everything + right. You have to call libtool explicitly when running valgrind + on binaries that depend on shared objects. e.g: + + libtool --mode=execute valgrind ./avahi-daemon + + Please note that valgrind can't find you all bugs. Please check + your code thrice with your brain before committing. Valgrind is + only a final check. + * When you code in C, please compile with the following gcc options from time to time: diff --git a/docs/TODO b/docs/TODO index ba9a14a..5ce60ce 100644 --- a/docs/TODO +++ b/docs/TODO @@ -1,6 +1,4 @@ todo: -* finish DBUS stuff: - - allow NUL bytes in TXT records * release! later: @@ -49,3 +47,4 @@ done: * drop trailing dot on avahi_normalize_name() * add entry_group::reset() * add internal error codes +* finish DBUS stuff: allow NUL bytes in TXT records -- cgit