]> git.meshlink.io Git - catta/commitdiff
* implement record updating through the new flags AVAHI_PUBLISH_UPDATE
authorLennart Poettering <lennart@poettering.net>
Mon, 17 Oct 2005 00:20:33 +0000 (00:20 +0000)
committerLennart Poettering <lennart@poettering.net>
Mon, 17 Oct 2005 00:20:33 +0000 (00:20 +0000)
* add new helper function avahi_server_update_service_txt() to ease TXT record updating for services
* other minor cleanups

git-svn-id: file:///home/lennart/svn/public/avahi/trunk@790 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

avahi-common/defs.h
avahi-core/Makefile.am
avahi-core/announce.c
avahi-core/announce.h
avahi-core/avahi-test.c
avahi-core/iface.c
avahi-core/publish.h
avahi-core/server.c
avahi-core/update-test.c [new file with mode: 0644]

index d12ed642ca22de4c47b31202ff3ab14b90aac20a..41e4daafbbaf1af093cd37d92a98c4d29de31218 100644 (file)
@@ -161,7 +161,8 @@ typedef enum {
     AVAHI_PUBLISH_ALLOW_MULTIPLE = 8,   /**< For raw records: Allow multiple local records of this type, even if they are intended to be unique */
     AVAHI_PUBLISH_NO_REVERSE = 16,      /**< For address records: don't create a reverse (PTR) entry */
     AVAHI_PUBLISH_NO_COOKIE = 32,       /**< For service records: do not implicitly add the local service cookie to TXT data */
-    AVAHI_PUBLISH_IS_PROXY = 64         /**< For service records: this is a proxy for another host. This modifies behaviour of avahi_server_is_service_local() */
+    AVAHI_PUBLISH_IS_PROXY = 64,        /**< For service records: this is a proxy for another host. This modifies behaviour of avahi_server_is_service_local() */
+    AVAHI_PUBLISH_UPDATE = 128          /**< Update existing records instead of adding new ones */
 } AvahiPublishFlags;
 
 /** Some flags for lookup functions */
index 14b161a8309f09df7bd340a4a8b9e3e83337e2cf..b62a4d54c763403c6006773a9d1baa82dc1923ce 100644 (file)
@@ -42,7 +42,8 @@ noinst_PROGRAMS = \
        dns-test \
        timeeventq-test \
        hashmap-test \
-       querier-test
+       querier-test \
+       update-test
 
 libavahi_core_la_SOURCES = \
        timeeventq.c timeeventq.h\
@@ -74,7 +75,7 @@ libavahi_core_la_SOURCES = \
        wide-area.c wide-area.h \
        multicast-lookup.c multicast-lookup.h \
        querier.c querier.h
-       
+
 if HAVE_NETLINK
 libavahi_core_la_SOURCES += \
        iface-linux.c iface-linux.h \
@@ -96,6 +97,10 @@ avahi_test_SOURCES = \
 avahi_test_CFLAGS = $(AM_CFLAGS)
 avahi_test_LDADD = $(AM_LDADD) ../avahi-common/libavahi-common.la libavahi-core.la
 
+update_test_SOURCES = \
+       update-test.c
+update_test_CFLAGS = $(AM_CFLAGS)
+update_test_LDADD = $(AM_LDADD) ../avahi-common/libavahi-common.la libavahi-core.la
 
 querier_test_SOURCES = \
        querier-test.c
