AvahiDnsPacket *reply;
AvahiRecord *r;
- if (!(reply = avahi_dns_packet_new_reply(p, 512 /* unicast DNS maximum packet size is 512 */ , 1, 1)))
+ if (!(reply = avahi_dns_packet_new_reply(p, 512 + AVAHI_DNS_PACKET_EXTRA_SIZE /* unicast DNS maximum packet size is 512 */ , 1, 1)))
return; /* OOM */
while ((r = avahi_record_list_next(s->record_list, NULL, NULL, NULL))) {
int tc = p && !!(avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_TC);
while ((r = avahi_record_list_next(s->record_list, &flush_cache, &unicast_response, &auxiliary))) {
-
- if (!avahi_interface_post_response(i, r, flush_cache, a, immediately || (flush_cache && !tc && !auxiliary)) && unicast_response) {
- append_aux_records_to_list(s, i, r, unicast_response);
-
+ int im = immediately;
+
+ /* Only send the response immediately if it contains a
+ * unique entry AND it is not in reply to a truncated
+ * packet AND it is not an auxiliary record AND all other
+ * responses for this record are unique too. */
+
+ if (flush_cache && !tc && !auxiliary && avahi_record_list_all_flush_cache(s->record_list))
+ im = 1;
+
+ if (!avahi_interface_post_response(i, r, flush_cache, a, im) && unicast_response) {
+
/* Due to some reasons the record has not been scheduled.
* The client requested an unicast response in that
* case. Therefore we prepare such a response */
+ append_aux_records_to_list(s, i, r, unicast_response);
+
for (;;) {
if (!reply) {
* the specific header field, and return to the caller */
avahi_dns_packet_inc_field(reply, AVAHI_DNS_FIELD_ANCOUNT);
-
break;
}
avahi_dns_packet_free(reply);
size = avahi_record_get_estimate_size(r) + AVAHI_DNS_PACKET_HEADER_SIZE;
- if (size > AVAHI_DNS_PACKET_SIZE_MAX)
- size = AVAHI_DNS_PACKET_SIZE_MAX;
- if (!(reply = avahi_dns_packet_new_reply(p, size, 0, 1)))
+ if (!(reply = avahi_dns_packet_new_reply(p, size + AVAHI_DNS_PACKET_EXTRA_SIZE, 0, 1)))
break; /* OOM */
- if (!avahi_dns_packet_append_record(reply, r, flush_cache, 0)) {
+ if (avahi_dns_packet_append_record(reply, r, flush_cache, 0)) {
+
+ /* Appending this record succeeded, so incremeant
+ * the specific header field, and return to the caller */
+
+ avahi_dns_packet_inc_field(reply, AVAHI_DNS_FIELD_ANCOUNT);
+ break;
+
+ } else {
+
+ /* We completely fucked up, there's
+ * nothing we can do. The RR just doesn't
+ * fit in. Let's ignore it. */
+
char *t;
avahi_dns_packet_free(reply);
+ reply = NULL;
t = avahi_record_to_string(r);
avahi_log_warn("Record [%s] too large, doesn't fit in any packet!", t);
avahi_free(t);
break;
- } else
- avahi_dns_packet_inc_field(reply, AVAHI_DNS_FIELD_ANCOUNT);
+ }
}
/* Appending the record didn't succeeed, so let's send this packet, and create a new one */
avahi_record_list_flush(s->record_list);
}
-
static void reflect_response(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, int flush_cache) {
AvahiInterface *j;
for (j = s->monitor->interfaces; j; j = j->interface_next)
if (j != i && (s->config.reflect_ipv || j->protocol == i->protocol)) {
/* Post the query to other networks */
- avahi_interface_post_query(j, k, 1);
+ avahi_interface_post_query(j, k, 1, NULL);
/* Reply from caches of other network. This is needed to
* "work around" known answer suppression. */
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;
int unicast_response = 0;
if (!(key = avahi_dns_packet_consume_key(p, &unicast_response))) {
- avahi_log_warn("Packet too short (1)");
+ avahi_log_warn(__FILE__": Packet too short or invalid while reading question key. (Maybe an UTF8 problem?)");
goto fail;
}
int unique = 0;
if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
- avahi_log_warn("Packet too short (2)");
+ avahi_log_warn(__FILE__": Packet too short or invalid while reading known answer record. (Maybe an UTF8 problem?)");
goto fail;
}
int unique = 0;
if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
- avahi_log_warn("Packet too short (3)");
+ avahi_log_warn(__FILE__": Packet too short or invalid while reading probe record. (Maybe an UTF8 problem?)");
goto fail;
}
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;
/* char *txt; */
if (!(record = avahi_dns_packet_consume_record(p, &cache_flush))) {
- avahi_log_warn("Packet too short (4)");
+ avahi_log_warn(__FILE__": Packet too short or invalid while reading response record. (Maybe an UTF8 problem?)");
break;
}
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
avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ID, slot->id);
for (j = s->monitor->interfaces; j; j = j->interface_next)
- if (avahi_interface_is_relevant(j) &&
+ if (j->announcing &&
j != i &&
(s->config.reflect_ipv || j->protocol == i->protocol)) {
assert(src_address->proto == dst_address->proto);
if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, src_address->proto)) ||
- !avahi_interface_is_relevant(i)) {
+ !i->announcing) {
avahi_log_warn("Recieved packet from invalid interface.");
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"); */
}
}
}
if (!(j = avahi_interface_monitor_get_interface(s->monitor, slot->interface, slot->address.proto)) ||
- !avahi_interface_is_relevant(j))
+ !j->announcing)
return;
/* Patch the original ID into this response */
s->state = state;
+ avahi_interface_monitor_update_rrs(s->monitor, 0);
+
if (s->callback)
s->callback(s, state, s->userdata);
}
/* Fill in HINFO rr */
if ((r = avahi_record_new_full(s->host_name_fqdn, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_HINFO, AVAHI_DEFAULT_TTL_HOST_NAME))) {
- uname(&utsname);
- r->data.hinfo.cpu = avahi_strdup(avahi_strup(utsname.machine));
- r->data.hinfo.os = avahi_strdup(avahi_strup(utsname.sysname));
- if (avahi_server_add(s, s->hinfo_entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_UNIQUE, r) < 0) {
- avahi_log_warn("Failed to add HINFO RR: %s", avahi_strerror(s->error));
- return;
+ if (uname(&utsname) < 0)
+ avahi_log_warn("uname() failed: %s\n", avahi_strerror(errno));
+ else {
+
+ r->data.hinfo.cpu = avahi_strdup(avahi_strup(utsname.machine));
+ r->data.hinfo.os = avahi_strdup(avahi_strup(utsname.sysname));
+
+ avahi_log_info("Registering HINFO record with values '%s'/'%s'.", r->data.hinfo.cpu, r->data.hinfo.os);
+
+ if (avahi_server_add(s, s->hinfo_entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_UNIQUE, r) < 0) {
+ avahi_log_warn("Failed to add HINFO RR: %s", avahi_strerror(s->error));
+ return;
+ }
}
avahi_record_unref(r);
if (!s->config.publish_domain)
return;
+ if (avahi_domain_equal(s->domain_name, "local"))
+ return;
+
if (s->browse_domain_entry_group)
assert(avahi_s_entry_group_is_empty(s->browse_domain_entry_group));
else
}
int avahi_server_set_host_name(AvahiServer *s, const char *host_name) {
+ char *hn = NULL;
assert(s);
- assert(host_name);
+
+ AVAHI_CHECK_VALIDITY(s, !host_name || avahi_is_valid_host_name(host_name), AVAHI_ERR_INVALID_HOST_NAME);
- if (host_name && !avahi_is_valid_host_name(host_name))
- return avahi_server_set_errno(s, AVAHI_ERR_INVALID_HOST_NAME);
+ if (!host_name) {
+ hn = avahi_get_host_name_strdup();
+ hn[strcspn(hn, ".")] = 0;
+ host_name = hn;
+ }
+ if (avahi_domain_equal(s->host_name, host_name) && s->state != AVAHI_SERVER_COLLISION) {
+ avahi_free(hn);
+ return avahi_server_set_errno(s, AVAHI_ERR_NO_CHANGE);
+ }
+
withdraw_host_rrs(s);
avahi_free(s->host_name);
- s->host_name = host_name ? avahi_normalize_name_strdup(host_name) : avahi_get_host_name_strdup();
- s->host_name[strcspn(s->host_name, ".")] = 0;
+ s->host_name = hn ? hn : avahi_strdup(host_name);
+
update_fqdn(s);
register_stuff(s);
}
int avahi_server_set_domain_name(AvahiServer *s, const char *domain_name) {
+ char *dn = NULL;
assert(s);
- assert(domain_name);
- if (domain_name && !avahi_is_valid_domain_name(domain_name))
- return avahi_server_set_errno(s, AVAHI_ERR_INVALID_DOMAIN_NAME);
+ AVAHI_CHECK_VALIDITY(s, !domain_name || avahi_is_valid_domain_name(domain_name), AVAHI_ERR_INVALID_DOMAIN_NAME);
+
+ if (!domain_name) {
+ dn = avahi_strdup("local");
+ domain_name = dn;
+ }
+
+ if (avahi_domain_equal(s->domain_name, domain_name)) {
+ avahi_free(dn);
+ return avahi_server_set_errno(s, AVAHI_ERR_NO_CHANGE);
+ }
withdraw_host_rrs(s);
avahi_free(s->domain_name);
- s->domain_name = domain_name ? avahi_normalize_name_strdup(domain_name) : avahi_strdup("local");
+ s->domain_name = avahi_normalize_name_strdup(domain_name);
update_fqdn(s);
register_stuff(s);
+
+ avahi_free(dn);
return AVAHI_OK;
}
c->enable_wide_area = 0;
c->n_wide_area_servers = 0;
c->disallow_other_stacks = 0;
+ c->browse_domains = NULL;
+ c->disable_publishing = 0;
+ c->allow_point_to_point = 0;
+ c->publish_aaaa_on_ipv4 = 1;
+ c->publish_a_on_ipv6 = 0;
return c;
}
avahi_free(c->host_name);
avahi_free(c->domain_name);
+ avahi_string_list_free(c->browse_domains);
}
AvahiServerConfig* avahi_server_config_copy(AvahiServerConfig *ret, const AvahiServerConfig *c) {
char *d = NULL, *h = NULL;
+ AvahiStringList *l = NULL;
assert(ret);
assert(c);
avahi_free(h);
return NULL;
}
+
+ if (!(l = avahi_string_list_copy(c->browse_domains)) && c->browse_domains) {
+ avahi_free(h);
+ avahi_free(d);
+ return NULL;
+ }
*ret = *c;
ret->host_name = h;
ret->domain_name = d;
+ ret->browse_domains = l;
return ret;
}
assert(type);
assert(ret_group);
- if (!AVAHI_IF_VALID(interface))
- return avahi_server_set_errno(s, AVAHI_ERR_INVALID_INTERFACE);
-
- if (!AVAHI_IF_VALID(protocol))
- return avahi_server_set_errno(s, AVAHI_ERR_INVALID_PROTOCOL);
-
- if (!avahi_is_valid_service_name(name))
- return avahi_server_set_errno(s, AVAHI_ERR_INVALID_SERVICE_NAME);
-
- if (!avahi_is_valid_service_type_strict(type))
- return avahi_server_set_errno(s, AVAHI_ERR_INVALID_SERVICE_TYPE);
-
- if (domain && !avahi_is_valid_domain_name(domain))
- return avahi_server_set_errno(s, AVAHI_ERR_INVALID_DOMAIN_NAME);
+ AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
+ AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
+ AVAHI_CHECK_VALIDITY(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
+ AVAHI_CHECK_VALIDITY(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
+ AVAHI_CHECK_VALIDITY(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
if ((ret = avahi_service_name_join(n, sizeof(n), name, type, domain) < 0))
return avahi_server_set_errno(s, ret);
avahi_wide_area_set_servers(s->wide_area_lookup_engine, a, n);
return AVAHI_OK;
}
+
+const AvahiServerConfig* avahi_server_get_config(AvahiServer *s) {
+ assert(s);
+
+ return &s->config;
+}