1#include <stdlib.h>
2#include <avahi-common/malloc.h>
3#include <avahi-core/log.h>
4
5#include "llmnr-response.h"
6
7AvahiLLMNRResponseScheduler *avahi_llmnr_response_scheduler_new(AvahiInterface *i) {
8    AvahiLLMNRResponseScheduler *s;
9
10    assert(i);
11
12    if (!(s = avahi_new(AvahiLLMNRResponseScheduler, 1)))
13        return NULL;
14
15    s->interface = i;
16    s->time_event_queue = i->monitor->server->time_event_queue;
17
18    AVAHI_LLIST_HEAD_INIT(AvahiLLMNRResponseJob, s->jobs);
19
20    return s;
21}
22
23static AvahiLLMNRResponseJob *job_new(
24    AvahiLLMNRResponseScheduler *s,
25    AvahiDnsPacket *p,
26    const AvahiAddress *a,
27    uint16_t port) {
28    AvahiLLMNRResponseJob *rj;
29
30    assert(a->proto == s->interface->protocol);
31
32    if (!(rj = avahi_new(AvahiLLMNRResponseJob, 1)))
33        return NULL;
34
35    rj->s = s;
36    rj->reply = p;
37    rj->address = *a;
38    rj->port = port;
39    rj->time_event = NULL;
40
41    AVAHI_LLIST_PREPEND(AvahiLLMNRResponseJob, jobs, s->jobs , rj);
42
43    return rj;
44}
45
46void avahi_llmnr_response_job_free(AvahiLLMNRResponseScheduler *s, AvahiLLMNRResponseJob *rj) {
47    assert(s);
48    assert(rj);
49
50    if (rj->time_event)
51        avahi_time_event_free(rj->time_event);
52
53    if (rj->reply)
54        avahi_dns_packet_free(rj->reply);
55
56    AVAHI_LLIST_REMOVE(AvahiLLMNRResponseJob, jobs, s->jobs, rj);
57
58    avahi_free(rj);
59}
60
61
62void avahi_llmnr_response_scheduler_clear(AvahiLLMNRResponseScheduler *s) {
63    assert(s);
64
65    while (s->jobs)
66        avahi_llmnr_response_job_free(s, s->jobs);
67}
68
69void avahi_llmnr_response_scheduler_free(AvahiLLMNRResponseScheduler *s) {
70    assert(s);
71
72    avahi_llmnr_response_scheduler_clear(s);
73    avahi_free(s);
74}
75
76static void elapse_response_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void *userdata) {
77    AvahiLLMNRResponseJob *rj = userdata;
78
79    assert(rj);
80
81    /* Send Packet */
82    avahi_interface_send_packet_unicast(rj->s->interface, rj->reply, &rj->address, rj->port, AVAHI_LLMNR);
83    avahi_llmnr_response_job_free(rj->s, rj);
84}
85
86int avahi_post_llmnr_response(AvahiLLMNRResponseScheduler *s, AvahiDnsPacket *p, const AvahiAddress *a, uint16_t port) {
87    AvahiLLMNRResponseJob *rj;
88    struct timeval tv;
89
90    assert(s);
91    assert(p);
92    assert(a);
93    assert(port);
94
95    assert(a->proto == s->interface->protocol);
96
97    if (!s->interface->llmnr.verifying)
98        return 0;
99
100    if (!(rj = job_new(s, p, a, port)))
101        return 0;
102
103    avahi_elapse_time(&tv, 0, AVAHI_LLMNR_JITTER);
104    rj->time_event = avahi_time_event_new(s->time_event_queue, &tv, elapse_response_callback, rj);
105
106    return 1;
107}
108
109
110