• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/avahi-0.6.31/avahi-core/
1#include <string.h>
2#include <stdio.h>
3
4#include <avahi-common/timeval.h>
5#include <avahi-common/malloc.h>
6
7#include "log.h"
8#include "rrlist.h"
9
10#include "llmnr-query-sched.h"
11#include "dns.h"
12#include "verify.h"
13
14AvahiLLMNRQueryScheduler *avahi_llmnr_query_scheduler_new(AvahiInterface *i) {
15    AvahiLLMNRQueryScheduler *s;
16    assert(i);
17
18    if (!(s = avahi_new(AvahiLLMNRQueryScheduler, 1)))
19        return NULL;
20
21    s->i = i;
22    s->time_event_queue = i->monitor->server->time_event_queue;
23    s->next_id = 1;
24    AVAHI_LLIST_HEAD_INIT(AvahiLLMNRQueryJob, s->jobs);
25
26    return s;
27}
28
29void avahi_llmnr_query_scheduler_free(AvahiLLMNRQueryScheduler *s) {
30    assert(s);
31
32    avahi_llmnr_query_scheduler_clear(s);
33    avahi_free(s);
34}
35
36void avahi_llmnr_query_scheduler_clear(AvahiLLMNRQueryScheduler *s) {
37    assert(s);
38
39    while (s->jobs)
40        avahi_llmnr_query_job_destroy(s, s->jobs);
41}
42
43void avahi_llmnr_query_job_destroy(AvahiLLMNRQueryScheduler *s, AvahiLLMNRQueryJob *qj) {
44    assert(s);
45    assert(qj);
46
47     /* Free lq */
48    avahi_llmnr_query_destroy(qj->lq);
49
50    /* Free dns packet and time_event */
51    if (qj->p)
52        avahi_dns_packet_free(qj->p);
53
54    if (qj->time_event)
55        avahi_time_event_free(qj->time_event);
56
57    /* Remove from the lists */
58    AVAHI_LLIST_REMOVE(AvahiLLMNRQueryJob, jobs_by_scheduler, s->jobs, qj);
59    AVAHI_LLIST_REMOVE(AvahiLLMNRQueryJob, jobs_by_interface, s->i->llmnr.queryjobs, qj);
60
61    avahi_free(qj);
62}
63
64static void avahi_prepare_llmnr_query_job_packet(AvahiLLMNRQueryJob *qj) {
65    assert(qj);
66
67    /* New Packet*/
68    qj->p = avahi_llmnr_packet_new_query(512 + AVAHI_DNS_PACKET_EXTRA_SIZE);
69
70    /* Set ID*/
71    avahi_dns_packet_set_field(qj->p, AVAHI_LLMNR_FIELD_ID, (uint16_t)(qj->lq->id));
72
73    /*Append Key*/
74    if (!avahi_llmnr_packet_append_key(qj->p, qj->lq->key))
75        return;
76
77    /* Set QDCOUNT */
78    avahi_dns_packet_set_field(qj->p, AVAHI_LLMNR_FIELD_QDCOUNT, 1);
79
80}
81
82static AvahiLLMNRQueryJob *job_new(AvahiLLMNRQueryScheduler *s, AvahiLLMNRQuery *lq) {
83    AvahiLLMNRQueryJob *qj;
84
85    assert(s);
86    assert(lq);
87
88    if (!(qj = avahi_new(AvahiLLMNRQueryJob, 1)))
89        return NULL;
90
91    qj->scheduler = s;
92    qj->lq = lq;
93
94    /* Set lq parameters */
95    lq->post_id_valid = 1;
96    lq->post_id = s->next_id++;
97
98    /* qj parameters */
99    qj->n_sent = 0;
100    qj->prev_scheduled = 0;
101    qj->time_event = NULL;
102
103    /* Prepend in Lists */
104    AVAHI_LLIST_PREPEND(AvahiLLMNRQueryJob, jobs_by_scheduler, s->jobs, qj);
105    AVAHI_LLIST_PREPEND(AvahiLLMNRQueryJob, jobs_by_interface, s->i->llmnr.queryjobs, qj);
106
107    /*Just prepare dns packet, don't send it */
108    avahi_prepare_llmnr_query_job_packet(qj);
109
110    return qj;
111}
112
113
114static void resend_llmnr_query(AvahiLLMNRQueryJob *qj) {
115    AvahiLLMNRQuery *lq = qj->lq;
116    struct timeval tv;
117    assert(qj);
118
119    if (lq->type == AVAHI_LLMNR_SIMPLE_QUERY || lq->type == AVAHI_LLMNR_UNIQUENESS_VERIFICATION_QUERY) {
120        /**Check whether we have already sent this query three times */
121        if (qj->n_sent >= 3) {
122            lq->callback(lq->interface->hardware->index, lq->interface->protocol, NULL, lq->userdata);
123            avahi_llmnr_query_job_destroy(qj->scheduler, qj);
124            /* Free Timeevent */
125/*            avahi_time_event_free(qj->time_event);
126            qj->time_event = NULL;*/
127
128        } else {
129
130            /* Send packet */
131            avahi_interface_send_packet(lq->interface, qj->p, AVAHI_LLMNR);
132            (qj->n_sent)++;
133            /* Schedule further queries*/
134            avahi_elapse_time(&tv, AVAHI_LLMNR_INTERVAL, 0);
135            avahi_time_event_update(qj->time_event, &tv);
136        }
137
138    } else {
139
140        assert(lq->type == AVAHI_LLMNR_CONFLICT_QUERY);
141        assert(qj->n_sent == 1);
142
143        /* Destroy this query */
144        lq->callback(lq->interface->hardware->index, lq->interface->protocol, NULL, lq->userdata);
145        avahi_llmnr_query_job_destroy(qj->scheduler, qj);
146    }
147
148    return;
149}
150
151static void reschedule_llmnr_query_job(AvahiLLMNRQueryJob *qj) {
152    struct timeval tv;
153
154    assert(qj);
155    assert(!avahi_record_list_is_empty(qj->lq->c_bit_clear));
156
157    if (!(qj->prev_scheduled)) {
158
159        qj->prev_scheduled = 1;
160        avahi_elapse_time(&tv, AVAHI_LLMNR_INTERVAL + AVAHI_LLMNR_JITTER, 0);
161        avahi_time_event_update(qj->time_event, &tv);
162
163    } else {
164        /* We have already waited but we still have not received any response/s
165        with 'c' bit clear. */
166        qj->lq->callback(qj->lq->interface->hardware->index, qj->lq->interface->protocol, NULL, qj->lq->userdata);
167        /*avahi_time_event_free(qj->time_event);
168        qj->time_event = NULL;*/
169        avahi_llmnr_query_job_destroy(qj->scheduler, qj);
170    }
171    return;
172}
173
174static void call_llmnr_query_callback(AvahiLLMNRQuery *lq) {
175    AvahiRecord *r;
176
177    assert(lq);
178    assert(avahi_record_list_is_empty(lq->c_bit_set));
179
180    while ((r = avahi_record_list_next(lq->c_bit_clear, NULL, NULL, NULL)))
181        lq->callback(lq->interface->hardware->index, lq->interface->protocol, r, lq->userdata);
182
183    return;
184}
185
186static void send_conflict_query(AvahiLLMNRQueryJob *qj) {
187    /* Send the packet */
188    AvahiRecord *r;
189    AvahiLLMNRQuery *lq;
190    assert(qj);
191
192    /* We use the same lq */
193
194    /*1. Change 'lq->type' and reset 'n_sent' */
195    lq = qj->lq;
196    lq->callback(lq->interface->hardware->index, lq->interface->protocol, NULL, lq->userdata);
197    lq->type = AVAHI_LLMNR_CONFLICT_QUERY;
198    qj->n_sent = 0;
199
200    /* Reset 'c' bit in existing packet */
201    avahi_dns_packet_set_field(qj->p, AVAHI_LLMNR_FIELD_FLAGS, AVAHI_LLMNR_FLAGS(0, 0, 1, 0, 0, 0, 0));
202
203    /* Append records */
204    while ((r = avahi_record_list_next(lq->c_bit_clear, NULL, NULL, NULL))) {
205        /* Append Record TODO TTL*/
206        if (!(avahi_llmnr_packet_append_record(qj->p, r, AVAHI_DEFAULT_TTL)))
207        /* we send only those much of record which fits in */
208            break;
209        avahi_dns_packet_inc_field(qj->p, AVAHI_LLMNR_FIELD_ARCOUNT);
210    }
211
212    /* Send packet */
213    if (avahi_dns_packet_get_field(qj->p, AVAHI_LLMNR_FIELD_ARCOUNT) != 0)
214        avahi_interface_send_packet(lq->interface, qj->p, AVAHI_LLMNR);
215
216    /* Destroy this AvahiLLMNRQueryJob */
217    avahi_llmnr_query_job_destroy(qj->scheduler, qj);
218
219    return;
220
221}
222
223static void elapse_timeout_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void *userdata) {
224    AvahiLLMNRQueryJob *qj = userdata;
225    AvahiLLMNRQuery *lq = qj->lq;
226    int c_bit_set, c_bit_clear, counter;
227
228    c_bit_set = avahi_record_list_is_empty(lq->c_bit_set);
229    c_bit_clear = avahi_record_list_is_empty(lq->c_bit_clear);
230
231    counter = (2*(!c_bit_set)) + (!c_bit_clear);
232
233    switch (counter)/*TODO, clean it*/  {
234
235        case 0 :
236             /*We have not yet received any responses. Try to resend the same query*/
237            resend_llmnr_query(qj);
238            break;
239
240        case 1 :
241            /*We have received one or multiple reponse/s with 'c' bit clear
242            and none with 'c' bit set within AVAHI_LLMNR_TIMEOUT. It means
243            query has been replied. */
244            call_llmnr_query_callback(lq);
245            avahi_llmnr_query_job_destroy(qj->scheduler, qj);
246            /*avahi_time_event_free(qj->time_event);
247            qj->time_event = NULL;*/
248            break;
249
250        case 2 :
251            /*We have received atleast one response with 'c' bit set but we didn't
252            receive any response with 'c' bit clear. We don't want to send this query
253            further but wait for atleast LLMNR_TIMEOUT + JITTER_INTERVAL to collect
254            more responses, if any */
255            reschedule_llmnr_query_job(qj);
256            break;
257
258        case 3 :
259            /*This is conflict. Let us send AVAHI_LLMNR_CONFLICT_QUERY (with c bit set
260            in query) along with responses*/
261            avahi_log_info("CONFLICT..CONFLICT..CONFLICT");
262            send_conflict_query(qj);
263            avahi_llmnr_query_job_destroy(qj->scheduler, qj);
264            break;
265    }
266
267    return;
268}
269
270int avahi_llmnr_query_scheduler_post(AvahiLLMNRQueryScheduler *s, AvahiLLMNRQuery *lq, int immediately) {
271    AvahiLLMNRQueryJob *qj;
272    struct timeval tv;
273
274    assert(s);
275    assert(lq);
276
277    if (!(qj = job_new(s, lq)))
278        return 0;
279
280    qj->time_event = avahi_time_event_new(s->time_event_queue,
281                                          avahi_elapse_time(&tv, 0, immediately ? 0 : AVAHI_LLMNR_JITTER),
282                                          elapse_timeout_callback,
283                                          qj);
284
285    return 1;
286}
287
288int avahi_llmnr_query_scheduler_withdraw_by_id(AvahiLLMNRQueryScheduler *s, unsigned post_id) {
289    AvahiLLMNRQueryJob *qj;
290
291    assert(s);
292
293    for (qj = s->jobs; qj; qj = qj->jobs_by_scheduler_next) {
294        assert(!(qj->lq->dead));
295
296        if (qj->lq->post_id == post_id) {
297            avahi_llmnr_query_job_destroy(qj->scheduler, qj);
298            return 1;
299        }
300    }
301
302    return 0;
303}
304
305void avahi_llmnr_query_job_remove(AvahiInterface *i, AvahiKey *key) {
306    AvahiLLMNRQueryJob *qj;
307
308    assert(i);
309    assert(key);
310
311    if (!(qj = avahi_hashmap_lookup(i->llmnr.queryjobs_by_key, key)))
312    /* No AvahiLLMNRQueryJob object present for this key*/
313        return;
314
315    avahi_llmnr_query_job_destroy(qj->scheduler, qj);
316
317    return;
318}
319