index 87966211e68f22234be76084426d051b49b76195..d1e5995bc1fcb1fb65b86315ff6640fdcac8e199 100644 (file)
@@ -230,13 +230,11 @@ static void go_to_initial_state(AvahiAnnouncement *a, int immediately) {
     if (a->state == AVAHI_PROBING && e->group)
         e->group->n_probing++;
 
-    if (a->state == AVAHI_PROBING) {
-        avahi_elapse_time(&tv, 0, immediately ? 0 : AVAHI_PROBE_JITTER_MSEC);
-        set_timeout(a, &tv);
-    } else if (a->state == AVAHI_ANNOUNCING) {
-        avahi_elapse_time(&tv, 0, immediately ? 0 : AVAHI_ANNOUNCEMENT_JITTER_MSEC);
-        set_timeout(a, &tv);
-    } else
+    if (a->state == AVAHI_PROBING) 
+        set_timeout(a, avahi_elapse_time(&tv, 0, AVAHI_PROBE_JITTER_MSEC));
+    else if (a->state == AVAHI_ANNOUNCING) 
+        set_timeout(a, avahi_elapse_time(&tv, 0, AVAHI_ANNOUNCEMENT_JITTER_MSEC));
+    else
         set_timeout(a, NULL);
 }
 
@@ -438,55 +436,123 @@ static void send_goodbye_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, v
     avahi_interface_post_response(i, g, e->flags & AVAHI_PUBLISH_UNIQUE, NULL, 1);
     avahi_record_unref(g);
 }
+
+static void reannounce(AvahiAnnouncement *a) {
+    AvahiEntry *e;
+    struct timeval tv;
+        
+    assert(a);
+    e = a->entry;
+
+    /* If the group this entry belongs to is not even commited, there's nothing to reannounce */
+    if (e->group && (e->group->state == AVAHI_ENTRY_GROUP_UNCOMMITED || e->group->state == AVAHI_ENTRY_GROUP_COLLISION))
+        return;
+
+    /* Because we might change state we decrease the probing counter first */
+    if (a->state == AVAHI_PROBING && a->entry->group)
+        a->entry->group->n_probing--;
     
-void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, int goodbye) {
-    assert(s);
-    assert(i);
+    if (a->state == AVAHI_PROBING ||
+        (a->state == AVAHI_WAITING && (e->flags & AVAHI_PUBLISH_UNIQUE) && !(e->flags & AVAHI_PUBLISH_NO_PROBE)))
 
-/*     avahi_log_debug("goodbye interface: %s.%u", i->hardware->name, i->protocol); */
+        /* We were probing or waiting after probe, so we restart probing from the beginning here */
+        
+        a->state = AVAHI_PROBING;
+    else if (a->state == AVAHI_WAITING)
 
-    if (goodbye && avahi_interface_is_relevant(i)) {
-        AvahiEntry *e;
+        /* We were waiting, but were not probing before, so we continue waiting  */
+        a->state = AVAHI_WAITING;
+
+    else if (e->flags & AVAHI_PUBLISH_NO_ANNOUNCE)
         
-        for (e = s->entries; e; e = e->entries_next)
-            if (!e->dead)
-                send_goodbye_callback(s->monitor, i, e);
-    }
+        /* No announcement needed */
+        a->state = AVAHI_ESTABLISHED;
+
+    else {
+        
+        /* Ok, let's restart announcing */
+        a->state = AVAHI_ANNOUNCING;
+    } 
+        
+    /* Now let's increase the probing counter again */
+    if (a->state == AVAHI_PROBING && e->group)
+        e->group->n_probing++;
+    
+    a->n_iteration = 1;
+    a->sec_delay = 1;
+
+    if (a->state == AVAHI_PROBING)
+        set_timeout(a, avahi_elapse_time(&tv, 0, AVAHI_PROBE_JITTER_MSEC));
+    else if (a->state == AVAHI_ANNOUNCING) 
+        set_timeout(a, avahi_elapse_time(&tv, 0, AVAHI_ANNOUNCEMENT_JITTER_MSEC));
+    else
+        set_timeout(a, NULL);
+}
 
-    while (i->announcements)
-        remove_announcement(s, i->announcements);
 
-/*     avahi_log_debug("goodbye interface done: %s.%u", i->hardware->name, i->protocol); */
+static void reannounce_walk_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, void* userdata) {
+    AvahiEntry *e = userdata;
+    AvahiAnnouncement *a;
+    
+    assert(m);
+    assert(i);
+    assert(e);
+    assert(!e->dead);
+
+    if (!(a = avahi_get_announcement(m->server, e, i)))
+        return;
+
+    reannounce(a);
 }
 
