cache_update(void)
{
struct cache_service *s;
- int count = 2;
- dns_packet_init();
- dns_packet_question(C_DNS_SD, TYPE_ANY);
- dns_packet_question(C_DNS_SD, TYPE_PTR);
+ dns_query(C_DNS_SD, TYPE_ANY);
+ dns_query(C_DNS_SD, TYPE_PTR);
avl_for_each_element(&services, s, avl) {
if (s->host) {
- dns_packet_question(s->host, TYPE_A);
- dns_packet_question(s->host, TYPE_AAAA);
+ dns_query(s->host, TYPE_A);
+ dns_query(s->host, TYPE_AAAA);
} else {
- dns_packet_question(s->entry, TYPE_PTR);
+ dns_query(s->entry, TYPE_PTR);
}
- if (++count < 16)
- continue;
- dns_packet_broadcast();
- count = 0;
}
-
- if (count)
- dns_packet_broadcast();
}
static struct cache_service*
s->avl.key = type;
avl_insert(&services, &s->avl);
- dns_packet_init();
if (hlen) {
- dns_packet_question(s->host, TYPE_A);
- dns_packet_question(s->host, TYPE_AAAA);
+ dns_query(s->host, TYPE_A);
+ dns_query(s->host, TYPE_AAAA);
} else {
- dns_packet_question(entry, TYPE_PTR);
+ dns_query(entry, TYPE_PTR);
}
- dns_packet_broadcast();
return s;
}
#include <libubox/uloop.h>
#include <libubox/usock.h>
#include <libubox/utils.h>
+#include <libubox/avl-cmp.h>
#include "announce.h"
#include "util.h"
#include "service.h"
#include "interface.h"
+#define QUERY_BATCH_SIZE 16
+
+struct query_entry {
+ struct avl_node node;
+ uint16_t type;
+ char name[];
+};
+
+static AVL_TREE(queries, avl_strcmp, true, NULL);
static char name_buffer[MAX_NAME_LEN + 1];
static struct {
perror("failed to send answer");
}
-void dns_packet_broadcast(void)
+static void dns_packet_broadcast(void)
{
struct interface *iface;
dns_packet_send(iface, to, true, multicast);
}
+static void
+dns_query_pending(struct uloop_timeout *t)
+{
+ struct query_entry *e, *tmp;
+ int count = 0;
+
+ dns_packet_init();
+ avl_remove_all_elements(&queries, e, node, tmp) {
+ dns_packet_question(e->name, e->type);
+ free(e);
+
+ if (++count < QUERY_BATCH_SIZE)
+ continue;
+
+ count = 0;
+ dns_packet_broadcast();
+ }
+
+ if (count)
+ dns_packet_broadcast();
+}
+
+void dns_query(const char *name, uint16_t type)
+{
+ static struct uloop_timeout timer = {
+ .cb = dns_query_pending
+ };
+ struct query_entry *e;
+
+ e = avl_find_element(&queries, name, e, node);
+ while (e) {
+ if (e->type == type)
+ return;
+
+ e = avl_next_element(e, node);
+ if (strcmp(e->name, name) != 0)
+ break;
+ }
+
+ e = calloc(1, sizeof(*e) + strlen(name) + 1);
+ e->type = type;
+ e->node.key = e->name;
+ strcpy(e->name, name);
+ avl_insert(&queries, &e->node);
+
+ if (queries.count > QUERY_BATCH_SIZE)
+ timer.cb(&timer);
+
+ if (!timer.pending)
+ uloop_timeout_set(&timer, 100);
+}
+
void
dns_reply_a(struct interface *iface, struct sockaddr *to, int ttl, const char *hostname)
{
bool dns_packet_question(const char *name, int type);
void dns_packet_answer(const char *name, int type, const uint8_t *rdata, uint16_t rdlength, int ttl);
void dns_packet_send(struct interface *iface, struct sockaddr *to, bool query, int multicast);
-void dns_packet_broadcast(void);
+
+void dns_query(const char *name, uint16_t type);
void dns_send_question(struct interface *iface, struct sockaddr *to,
const char *question, int type, int multicast);