diff --git a/announce.c b/announce.c index a562277..c33f014 100644 --- a/announce.c +++ b/announce.c @@ -37,6 +37,8 @@ enum { int announce_ttl = 75 * 60; +static void announce_restart(void); + static void announce_timer(struct uloop_timeout *timeout) { @@ -58,7 +60,24 @@ announce_timer(struct uloop_timeout *timeout) case STATE_PROBE_END: if (cache_host_is_known(mdns_hostname_local)) { - fprintf(stderr, "the host %s already exists. stopping announce service\n", mdns_hostname_local); + char conflict[sizeof(mdns_hostname_local)]; + + snprintf(conflict, sizeof(conflict), "%s", mdns_hostname_local); + + if (!rename_hostname()) { + fprintf(stderr, "the host %s already exists. stopping announce service\n", + conflict); + return; + } + + fprintf(stderr, "the host %s already exists, renaming to %s\n", + conflict, mdns_hostname_local); + + /* + * The host name is global, so every interface has to probe + * again for the new one rather than announce the old one. + */ + announce_restart(); return; } iface->announce_state++; @@ -81,6 +100,15 @@ announce_init(struct interface *iface) uloop_timeout_set(&iface->announce_timer, 100); } +static void +announce_restart(void) +{ + struct interface *iface; + + vlist_for_each_element(&interfaces, iface, node) + announce_init(iface); +} + void announce_free(struct interface *iface) { diff --git a/util.c b/util.c index f5cfdb8..54bc6f4 100644 --- a/util.c +++ b/util.c @@ -38,6 +38,9 @@ int debug = 0; char umdns_host_label[HOSTNAME_LEN]; char mdns_hostname_local[HOSTNAME_LEN + 6]; +static char umdns_host_base[HOSTNAME_LEN]; +static unsigned int umdns_host_suffix; + uint32_t rand_time_delta(uint32_t t) { @@ -61,6 +64,21 @@ rand_time_delta(uint32_t t) return val; } +/* "-" plus the widest suffix an unsigned int can print, plus the terminator */ +#define HOSTNAME_SUFFIX_LEN 12 + +static void apply_hostname(void) +{ + if (umdns_host_suffix) + snprintf(umdns_host_label, sizeof(umdns_host_label), "%.*s-%u", + (int)sizeof(umdns_host_label) - HOSTNAME_SUFFIX_LEN, + umdns_host_base, umdns_host_suffix + 1); + else + snprintf(umdns_host_label, sizeof(umdns_host_label), "%s", umdns_host_base); + + snprintf(mdns_hostname_local, sizeof(mdns_hostname_local), "%s.local", umdns_host_label); +} + void get_hostname(void) { struct utsname utsname; @@ -71,8 +89,28 @@ void get_hostname(void) if (uname(&utsname) < 0) return; - snprintf(umdns_host_label, sizeof(umdns_host_label), "%s", utsname.nodename); - snprintf(mdns_hostname_local, sizeof(mdns_hostname_local), "%s.local", utsname.nodename); + /* + * Only start over from the unsuffixed name when the system host name + * itself changed, so that a name picked to resolve a conflict survives + * an unrelated reload. + */ + if (strcmp(umdns_host_base, utsname.nodename)) { + snprintf(umdns_host_base, sizeof(umdns_host_base), "%s", utsname.nodename); + umdns_host_suffix = 0; + } + + apply_hostname(); +} + +bool rename_hostname(void) +{ + if (umdns_host_suffix >= HOSTNAME_MAX_SUFFIX) + return false; + + umdns_host_suffix++; + apply_hostname(); + + return true; } time_t monotonic_time(void) diff --git a/util.h b/util.h index 57afcd3..5e2de4e 100644 --- a/util.h +++ b/util.h @@ -26,6 +26,9 @@ #define MDNS_BUF_LEN (8 * 1024) #define HOSTNAME_LEN 256 +/* Highest -N suffix appended to the host name to resolve a conflict. */ +#define HOSTNAME_MAX_SUFFIX 9 + extern int debug; extern uint8_t mdns_buf[MDNS_BUF_LEN]; @@ -39,6 +42,14 @@ extern char umdns_host_label[HOSTNAME_LEN]; extern char mdns_hostname_local[HOSTNAME_LEN + 6]; extern void get_hostname(void); + +/** + * Append or bump the -N suffix on the host name after a probe conflict + * + * Returns false once HOSTNAME_MAX_SUFFIX is reached, leaving the name as is. + */ +extern bool rename_hostname(void); + extern uint32_t rand_time_delta(uint32_t t); extern time_t monotonic_time(void);