-void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, int goodbye) {
+void avahi_reannounce_entry(AvahiServer *s, AvahiEntry *e) {
+
     assert(s);
     assert(e);
+    assert(!e->dead);
+
+    avahi_interface_monitor_walk(s->monitor, e->interface, e->protocol, reannounce_walk_callback, e);
+}
     
-/*     avahi_log_debug("goodbye entry: %p", e); */
-    
-    if (goodbye && !e->dead)
-        avahi_interface_monitor_walk(s->monitor, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, send_goodbye_callback, e);
+void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, int send_goodbye, int remove) {
+    assert(s);
+    assert(i);
+
+    if (send_goodbye)
+        if (avahi_interface_is_relevant(i)) {
+            AvahiEntry *e;
+            
+            for (e = s->entries; e; e = e->entries_next)
+                if (!e->dead)
+                    send_goodbye_callback(s->monitor, i, e);
+        }
 
-    while (e->announcements)
-        remove_announcement(s, e->announcements);
+    if (remove)
+        while (i->announcements)
+            remove_announcement(s, i->announcements);
+}
 
-/*     avahi_log_debug("goodbye entry done: %p", e); */
+void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, int send_goodbye, int remove) {
+    assert(s);
+    assert(e);
+    
+    if (send_goodbye)
+        if (!e->dead)
+            avahi_interface_monitor_walk(s->monitor, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, send_goodbye_callback, e);
 
+    if (remove)
+        while (e->announcements)
+            remove_announcement(s, e->announcements);
 }
 
