#include <config.h>
#endif
+#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
return avahi_timeval_diff(&now, a);
}
-
struct timeval *avahi_elapse_time(struct timeval *tv, unsigned msec, unsigned jitter) {
assert(tv);
if (msec)
avahi_timeval_add(tv, (AvahiUsec) msec*1000);
- if (jitter)
- avahi_timeval_add(tv, (AvahiUsec) (jitter*1000.0*rand()/(RAND_MAX+1.0)));
+ if (jitter) {
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ static int last_rand;
+ static time_t timestamp = 0;
+
+ time_t now;
+ int r;
+
+ now = time(NULL);
+
+ pthread_mutex_lock(&mutex);
+ if (now >= timestamp + 10) {
+ timestamp = now;
+ last_rand = rand();
+ }
+
+ r = last_rand;
+
+ pthread_mutex_unlock(&mutex);
+
+ /* We use the same jitter for 10 seconds. That way our
+ * time events elapse in bursts which has the advantage that
+ * packet data can be aggegrated better */
+
+ avahi_timeval_add(tv, (AvahiUsec) (jitter*1000.0*r/(RAND_MAX+1.0)));
+ }
return tv;
}
if (g->dead)
return;
- for (e = g->entries; e; e = e->entries_next) {
+ for (e = g->entries; e; e = e->by_group_next) {
AvahiAnnouncer *a;
for (a = e->announcers; a; a = a->by_entry_next) {
-
+
if (a->state != AVAHI_WAITING)
continue;
static void next_state(AvahiAnnouncer *a) {
assert(a);
-/* avahi_log_debug("%i -- %u", a->state, a->n_iteration); */
-
if (a->state == AVAHI_WAITING) {
assert(a->entry->group);
if (a->n_iteration >= 4) {
/* Probing done */
-/* char *t; */
-
-/* avahi_log_debug("Enough probes for record [%s]", t = avahi_record_to_string(a->entry->record)); */
-/* avahi_free(t); */
-
if (a->entry->group) {
assert(a->entry->group->n_probing);
a->entry->group->n_probing--;
avahi_server_generate_response(a->server, a->interface, NULL, NULL, 0, 0, 0);
if (++a->n_iteration >= 4) {
-/* char *t; */
/* Announcing done */
-/* avahi_log_debug("Enough announcements for record [%s]", t = avahi_record_to_string(a->entry->record)); */
-/* avahi_free(t); */
-
a->state = AVAHI_ESTABLISHED;
set_timeout(a, NULL);
static void new_announcer(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) {
AvahiAnnouncer *a;
-/* char *t; */
assert(s);
assert(i);
assert(e);
assert(!e->dead);
-/* avahi_log_debug("NEW ANNOUNCER: %s.%i [%s]", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record)); */
-/* avahi_free(t); */
-
if (!avahi_interface_match(i, e->interface, e->protocol) || !i->announcing || !avahi_entry_is_commited(e))
return;
AVAHI_LLIST_PREPEND(AvahiAnnouncer, by_entry, e->announcers, a);
go_to_initial_state(a);
-
-/* avahi_log_debug("New announcer on interface %s.%i for entry [%s] state=%i", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record), a->state); */
-/* avahi_free(t); */
}
void avahi_announce_interface(AvahiServer *s, AvahiInterface *i) {
if (!(a = get_announcer(s, e, i)))
return 0;
-
-/* avahi_log_debug("state: %i", a->state); */
return
a->state == AVAHI_PROBING ||
}
static AvahiRecord *make_goodbye_record(AvahiRecord *r) {
-/* char *t; */
AvahiRecord *g;
assert(r);
-/* avahi_log_debug("Preparing goodbye for record [%s]", t = avahi_record_to_string(r)); */
-/* avahi_free(t); */
-
if (!(g = avahi_record_copy(r)))
return NULL; /* OOM */
#include <string.h>
#include <stdlib.h>
+#include <time.h>
#include <avahi-common/timeval.h>
#include <avahi-common/malloc.h>
AVAHI_LLIST_HEAD_INIT(AvahiCacheEntry, c->entries);
c->n_entries = 0;
+
+ c->last_rand_timestamp = 0;
return c;
}
static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, unsigned percent) {
AvahiUsec usec, left, right;
+ time_t now;
assert(c);
assert(e);
left = usec * percent;
right = usec * (percent+2); /* 2% jitter */
- usec = left + (AvahiUsec) ((double) (right-left) * rand() / (RAND_MAX+1.0));
+ now = time(NULL);
+
+ if (now >= c->last_rand_timestamp + 10) {
+ c->last_rand = rand();
+ c->last_rand_timestamp = now;
+ }
+
+ usec = left + (AvahiUsec) ((double) (right-left) * c->last_rand / (RAND_MAX+1.0));
e->expiry = e->timestamp;
avahi_timeval_add(&e->expiry, usec);
AVAHI_LLIST_HEAD(AvahiCacheEntry, entries);
unsigned n_entries;
+
+ int last_rand;
+ time_t last_rand_timestamp;
};
AvahiCache *avahi_cache_new(AvahiServer *server, AvahiInterface *interface);
avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING);
- if (!g->dead) {
- avahi_announce_group(g->server, g);
- avahi_s_entry_group_check_probed(g, 0);
- }
+ if (g->dead)
+ return;
+
+ avahi_announce_group(g->server, g);
+ avahi_s_entry_group_check_probed(g, 0);
}
static void entry_group_register_time_event_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* userdata) {
AvahiSEntryGroup *g = userdata;
assert(g);
-/* avahi_log_debug("Holdoff passed, waking up and going on."); */
-
avahi_time_event_free(g->register_time_event);
g->register_time_event = NULL;
gettimeofday(&now, NULL);
if (avahi_timeval_compare(&g->register_time, &now) <= 0) {
- /* Holdoff time passed, so let's start probing */
-/* avahi_log_debug("Holdoff passed, directly going on."); */
+ /* Holdoff time passed, so let's start probing */
entry_group_commit_real(g);
} else {
-/* avahi_log_debug("Holdoff not passed, sleeping."); */
/* Holdoff time has not yet passed, so let's wait */
assert(!g->register_time_event);
if (m->list_complete &&
!remove_rrs &&
m->server->config.publish_workstation &&
- (m->server->state == AVAHI_SERVER_RUNNING ||
- m->server->state == AVAHI_SERVER_REGISTERING)) {
+ (m->server->state == AVAHI_SERVER_RUNNING)) {
if (!hw->entry_group)
hw->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
return; /* OOM */
if (avahi_s_entry_group_is_empty(hw->entry_group)) {
- char name[AVAHI_LABEL_MAX];
- char *t;
-
- if (!(t = avahi_format_mac_address(hw->mac_address, hw->mac_address_size)))
- return; /* OOM */
+ char name[AVAHI_LABEL_MAX], mac[256];
- snprintf(name, sizeof(name), "%s [%s]", m->server->host_name, t);
- avahi_free(t);
+ avahi_format_mac_address(mac, sizeof(mac), hw->mac_address, hw->mac_address_size);
+ snprintf(name, sizeof(name), "%s [%s]", m->server->host_name, mac);
- if (!name)
- return; /* OOM */
-
if (avahi_server_add_service(m->server, hw->entry_group, hw->index, AVAHI_PROTO_UNSPEC, 0, name, "_workstation._tcp", NULL, NULL, 9, NULL) < 0) {
avahi_log_warn(__FILE__": avahi_server_add_service() failed: %s", avahi_strerror(m->server->error));
avahi_s_entry_group_free(hw->entry_group);
return NULL;
}
-
void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, uint16_t port) {
assert(i);
assert(p);
-/* char t[AVAHI_ADDRESS_STR_MAX]; */
if (!avahi_interface_is_relevant(i))
return;
assert(!a || a->proto == i->protocol);
-/* if (a) */
-/* avahi_log_debug("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port); */
-/* else */
-/* avahi_log_debug("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */
-
if (i->protocol == AVAHI_PROTO_INET && i->monitor->server->fd_ipv4 >= 0)
avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, i->mcast_joined ? &i->local_mcast_address.data.ipv4 : NULL, a ? &a->data.ipv4 : NULL, port);
else if (i->protocol == AVAHI_PROTO_INET6 && i->monitor->server->fd_ipv6 >= 0)
const char *name,
const char *dest);
-
#define AVAHI_CHECK_VALIDITY(server, expression, error) { \
if (!(expression)) \
return avahi_server_set_errno((server), (error)); \
assert(i);
assert(a);
-/* avahi_log_debug("query"); */
-
assert(avahi_record_list_is_empty(s->record_list));
is_probe = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) > 0;
assert(i);
assert(a);
-/* avahi_log_debug("response"); */
-
for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) +
avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT); n > 0; n--) {
AvahiRecord *record;
if (!avahi_key_is_pattern(record->key)) {
-/* avahi_log_debug("Handling response: %s", txt = avahi_record_to_string(record)); */
-/* avahi_free(txt); */
-
if (handle_conflict(s, i, record, cache_flush)) {
if (!from_local_iface)
reflect_response(s, i, record, cache_flush);
if (!s->config.enable_reflector)
return;
-/* avahi_log_debug("legacy unicast reflector"); */
-
/* Reflecting legacy unicast queries is a little more complicated
than reflecting normal queries, since we must route the
responses back to the right client. Therefore we must store
return;
}
-/* avahi_log_debug("new packet received on interface '%s.%i'.", i->hardware->name, i->protocol); */
-
if (avahi_address_is_ipv4_in_ipv6(src_address))
/* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
return;
handle_query_packet(s, p, i, src_address, port, legacy_unicast, from_local_iface);
-/* avahi_log_debug("Handled query"); */
} else {
if (port != AVAHI_MDNS_PORT) {
avahi_log_warn("Recieved repsonse with invalid source port %u on interface '%s.%i'", port, i->hardware->name, i->protocol);
}
handle_response_packet(s, p, i, src_address, from_local_iface);
-/* avahi_log_debug("Handled response"); */
}
}
s->state = state;
+ avahi_interface_monitor_update_rrs(s->monitor, 0);
+
if (s->callback)
s->callback(s, state, s->userdata);
}
}
}
-
-char *avahi_format_mac_address(const uint8_t* mac, size_t size) {
- char *r, *t;
+char *avahi_format_mac_address(char *r, size_t l, const uint8_t* mac, size_t size) {
+ char *t = r;
unsigned i;
static const char hex[] = "0123456789abcdef";
- if (!(t = r = avahi_new(char, size > 0 ? size*3 : 1)))
- return NULL;
-
+ assert(r);
+ assert(l > 0);
+ assert(mac);
+
if (size <= 0) {
*r = 0;
return r;
}
for (i = 0; i < size; i++) {
+ if (l < 3)
+ break;
+
*(t++) = hex[*mac >> 4];
*(t++) = hex[*mac & 0xF];
*(t++) = ':';
+ l -= 3;
+
mac++;
}
- *(--t) = 0;
+ if (t > r)
+ *(t-1) = 0;
+ else
+ *r = 0;
+
return r;
}
void avahi_hexdump(const void *p, size_t size);
-char *avahi_format_mac_address(const uint8_t* mac, size_t size);
+char *avahi_format_mac_address(char *t, size_t l, const uint8_t* mac, size_t size);
/** Change every character in the string to upper case (ASCII), return a pointer to the string */
char *avahi_strup(char *s);