avahi_test_LDADD = $(AM_LDADD) libavahi-core.la
+valgrind: avahi-test
+ libtool --mode=execute valgrind ./avahi-test
+
+gdb: avahi-test
+ libtool --mode=execute gdb ./avahi-test
gchar t[256], *a, *b, *c, *d;
AvahiDnsPacket *p;
- p = avahi_dns_packet_new(8000);
+ p = avahi_dns_packet_new(0);
avahi_dns_packet_append_name(p, a = "hello.hello.hello.de.");
avahi_dns_packet_append_name(p, b = "this is a test.hello.de.");
#include "dns.h"
#include "util.h"
-AvahiDnsPacket* avahi_dns_packet_new(guint max_size) {
+AvahiDnsPacket* avahi_dns_packet_new(guint mtu) {
AvahiDnsPacket *p;
+ guint max_size;
- if (max_size <= 0)
+ if (mtu <= 0)
max_size = AVAHI_DNS_PACKET_MAX_SIZE;
- else if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
+ else if (mtu >= 48)
+ max_size = mtu - 48;
+ else
+ max_size = 0;
+
+ if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
max_size = AVAHI_DNS_PACKET_HEADER_SIZE;
p = g_malloc(sizeof(AvahiDnsPacket) + max_size);
return p;
}
-AvahiDnsPacket* avahi_dns_packet_new_query(guint max_size) {
+AvahiDnsPacket* avahi_dns_packet_new_query(guint mtu) {
AvahiDnsPacket *p;
- p = avahi_dns_packet_new(max_size);
+ p = avahi_dns_packet_new(mtu);
avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
return p;
}
-AvahiDnsPacket* avahi_dns_packet_new_response(guint max_size) {
+AvahiDnsPacket* avahi_dns_packet_new_response(guint mtu) {
AvahiDnsPacket *p;
- p = avahi_dns_packet_new(max_size);
+ p = avahi_dns_packet_new(mtu);
avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
return p;
}
+AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, guint mtu, gboolean copy_queries, gboolean aa) {
+ AvahiDnsPacket *r;
+ g_assert(p);
+
+ r = avahi_dns_packet_new_response(mtu);
+
+ if (copy_queries) {
+ guint n, saved_rindex;
+
+ saved_rindex = p->rindex;
+ p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
+
+ for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n--) {
+ AvahiKey *k;
+ gboolean unicast_response;
+
+ if ((k = avahi_dns_packet_consume_key(p, &unicast_response))) {
+ avahi_dns_packet_append_key(r, k, unicast_response);
+ avahi_key_unref(k);
+ }
+ }
+
+ p->rindex = saved_rindex;
+
+ avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_QDCOUNT, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT));
+ }
+
+ avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_ID, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID));
+
+ avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_FLAGS,
+ (avahi_dns_packet_get_field(r, AVAHI_DNS_FIELD_FLAGS) & ~AVAHI_DNS_FLAG_OPCODE) |
+ (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_OPCODE) |
+ (aa ? AVAHI_DNS_FLAG_AA : 0));
+
+ return r;
+}
+
+
void avahi_dns_packet_free(AvahiDnsPacket *p) {
g_assert(p);
return t;
}
-guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush) {
+guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush, guint max_ttl) {
guint8 *t, *l, *start;
guint size;
if (!(t = avahi_dns_packet_append_name(p, r->key->name)) ||
!avahi_dns_packet_append_uint16(p, r->key->type) ||
!avahi_dns_packet_append_uint16(p, cache_flush ? (r->key->class | AVAHI_DNS_CACHE_FLUSH) : (r->key->class &~ AVAHI_DNS_CACHE_FLUSH)) ||
- !avahi_dns_packet_append_uint32(p, r->ttl) ||
+ !avahi_dns_packet_append_uint32(p, (max_ttl && r->ttl > max_ttl) ? max_ttl : r->ttl) ||
!(l = avahi_dns_packet_append_uint16(p, 0)))
goto fail;
#define AVAHI_DNS_PACKET_DATA(p) (((guint8*) p) + sizeof(AvahiDnsPacket))
-AvahiDnsPacket* avahi_dns_packet_new(guint size);
-AvahiDnsPacket* avahi_dns_packet_new_query(guint size);
-AvahiDnsPacket* avahi_dns_packet_new_response(guint size);
+AvahiDnsPacket* avahi_dns_packet_new(guint mtu);
+AvahiDnsPacket* avahi_dns_packet_new_query(guint mtu);
+AvahiDnsPacket* avahi_dns_packet_new_response(guint mtu);
+
+AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, guint mtu, gboolean copy_queries, gboolean aa);
void avahi_dns_packet_free(AvahiDnsPacket *p);
void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v);
guint8 *avahi_dns_packet_append_name(AvahiDnsPacket *p, const gchar *name);
guint8 *avahi_dns_packet_append_bytes(AvahiDnsPacket *p, gconstpointer, guint l);
guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean unicast_response);
-guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush);
+guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush, guint max_ttl);
guint8* avahi_dns_packet_append_string(AvahiDnsPacket *p, const gchar *s);
gint avahi_dns_packet_is_query(AvahiDnsPacket *p);
#define AVAHI_DNS_FLAG_OPCODE (15 << 11)
#define AVAHI_DNS_FLAG_RCODE (15)
#define AVAHI_DNS_FLAG_TC (1 << 9)
+#define AVAHI_DNS_FLAG_AA (1 << 10)
#define AVAHI_DNS_FLAGS(qr, opcode, aa, tc, rd, ra, z, ad, cd, rcode) \
(((guint16) !!qr << 15) | \
}
-void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
+void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port) {
g_assert(i);
g_assert(p);
+ char t[64];
- if (avahi_interface_relevant(i)) {
- g_message("sending on '%s.%i'", i->hardware->name, i->protocol);
+ if (!avahi_interface_relevant(i))
+ return;
+
+ g_assert(!a || a->family == i->protocol);
- if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
- avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p);
- else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0)
- avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p);
- }
+ if (a)
+ g_message("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port);
+ else
+ g_message("multicast sending on '%s.%i'", i->hardware->name, i->protocol);
+
+ if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
+ avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port);
+ else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0)
+ avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, a ? &a->data.ipv6 : NULL, port);
+}
+
+void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
+ g_assert(i);
+ g_assert(p);
+
+ avahi_interface_send_packet_unicast(i, p, NULL, 0);
}
-void avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean immediately) {
+gboolean avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean immediately) {
g_assert(i);
g_assert(key);
if (avahi_interface_relevant(i))
- avahi_packet_scheduler_post_query(i->scheduler, key, immediately);
-}
+ return avahi_packet_scheduler_post_query(i->scheduler, key, immediately);
+ return FALSE;
+}
-void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+gboolean avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
g_assert(i);
g_assert(record);
if (avahi_interface_relevant(i))
- avahi_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately);
+ return avahi_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately);
+
+ return FALSE;
}
-void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, gboolean immediately) {
+gboolean avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, gboolean immediately) {
g_assert(i);
g_assert(record);
if (avahi_interface_relevant(i))
- avahi_packet_scheduler_post_probe(i->scheduler, record, immediately);
+ return avahi_packet_scheduler_post_probe(i->scheduler, record, immediately);
+
+ return FALSE;
}
void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f) {
AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, gint index);
void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p);
+void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port);
-void avahi_interface_post_query(AvahiInterface *i, AvahiKey *k, gboolean immediately);
-void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *p, gboolean immediately);
-void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+gboolean avahi_interface_post_query(AvahiInterface *i, AvahiKey *k, gboolean immediately);
+gboolean avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *p, gboolean immediately);
+gboolean avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f);
while ((ka = s->known_answers)) {
- while (!avahi_dns_packet_append_record(p, ka->record, FALSE)) {
+ while (!avahi_dns_packet_append_record(p, ka->record, FALSE, 0)) {
g_assert(!avahi_dns_packet_is_empty(p));
avahi_interface_send_packet(s->interface, p);
avahi_dns_packet_free(p);
- p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+ p = avahi_dns_packet_new_query(s->interface->hardware->mtu);
n = 0;
}
g_assert(!s->known_answers);
- p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+ p = avahi_dns_packet_new_query(s->interface->hardware->mtu);
d = packet_add_query_job(s, p, qj);
g_assert(d);
n = 1;
return qj;
}
-void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) {
+gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) {
GTimeVal tv;
AvahiQueryJob *qj;
/* Duplicate questions suppression */
if (d >= 0 && d <= AVAHI_QUERY_HISTORY_MSEC*1000) {
g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
- return;
+ return FALSE;
}
query_job_free(s, qj);
qj = query_job_new(s, key);
qj->delivery = tv;
qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &qj->delivery, query_elapse, qj);
+ return TRUE;
}
static guint8* packet_add_response_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) {
g_assert(p);
g_assert(rj);
- if ((d = avahi_dns_packet_append_record(p, rj->record, rj->flush_cache))) {
+ if ((d = avahi_dns_packet_append_record(p, rj->record, rj->flush_cache, 0))) {
GTimeVal tv;
rj->done = 1;
g_assert(s);
- p = avahi_dns_packet_new_response(s->interface->hardware->mtu - 200);
+ p = avahi_dns_packet_new_response(s->interface->hardware->mtu);
n = 0;
/* If a job was specified, put it in the packet. */
return rj;
}
-void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
AvahiResponseJob *rj;
GTimeVal tv;
rj->flush_cache = flush_cache;
- return;
+ return FALSE;
}
/* Either one was a goodbye packet, but the other was not, so
if ((rj->address_valid = !!a))
rj->address = *a;
+
+ return TRUE;
}
void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) {
g_assert(pj);
s = pj->scheduler;
- p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+ p = avahi_dns_packet_new_query(s->interface->hardware->mtu);
/* Add the import probe */
if (!packet_add_probe_query(s, p, pj)) {
if (!pj->chosen)
continue;
- if (!avahi_dns_packet_append_record(p, pj->record, TRUE)) {
+ if (!avahi_dns_packet_append_record(p, pj->record, TRUE, 0)) {
g_warning("Bad probe size estimate!");
/* Unmark all following jobs */
avahi_dns_packet_free(p);
}
-void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately) {
+gboolean avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately) {
AvahiProbeJob *pj;
GTimeVal tv;
pj = probe_job_new(s, record);
pj->delivery = tv;
pj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &pj->delivery, probe_elapse, pj);
+
+ return TRUE;
}
AvahiPacketScheduler *avahi_packet_scheduler_new(AvahiServer *server, AvahiInterface *i);
void avahi_packet_scheduler_free(AvahiPacketScheduler *s);
-void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately);
-void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
-void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately);
+gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately);
+gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+gboolean avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately);
void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key);
void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record);
}
}
-static void handle_query_key(AvahiServer *s, AvahiKey *k, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) {
+static void send_unicast_response_packet(AvahiServer *s, AvahiInterface *i, const AvahiAddress *a, guint16 port) {
+ g_assert(s);
+ g_assert(a);
+ g_assert(port > 0);
+ g_assert(s->unicast_packet);
+
+ if (avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT) != 0)
+ avahi_interface_send_packet_unicast(i, s->unicast_packet, a, port);
+
+ avahi_dns_packet_free(s->unicast_packet);
+ s->unicast_packet = NULL;
+}
+
+static void post_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, AvahiRecord *r, gboolean flush_cache, gboolean legacy_unicast, gboolean unicast_response) {
+ g_assert(s);
+ g_assert(a);
+ g_assert(port > 0);
+ g_assert(r);
+
+ if (legacy_unicast) {
+
+ /* Respond with a legacy unicast packet */
+
+ if (!(s->unicast_packet))
+ s->unicast_packet = avahi_dns_packet_new_reply(p, 512 /* unicast DNS maximum packet size is 512 */ , TRUE, TRUE);
+
+ if (avahi_dns_packet_append_record(s->unicast_packet, r, FALSE, 10))
+
+ /* Increment the ANCOUNT field */
+
+ avahi_dns_packet_set_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT,
+ avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT)+1);
+
+ /* If there's no space left for this response we simply don't send it */
+
+ } else {
+
+ if (!avahi_interface_post_response(i, a, r, flush_cache, FALSE) && 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 */
+
+ for (;;) {
+
+ if (!(s->unicast_packet))
+ s->unicast_packet = avahi_dns_packet_new_reply(p, i->hardware->mtu, FALSE, FALSE);
+
+ if (avahi_dns_packet_append_record(s->unicast_packet, r, flush_cache, 0)) {
+
+ /* Appending this record succeeded, so incremeant
+ * the specific header field, and return to the caller */
+
+ avahi_dns_packet_set_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT,
+ avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT)+1);
+
+ break;
+ }
+
+ if (avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT) == 0) {
+ g_warning("Record too large, doesn't fit in any packet!");
+ return;
+ }
+
+ /* Appending the record didn't succeeed, so let's send this packet, and create a new one */
+
+ send_unicast_response_packet(s, i, a, port);
+
+ avahi_dns_packet_free(s->unicast_packet);
+ s->unicast_packet = NULL;
+ }
+
+ }
+ }
+}
+
+static void handle_query_key(AvahiServer *s, AvahiDnsPacket *p, AvahiKey *k, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) {
AvahiEntry *e;
gchar *txt;
for (e = s->entries; e; e = e->entries_next)
if (!e->dead && avahi_key_pattern_match(k, e->record->key) && avahi_entry_registered(s, e, i))
- avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE);
+ post_response(s, p, i, a, port, e->record, e->flags & AVAHI_ENTRY_UNIQUE, legacy_unicast, unicast_response);
+
} else {
/* Handle all other queries */
for (e = g_hash_table_lookup(s->entries_by_key, k); e; e = e->by_key_next)
if (!e->dead && avahi_entry_registered(s, e, i))
- avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE);
+ post_response(s, p, i, a, port, e->record, e->flags & AVAHI_ENTRY_UNIQUE, legacy_unicast, unicast_response);
}
}
g_assert(i);
g_assert(a);
+ g_assert(!s->unicast_packet);
+
/* Handle the questions */
for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n --) {
AvahiKey *key;
return;
}
- handle_query_key(s, key, i, a, port, legacy_unicast, unicast_response);
+ handle_query_key(s, p, key, i, a, port, legacy_unicast, unicast_response);
avahi_key_unref(key);
}
avahi_record_unref(record);
}
+
+ if (s->unicast_packet)
+ send_unicast_response_packet(s, i, a, port);
}
static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, gboolean unique, const AvahiAddress *a) {
s->hostname = g_strdup_printf("%s.local.", hn);
g_free(hn);
+ s->unicast_packet = NULL;
+
s->time_event_queue = avahi_time_event_queue_new(s->context, G_PRIORITY_DEFAULT+10); /* Slightly less priority than the FDs */
s->monitor = avahi_interface_monitor_new(s);
avahi_interface_monitor_sync(s->monitor);
g_source_unref(s->source);
g_main_context_unref(s->context);
+ if (s->unicast_packet)
+ avahi_dns_packet_free(s->unicast_packet);
+
g_free(s);
}
#include "timeeventq.h"
#include "announce.h"
#include "subscribe.h"
+#include "dns.h"
struct AvahiEntry {
AvahiServer *server;
GSource *source;
gboolean ignore_bad_ttl;
+
+ AvahiDnsPacket *unicast_packet;
};
gboolean avahi_server_entry_match_interface(AvahiEntry *e, AvahiInterface *i);
inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
}
-int avahi_mdns_mcast_join_ipv4 (int index, int fd)
-{
+static void ipv4_address_to_sockaddr(struct sockaddr_in *ret_sa, const AvahiIPv4Address *a, guint16 port) {
+ g_assert(ret_sa);
+ g_assert(a);
+ g_assert(port > 0);
+
+ memset(ret_sa, 0, sizeof(struct sockaddr_in));
+ ret_sa->sin_family = AF_INET;
+ ret_sa->sin_port = htons(port);
+ memcpy(&ret_sa->sin_addr, a, sizeof(AvahiIPv4Address));
+}
+
+static void ipv6_address_to_sockaddr(struct sockaddr_in6 *ret_sa, const AvahiIPv6Address *a, guint16 port) {
+ g_assert(ret_sa);
+ g_assert(a);
+ g_assert(port > 0);
+
+ memset(ret_sa, 0, sizeof(struct sockaddr_in6));
+ ret_sa->sin6_family = AF_INET6;
+ ret_sa->sin6_port = htons(port);
+ memcpy(&ret_sa->sin6_addr, a, sizeof(AvahiIPv6Address));
+}
+
+int avahi_mdns_mcast_join_ipv4 (int index, int fd) {
struct ip_mreqn mreq;
struct sockaddr_in sa;
return 0;
}
-int avahi_mdns_mcast_join_ipv6 (int index, int fd)
-{
+int avahi_mdns_mcast_join_ipv6 (int index, int fd) {
struct ipv6_mreq mreq6;
struct sockaddr_in6 sa6;
return 0;
}
-int avahi_mdns_mcast_leave_ipv4 (int index, int fd)
-{
+int avahi_mdns_mcast_leave_ipv4 (int index, int fd) {
struct ip_mreqn mreq;
struct sockaddr_in sa;
return 0;
}
-int avahi_mdns_mcast_leave_ipv6 (int index, int fd)
-{
+int avahi_mdns_mcast_leave_ipv6 (int index, int fd) {
struct ipv6_mreq mreq6;
struct sockaddr_in6 sa6;
return 0;
}
-gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p) {
+gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p, const AvahiIPv4Address *a, guint16 port) {
struct sockaddr_in sa;
struct msghdr msg;
struct iovec io;
g_assert(fd >= 0);
g_assert(p);
g_assert(avahi_dns_packet_check_valid(p) >= 0);
+ g_assert(!a || port > 0);
- mdns_mcast_group_ipv4(&sa);
+ if (!a)
+ mdns_mcast_group_ipv4(&sa);
+ else
+ ipv4_address_to_sockaddr(&sa, a, port);
memset(&io, 0, sizeof(io));
io.iov_base = AVAHI_DNS_PACKET_DATA(p);
return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
}
-gint avahi_send_dns_packet_ipv6(gint fd, gint interface, AvahiDnsPacket *p) {
+gint avahi_send_dns_packet_ipv6(gint fd, gint interface, AvahiDnsPacket *p, const AvahiIPv6Address *a, guint16 port) {
struct sockaddr_in6 sa;
struct msghdr msg;
struct iovec io;
g_assert(p);
g_assert(avahi_dns_packet_check_valid(p) >= 0);
- mdns_mcast_group_ipv6(&sa);
+ if (!a)
+ mdns_mcast_group_ipv6(&sa);
+ else
+ ipv6_address_to_sockaddr(&sa, a, port);
memset(&io, 0, sizeof(io));
io.iov_base = AVAHI_DNS_PACKET_DATA(p);
gint avahi_open_socket_ipv4(void);
gint avahi_open_socket_ipv6(void);
-gint avahi_send_dns_packet_ipv4(gint fd, gint iface, AvahiDnsPacket *p);
-gint avahi_send_dns_packet_ipv6(gint fd, gint iface, AvahiDnsPacket *p);
+gint avahi_send_dns_packet_ipv4(gint fd, gint iface, AvahiDnsPacket *p, const AvahiIPv4Address *a, guint16 port);
+gint avahi_send_dns_packet_ipv6(gint fd, gint iface, AvahiDnsPacket *p, const AvahiIPv6Address *a, guint16 port);
AvahiDnsPacket *avahi_recv_dns_packet_ipv4(gint fd, struct sockaddr_in*ret_sa, gint *ret_iface, guint8 *ret_ttl);
AvahiDnsPacket *avahi_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6*ret_sa, gint *ret_iface, guint8 *ret_ttl);
todo:
-* Unicast responses/queries
-* Legacy unicast
-
* add SRV and TXT records referenced from PTR records automatically to packet
* add A and AAAA records referenced from SRV records automatically to packet
* allow NULL bytes in TXT records
* add flx_server_add_service_strlst() and friends
* change flx_* to avahi_*
+* Unicast responses/queries
+* Legacy unicast