-void avahi_goodbye_all(AvahiServer *s, int goodbye) {
+void avahi_goodbye_all(AvahiServer *s, int send_goodbye, int remove) {
     AvahiEntry *e;
     
     assert(s);
 
-/*     avahi_log_debug("goodbye all"); */
-
     for (e = s->entries; e; e = e->entries_next)
         if (!e->dead)
-            avahi_goodbye_entry(s, e, goodbye);
-
-/*     avahi_log_debug("goodbye all done"); */
+            avahi_goodbye_entry(s, e, send_goodbye, remove);
 
 }
 
index 9183258b55bbcda81e88711b02a33fcb3eebdadc..21dd148f6a3fd35d49e2beed6f3a73ae338929b3 100644 (file)
@@ -63,11 +63,12 @@ void avahi_s_entry_group_check_probed(AvahiSEntryGroup *g, int immediately);
 int avahi_entry_is_registered(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
 int avahi_entry_is_probing(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
 
-void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, int send_goodbye);
-void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, int send_goodbye);
-
-void avahi_goodbye_all(AvahiServer *s, int send_goodbye);
+void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, int send_goodbye, int rem);
+void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, int send_goodbye, int rem);
+void avahi_goodbye_all(AvahiServer *s, int send_goodbye, int rem);
 
 AvahiAnnouncement *avahi_get_announcement(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
 
+void avahi_reannounce_entry(AvahiServer *s, AvahiEntry *e);
+
 #endif
index 46e68d55710c5ab57846c5bbdfbf0e7080446bba..cf8bd3b83c232aedb05913ff8b6bdced499acc12 100644 (file)
@@ -361,9 +361,7 @@ int main(int argc, char *argv[]) {
     avahi_elapse_time(&tv, 1000*60, 0);
     poll_api->timeout_new(poll_api, &tv, quit_timeout_callback, simple_poll);
 
-    for (;;)
-        if (avahi_simple_poll_iterate(simple_poll, -1) != 0)
-            break;
+    avahi_simple_poll_loop(simple_poll);
 
     avahi_s_record_browser_free(r);
     avahi_s_host_name_resolver_free(hnr);
index e27f4895bd7d3f75d9084ae496176b421f7b6553..b2e81611cc480d99c60f654b1288428900ece0e0 100644 (file)
@@ -186,7 +186,7 @@ void avahi_interface_free(AvahiInterface *i, int send_goodbye) {
     assert(i);
 
     /* Handle goodbyes and remove announcers */
-    avahi_goodbye_interface(i->monitor->server, i, send_goodbye);
+    avahi_goodbye_interface(i->monitor->server, i, send_goodbye, 1);
     avahi_response_scheduler_force(i->response_scheduler);
     assert(!i->announcements);
 
@@ -358,7 +358,7 @@ void avahi_interface_check_relevant(AvahiInterface *i) {
         if (i->protocol == AVAHI_PROTO_INET6)
             avahi_mdns_mcast_leave_ipv6(m->server->fd_ipv6, i->hardware->index);
 
-        avahi_goodbye_interface(m->server, i, 0);
+        avahi_goodbye_interface(m->server, i, 0, 1);
         avahi_querier_free_all(i);
 
         avahi_response_scheduler_clear(i->response_scheduler);
index aa9eae022374970805ee669b9127d4ba154bb55c..36c29cff043e3367b8300a87bcad88845c1291f7 100644 (file)
@@ -220,6 +220,43 @@ int avahi_server_add_service_subtype(
     const char *domain,       /**< Specify the main type of the service you already added here */
     const char *subtype       /**< The new subtype for the specified service */ );
 
+
+/** Update the TXT record for a service with the data from the specified string list */
+int avahi_server_update_service_txt_strlst(
+    AvahiServer *s,
+    AvahiSEntryGroup *g,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiPublishFlags flags,
+    const char *name,     
+    const char *type,     
+    const char *domain,   
+    AvahiStringList *strlst);
+
+/** Update the TXT record for a service with the NULL terminated list of strings of the va_list. */
+int avahi_server_update_service_txt_va(
+    AvahiServer *s,
+    AvahiSEntryGroup *g,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiPublishFlags flags,
+    const char *name,     
+    const char *type,     
+    const char *domain,   
+    va_list va);
+
+/** Update the TXT record for a service with the NULL termonate list of strings */
+int avahi_server_update_service_txt(
+    AvahiServer *s,
+    AvahiSEntryGroup *g,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiPublishFlags flags,
+    const char *name,     
+    const char *type,     
+    const char *domain,   
+    ...) AVAHI_GCC_SENTINEL;
+
 /** The type of DNS server */
 typedef enum {
     AVAHI_DNS_SERVER_RESOLVE,         /**< Unicast DNS servers for normal resolves (_domain._udp)*/
index f23ef392e637b0fb602f115c484d52d157e4cd81..dd3adcdba1f6ece144317fd1752a785801ed2324 100644 (file)
@@ -55,7 +55,7 @@ static void free_entry(AvahiServer*s, AvahiEntry *e) {
     assert(s);
     assert(e);
 
-    avahi_goodbye_entry(s, e, 1);
+    avahi_goodbye_entry(s, e, 1, 1);
 
     /* Remove from linked list */
     AVAHI_LLIST_REMOVE(AvahiEntry, entries, s->entries, e);
@@ -207,7 +207,7 @@ static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
         
         for (k = e->group->entries; k; k = k->by_group_next) {
             if (!k->dead) {
-                avahi_goodbye_entry(s, k, 0);
+                avahi_goodbye_entry(s, k, 0, 1);
                 k->dead = 1;
             }
         }
@@ -216,7 +216,7 @@ static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
 
         avahi_s_entry_group_change_state(e->group, AVAHI_ENTRY_GROUP_COLLISION);
     } else {
-        avahi_goodbye_entry(s, e, 0);
+        avahi_goodbye_entry(s, e, 0, 1);
         e->dead = 1;
     }
 
@@ -1571,8 +1571,6 @@ int avahi_server_add(
     AvahiPublishFlags flags,
     AvahiRecord *r) {
     
-    AvahiEntry *e, *t;
-    
     assert(s);
     assert(r);
 
@@ -1582,7 +1580,14 @@ int avahi_server_add(
     if (!AVAHI_PROTO_VALID(protocol))
         return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PROTOCOL);
     
-    if (!AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_ANNOUNCE|AVAHI_PUBLISH_NO_PROBE|AVAHI_PUBLISH_UNIQUE|AVAHI_PUBLISH_ALLOW_MULTIPLE|AVAHI_PUBLISH_IS_PROXY))
+    if (!AVAHI_FLAGS_VALID(
+            flags,
+            AVAHI_PUBLISH_NO_ANNOUNCE|
+            AVAHI_PUBLISH_NO_PROBE|
+            AVAHI_PUBLISH_UNIQUE|
+            AVAHI_PUBLISH_ALLOW_MULTIPLE|
+            AVAHI_PUBLISH_IS_PROXY|
+            AVAHI_PUBLISH_UPDATE))
         return avahi_server_set_errno(s, AVAHI_ERR_INVALID_FLAGS);
     
     if (!avahi_is_valid_domain_name(r->key->name))
@@ -1597,36 +1602,83 @@ int avahi_server_add(
     if (!avahi_record_is_valid(r))
         return avahi_server_set_errno(s, AVAHI_ERR_INVALID_RECORD);
 
-    if (check_record_conflict(s, interface, protocol, r, flags) < 0)
-        return avahi_server_set_errno(s, AVAHI_ERR_LOCAL_COLLISION);
-
-    if (!(e = avahi_new(AvahiEntry, 1)))
-        return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
+    if (flags & AVAHI_PUBLISH_UPDATE) {
+        AvahiEntry *e;
+        AvahiRecord *old_record;
+        int is_first = 1;
         
-    e->server = s;
-    e->record = avahi_record_ref(r);
-    e->group = g;
-    e->interface = interface;
-    e->protocol = protocol;
-    e->flags = flags;
-    e->dead = 0;
+        /* Update and existing record */
 
-    AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, e->announcements);
+        /* Find the first matching entry */
+        for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) {
+            if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol)
+                break;
 
-    AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e);
+            is_first = 0;
+        }
 
-    /* Insert into hash table indexed by name */
-    t = avahi_hashmap_lookup(s->entries_by_key, e->record->key);
-    AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e);
-    avahi_hashmap_replace(s->entries_by_key, e->record->key, t);
+        /* Hmm, nothing found? */
+        if (!e)
+            return avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND);
 
-    /* Insert into group list */
-    if (g)
-        AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); 
+        /* Update the entry */
+        old_record = e->record;
+        e->record = avahi_record_ref(r);
+        e->flags = flags;
 
-    avahi_announce_entry(s, e);
+        /* Announce our changes when needed */
+        if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) {
 
-    return 0;
+            /* Remove the old entry from all caches, if needed */
+            if (!(e->flags & AVAHI_PUBLISH_UNIQUE))
+                avahi_goodbye_entry(s, e, 1, 0);
+
+            /* Reannounce our updated entry */
+            avahi_reannounce_entry(s, e);
+        }
+
+        /* If we were the first entry in the list, we need to update the key */
+        if (is_first)
+            avahi_hashmap_replace(s->entries_by_key, e->record->key, e);
+        
+        avahi_record_unref(old_record);
+
+    } else {
+        AvahiEntry *e, *t;
+
+        /* Add a new record */
+    
+        if (check_record_conflict(s, interface, protocol, r, flags) < 0)
+            return avahi_server_set_errno(s, AVAHI_ERR_LOCAL_COLLISION);
+
+        if (!(e = avahi_new(AvahiEntry, 1)))
+            return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
+        
+        e->server = s;
+        e->record = avahi_record_ref(r);
+        e->group = g;
+        e->interface = interface;
+        e->protocol = protocol;
+        e->flags = flags;
+        e->dead = 0;
+        
+        AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, e->announcements);
+        
+        AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e);
+        
+        /* Insert into hash table indexed by name */
+        t = avahi_hashmap_lookup(s->entries_by_key, e->record->key);
+        AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e);
+        avahi_hashmap_replace(s->entries_by_key, e->record->key, t);
+        
+        /* Insert into group list */
+        if (g)
+            AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); 
+        
+        avahi_announce_entry(s, e);
+    }
+
+    return AVAHI_OK;
 }
 
 const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiSEntryGroup *g, void **state) {
@@ -1729,7 +1781,7 @@ int avahi_server_add_address(
     if (!AVAHI_PROTO_VALID(protocol) || !AVAHI_PROTO_VALID(a->proto))
         return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PROTOCOL);
     
-    if (!AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_REVERSE|AVAHI_PUBLISH_NO_ANNOUNCE|AVAHI_PUBLISH_NO_PROBE))
+    if (!AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_REVERSE|AVAHI_PUBLISH_NO_ANNOUNCE|AVAHI_PUBLISH_NO_PROBE|AVAHI_PUBLISH_UPDATE))
         return avahi_server_set_errno(s, AVAHI_ERR_INVALID_FLAGS);
     
     if (name && !avahi_is_valid_domain_name(name))
@@ -1937,7 +1989,7 @@ static int server_add_service_strlst_nocopy(
 
     AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
     AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
-    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_COOKIE|AVAHI_PUBLISH_IS_PROXY), AVAHI_ERR_INVALID_FLAGS);
+    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_NO_COOKIE|AVAHI_PUBLISH_IS_PROXY|AVAHI_PUBLISH_UPDATE), AVAHI_ERR_INVALID_FLAGS);
     AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
     AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
     AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
@@ -2063,12 +2115,106 @@ int avahi_server_add_service(
     va_list va;
     int ret;
     
+    va_start(va, port);
+    ret = avahi_server_add_service_va(s, g, interface, protocol, flags, name, type, domain, host, port, va);
+    va_end(va);
+    
+    return ret;
+}
+
+static int server_update_service_txt_strlst_nocopy(
+    AvahiServer *s,
+    AvahiSEntryGroup *g,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiPublishFlags flags,
+    const char *name,     
+    const char *type,     
+    const char *domain,   
+    AvahiStringList *strlst) {
+
+    char svc_name[AVAHI_DOMAIN_NAME_MAX];
+    int ret = AVAHI_OK;
+    
     assert(s);
     assert(type);
     assert(name);
 
-    va_start(va, port);
-    ret = avahi_server_add_service_va(s, g, interface, protocol, flags, name, type, domain, host, port, va);
+    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
+    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
+    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_IS_PROXY|AVAHI_PUBLISH_NO_COOKIE), AVAHI_ERR_INVALID_FLAGS);
+    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
+    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
+    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
+
+    if (!domain)
+        domain = s->domain_name;
+
+    if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0) {
+        avahi_server_set_errno(s, ret);
+        goto fail;
+    }
+
+    /* Add TXT record */
+    if (!(flags & AVAHI_PUBLISH_NO_COOKIE))
+        strlst = add_magic_cookie(s, strlst);
+    
+    ret = server_add_txt_strlst_nocopy(s, g, interface, protocol, (flags & AVAHI_PUBLISH_IS_PROXY) | AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_UPDATE, AVAHI_DEFAULT_TTL, svc_name, strlst);
+    strlst = NULL;
+
+fail:
+    
+    avahi_string_list_free(strlst);
+    
+    return ret;
+}
+
+int avahi_server_update_service_txt_strlst(
+    AvahiServer *s,
+    AvahiSEntryGroup *g,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiPublishFlags flags,
+    const char *name,     
+    const char *type,     
+    const char *domain,   
+    AvahiStringList *strlst) {
+
+    return server_update_service_txt_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, avahi_string_list_copy(strlst));
+}
+
+/** Update the TXT record for a service with the NULL terminated list of strings of the va_list. */
+int avahi_server_update_service_txt_va(
+    AvahiServer *s,
+    AvahiSEntryGroup *g,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiPublishFlags flags,
+    const char *name,     
+    const char *type,     
+    const char *domain,   
+    va_list va) {
+
+    return server_update_service_txt_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, avahi_string_list_new_va(va));
+}
+
+/** Update the TXT record for a service with the NULL termonate list of strings */
+int avahi_server_update_service_txt(
+    AvahiServer *s,
+    AvahiSEntryGroup *g,
+    AvahiIfIndex interface,
+    AvahiProtocol protocol,
+    AvahiPublishFlags flags,
+    const char *name,     
+    const char *type,     
+    const char *domain,   
+    ...) {
+
+    va_list va;
+    int ret;
+    
+    va_start(va, domain);
+    ret = avahi_server_update_service_txt_va(s, g, interface, protocol, flags, name, type, domain, va);
     va_end(va);
     
     return ret;
@@ -2344,7 +2490,7 @@ void avahi_s_entry_group_free(AvahiSEntryGroup *g) {
 
     for (e = g->entries; e; e = e->by_group_next) {
         if (!e->dead) {
-            avahi_goodbye_entry(g->server, e, 1);
+            avahi_goodbye_entry(g->server, e, 1, 1);
             e->dead = 1;
         }
     }
@@ -2428,7 +2574,7 @@ void avahi_s_entry_group_reset(AvahiSEntryGroup *g) {
     
     for (e = g->entries; e; e = e->by_group_next) {
         if (!e->dead) {
-            avahi_goodbye_entry(g->server, e, 1);
+            avahi_goodbye_entry(g->server, e, 1, 1);
             e->dead = 1;
         }
     }
diff --git a/avahi-core/update-test.c b/avahi-core/update-test.c
new file mode 100644 (file)
index 0000000..8c5b5ed
--- /dev/null
@@ -0,0 +1,88 @@
+/* $Id$ */
+
+/***
+  This file is part of avahi.
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+  avahi is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include <avahi-common/error.h>
+#include <avahi-common/watch.h>
+#include <avahi-common/simple-watch.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/alternative.h>
+
+#include <avahi-core/core.h>
+#include <avahi-core/log.h>
+#include <avahi-core/publish.h>
+#include <avahi-core/lookup.h>
+
+static AvahiSEntryGroup *group = NULL;
+
+static void server_callback(AvahiServer *s, AvahiServerState state, void* userdata) {
+
+    avahi_log_debug("server state: %i", state); 
+    
+    if (state == AVAHI_SERVER_RUNNING) {
+        int ret;
+        
+        group = avahi_s_entry_group_new(s, NULL, NULL);
+        assert(group);
+
+        ret = avahi_server_add_service(s, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, "foo", "_http._tcp", NULL, NULL, 80, "test1", NULL);
+        assert(ret == AVAHI_OK);
+
+        avahi_s_entry_group_commit(group);
+    }
+}
+
+static void modify_txt_callback(AvahiTimeout *e, void *userdata) {
+    int ret;
+    AvahiServer *s = userdata;
+
+    ret = avahi_server_update_service_txt(s, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, "foo", "_http._tcp", NULL, "test2", NULL);
+    assert(ret == AVAHI_OK);
+}
+
+int main(int argc, char *argv[]) {
+    AvahiSimplePoll *simple_poll;
+    const AvahiPoll *poll_api;
+    AvahiServer *server;
+    struct timeval tv;
+    AvahiServerConfig config;
+
+    simple_poll = avahi_simple_poll_new();
+    assert(simple_poll);
+    
+    poll_api = avahi_simple_poll_get(simple_poll);
+    assert(poll_api);
+
+    avahi_server_config_init(&config);
+    config.publish_domain = config.publish_workstation = config.use_ipv6 = config.publish_hinfo = 0;
+    server = avahi_server_new(poll_api, &config, server_callback, NULL, NULL);
+    assert(server);
+    avahi_server_config_free(&config);
+
+    poll_api->timeout_new(poll_api, avahi_elapse_time(&tv, 1000*20, 0), modify_txt_callback, server);
+
+    avahi_simple_poll_loop(simple_poll);
+}