~ubuntu-branches/ubuntu/karmic/psi/karmic

« back to all changes in this revision

Viewing changes to iris/irisnet/jdns/jdns.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005,2006  Justin Karneges
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
 
5
 * copy of this software and associated documentation files (the
 
6
 * "Software"), to deal in the Software without restriction, including
 
7
 * without limitation the rights to use, copy, modify, merge, publish,
 
8
 * distribute, sublicense, and/or sell copies of the Software, and to
 
9
 * permit persons to whom the Software is furnished to do so, subject to
 
10
 * the following conditions:
 
11
 *
 
12
 * The above copyright notice and this permission notice shall be included
 
13
 * in all copies or substantial portions of the Software.
 
14
 *
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
16
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 
19
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
21
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 */
 
23
 
 
24
#include "jdns_p.h"
 
25
 
 
26
#include <time.h>
 
27
 
 
28
#include "jdns_packet.h"
 
29
#include "jdns_mdnsd.h"
 
30
 
 
31
#define JDNS_UDP_UNI_OUT_MAX  512
 
32
#define JDNS_UDP_UNI_IN_MAX   16384
 
33
#define JDNS_UDP_MUL_OUT_MAX  9000
 
34
#define JDNS_UDP_MUL_IN_MAX   16384
 
35
 
 
36
// cache no more than 7 days
 
37
#define JDNS_TTL_MAX          (86400 * 7)
 
38
 
 
39
//----------------------------------------------------------------------------
 
40
// util
 
41
//----------------------------------------------------------------------------
 
42
 
 
43
// declare this here, but implement it later after we define jdns_session_t
 
44
static void _debug_line(jdns_session_t *s, const char *format, ...);
 
45
 
 
46
static unsigned char _hex_nibble(unsigned char c)
 
47
{
 
48
        if(c <= 9)
 
49
                return '0' + c;
 
50
        else if(c <= 15)
 
51
                return 'a' + (c - 10);
 
52
        else
 
53
                return '?';
 
54
}
 
55
 
 
56
static void _hex_byte(unsigned char c, unsigned char *dest)
 
57
{
 
58
        dest[0] = _hex_nibble((unsigned char)(c >> 4));
 
59
        dest[1] = _hex_nibble((unsigned char)(c & 0x0f));
 
60
}
 
61
 
 
62
static jdns_string_t *_make_printable(const unsigned char *str, int size)
 
63
{
 
64
        unsigned char *buf;
 
65
        int n, i;
 
66
        jdns_string_t *out;
 
67
 
 
68
        if(size == 0)
 
69
        {
 
70
                out = jdns_string_new();
 
71
                jdns_string_set_cstr(out, "");
 
72
                return out;
 
73
        }
 
74
 
 
75
        // make room for the largest possible result
 
76
        buf = (unsigned char *)malloc(size * 4);
 
77
        i = 0;
 
78
        for(n = 0; n < size; ++n)
 
79
        {
 
80
                unsigned char c = str[n];
 
81
                if(c == '\\')
 
82
                {
 
83
                        buf[i++] = '\\';
 
84
                        buf[i++] = '\\';
 
85
                }
 
86
                else if(c >= 0x20 && c < 0x7f)
 
87
                {
 
88
                        buf[i++] = c;
 
89
                }
 
90
                else
 
91
                {
 
92
                        buf[i++] = '\\';
 
93
                        buf[i++] = 'x';
 
94
                        _hex_byte(c, buf + i);
 
95
                        i += 2;
 
96
                }
 
97
        }
 
98
 
 
99
        out = jdns_string_new();
 
100
        jdns_string_set(out, buf, i);
 
101
        free(buf);
 
102
        return out;
 
103
}
 
104
 
 
105
static jdns_string_t *_make_printable_str(const jdns_string_t *str)
 
106
{
 
107
        return _make_printable(str->data, str->size);
 
108
}
 
109
 
 
110
static jdns_string_t *_make_printable_cstr(const char *str)
 
111
{
 
112
        return _make_printable((const unsigned char *)str, strlen(str));
 
113
}
 
114
 
 
115
static unsigned char *_fix_input(const unsigned char *in)
 
116
{
 
117
        unsigned char *out;
 
118
        int len;
 
119
 
 
120
        // truncate
 
121
        len = _ustrlen(in);
 
122
        if(len > 254)
 
123
                len = 254;
 
124
 
 
125
        // add a dot to the end if needed
 
126
        if(in[len - 1] != '.' && len < 254)
 
127
        {
 
128
                out = (unsigned char *)malloc(len + 2); // a dot and a zero
 
129
                memcpy(out, in, len);
 
130
                out[len] = '.';
 
131
                out[len+1] = 0;
 
132
                ++len;
 
133
        }
 
134
        else
 
135
        {
 
136
                out = (unsigned char *)malloc(len + 1); // a zero
 
137
                memcpy(out, in, len);
 
138
                out[len] = 0;
 
139
        }
 
140
 
 
141
        return out;
 
142
}
 
143
 
 
144
static const char *_qtype2str(int qtype)
 
145
{
 
146
        const char *str;
 
147
        switch(qtype)
 
148
        {
 
149
                case JDNS_RTYPE_A:     str = "A";     break;
 
150
                case JDNS_RTYPE_AAAA:  str = "AAAA";  break;
 
151
                case JDNS_RTYPE_MX:    str = "MX";    break;
 
152
                case JDNS_RTYPE_SRV:   str = "SRV";   break;
 
153
                case JDNS_RTYPE_CNAME: str = "CNAME"; break;
 
154
                case JDNS_RTYPE_PTR:   str = "PTR";   break;
 
155
                case JDNS_RTYPE_TXT:   str = "TXT";   break;
 
156
                case JDNS_RTYPE_HINFO: str = "HINFO"; break;
 
157
                case JDNS_RTYPE_NS:    str = "NS";    break;
 
158
                case JDNS_RTYPE_ANY:   str = "ANY";   break;
 
159
                default:               str = "";      break;
 
160
        }
 
161
        return str;
 
162
}
 
163
 
 
164
static jdns_response_t *_packet2response(const jdns_packet_t *packet, const unsigned char *qname, int qtype, int classmask)
 
165
{
 
166
        int n;
 
167
        jdns_response_t *r;
 
168
 
 
169
        r = jdns_response_new();
 
170
        for(n = 0; n < packet->answerRecords->count; ++n)
 
171
        {
 
172
                jdns_packet_resource_t *res = (jdns_packet_resource_t *)packet->answerRecords->item[n];
 
173
                jdns_rr_t *rr;
 
174
                int put_in_answer;
 
175
                if((res->qclass & classmask) != 0x0001)
 
176
                        continue;
 
177
                rr = jdns_rr_from_resource(res, packet);
 
178
                if(!rr)
 
179
                        continue;
 
180
                // if qname is set, restrict answers to those that match
 
181
                //  the question
 
182
                put_in_answer = 1;
 
183
                if(qname)
 
184
                {
 
185
                        // name must match, type can match or be CNAME
 
186
                        if((res->qtype != qtype && res->qtype != JDNS_RTYPE_CNAME) || !jdns_domain_cmp(res->qname->data, qname))
 
187
                        {
 
188
                                // put unusable records in additional section
 
189
                                put_in_answer = 0;
 
190
                        }
 
191
                }
 
192
                if(put_in_answer)
 
193
                        jdns_response_append_answer(r, rr);
 
194
                else
 
195
                        jdns_response_append_additional(r, rr);
 
196
                jdns_rr_delete(rr);
 
197
        }
 
198
        for(n = 0; n < packet->authorityRecords->count; ++n)
 
199
        {
 
200
                jdns_packet_resource_t *res = (jdns_packet_resource_t *)packet->authorityRecords->item[n];
 
201
                jdns_rr_t *rr;
 
202
                if((res->qclass & classmask) != 0x0001)
 
203
                        continue;
 
204
                rr = jdns_rr_from_resource(res, packet);
 
205
                if(!rr)
 
206
                        continue;
 
207
                jdns_response_append_authority(r, rr);
 
208
                jdns_rr_delete(rr);
 
209
        }
 
210
        for(n = 0; n < packet->additionalRecords->count; ++n)
 
211
        {
 
212
                jdns_packet_resource_t *res = (jdns_packet_resource_t *)packet->additionalRecords->item[n];
 
213
                jdns_rr_t *rr;
 
214
                if((res->qclass & classmask) != 0x0001)
 
215
                        continue;
 
216
                rr = jdns_rr_from_resource(res, packet);
 
217
                if(!rr)
 
218
                        continue;
 
219
                jdns_response_append_additional(r, rr);
 
220
                jdns_rr_delete(rr);
 
221
        }
 
222
        return r;
 
223
}
 
224
 
 
225
// size must be 1 to 16
 
226
static void _print_hexdump_line(jdns_session_t *s, const unsigned char *buf, int size)
 
227
{
 
228
        char line[67]; // 3 * 16 + 2 + 16 + zero byte
 
229
        int n;
 
230
 
 
231
        memset(line, ' ', 66);
 
232
        line[66] = 0;
 
233
        if(size > 16)
 
234
                size = 16;
 
235
        for(n = 0; n < size; ++n)
 
236
        {
 
237
                unsigned char c = buf[n];
 
238
                _hex_byte(c, ((unsigned char *)line) + n * 3);
 
239
                line[n * 3 + 2] = ' ';
 
240
                if(c >= 0x20 && c < 0x7f)
 
241
                        line[50 + n] = c;
 
242
                else
 
243
                        line[50 + n] = '.';
 
244
        }
 
245
        _debug_line(s, "  %s", line);
 
246
}
 
247
 
 
248
static void _print_hexdump(jdns_session_t *s, const unsigned char *buf, int size)
 
249
{
 
250
        int n;
 
251
        int lines;
 
252
        int at, len;
 
253
 
 
254
        lines = size / 16;
 
255
        if(size % 16 != 0)
 
256
                ++lines;
 
257
        for(n = 0; n < lines; ++n)
 
258
        {
 
259
                at = n * 16;
 
260
                if(at + 16 <= size)
 
261
                        len = 16;
 
262
                else
 
263
                        len = size - at;
 
264
                _print_hexdump_line(s, buf + at, len);
 
265
        }
 
266
}
 
267
 
 
268
static void _print_packet_resources(jdns_session_t *s, const jdns_list_t *reslist)
 
269
{
 
270
        int n;
 
271
        for(n = 0; n < reslist->count; ++n)
 
272
        {
 
273
                jdns_packet_resource_t *r;
 
274
                jdns_string_t *str;
 
275
                r = (jdns_packet_resource_t *)reslist->item[n];
 
276
                str = _make_printable_str(r->qname);
 
277
                _debug_line(s, "    %04x/%04x [%s] ttl=%ld size=%d", r->qclass, r->qtype, str->data, r->ttl, r->rdlength);
 
278
                jdns_string_delete(str);
 
279
        }
 
280
}
 
281
 
 
282
static void _print_packet(jdns_session_t *s, const jdns_packet_t *packet)
 
283
{
 
284
        int n;
 
285
        _debug_line(s, "Packet:");
 
286
        _debug_line(s, "  id:   %d", packet->id);
 
287
        _debug_line(s, "  opts: qr:%d, opcode:%d, aa:%d, tc:%d, rd:%d, ra:%d, z:%d, rcode:%d",
 
288
                packet->opts.qr, packet->opts.opcode, packet->opts.aa, packet->opts.tc,
 
289
                packet->opts.rd, packet->opts.ra, packet->opts.z, packet->opts.rcode);
 
290
        _debug_line(s, "  qdcount=%d, ancount=%d, nscount=%d, arcount=%d",
 
291
                packet->qdcount, packet->ancount, packet->nscount, packet->arcount);
 
292
        if(packet->questions->count > 0)
 
293
        {
 
294
                _debug_line(s, "  questions: (class/type name)");
 
295
                for(n = 0; n < packet->questions->count; ++n)
 
296
                {
 
297
                        jdns_packet_question_t *q;
 
298
                        jdns_string_t *str;
 
299
                        q = (jdns_packet_question_t *)packet->questions->item[n];
 
300
                        str = _make_printable_str(q->qname);
 
301
                        _debug_line(s, "    %04x/%04x [%s]", q->qclass, q->qtype, str->data);
 
302
                        jdns_string_delete(str);
 
303
                }
 
304
        }
 
305
        if(packet->answerRecords->count > 0)
 
306
        {
 
307
                _debug_line(s, "  answerRecords: (class/type owner ttl size)");
 
308
                _print_packet_resources(s, packet->answerRecords);
 
309
        }
 
310
        if(packet->authorityRecords->count > 0)
 
311
        {
 
312
                _debug_line(s, "  authorityRecords: (class/type owner ttl size)");
 
313
                _print_packet_resources(s, packet->authorityRecords);
 
314
        }
 
315
        if(packet->additionalRecords->count > 0)
 
316
        {
 
317
                _debug_line(s, "  additionalRecords: (class/type owner ttl size)");
 
318
                _print_packet_resources(s, packet->additionalRecords);
 
319
        }
 
320
}
 
321
 
 
322
static void _print_rr(jdns_session_t *s, const jdns_rr_t *rr, const unsigned char *owner)
 
323
{
 
324
        int n;
 
325
        jdns_string_t *ownerstr;
 
326
 
 
327
        ownerstr = jdns_string_new();
 
328
 
 
329
        // not the expected owner?
 
330
        if(!owner || !jdns_domain_cmp(owner, rr->owner))
 
331
        {
 
332
                unsigned char *buf;
 
333
                jdns_string_t *str = _make_printable_cstr((const char *)rr->owner);
 
334
                buf = (unsigned char *)malloc(str->size + 3); // " [%s]"
 
335
                buf[0] = ' ';
 
336
                buf[1] = '[';
 
337
                memcpy(buf + 2, str->data, str->size);
 
338
                buf[str->size + 2] = ']';
 
339
                jdns_string_set(ownerstr, buf, str->size + 3);
 
340
                jdns_string_delete(str);
 
341
                free(buf);
 
342
        }
 
343
        else
 
344
                jdns_string_set_cstr(ownerstr, "");
 
345
 
 
346
        switch(rr->type)
 
347
        {
 
348
                case JDNS_RTYPE_A:
 
349
                {
 
350
                        _debug_line(s, "    A: [%s] (ttl=%d)%s", rr->data.address->c_str, rr->ttl, ownerstr->data);
 
351
                        break;
 
352
                }
 
353
                case JDNS_RTYPE_AAAA:
 
354
                {
 
355
                        _debug_line(s, "    AAAA: [%s] (ttl=%d)%s", rr->data.address->c_str, rr->ttl, ownerstr->data);
 
356
                        break;
 
357
                }
 
358
                case JDNS_RTYPE_MX:
 
359
                {
 
360
                        jdns_string_t *str = _make_printable_cstr((const char *)rr->data.server->name);
 
361
                        _debug_line(s, "    MX: [%s] priority=%d (ttl=%d)%s", str->data, rr->data.server->priority, rr->ttl, ownerstr->data);
 
362
                        jdns_string_delete(str);
 
363
                        break;
 
364
                }
 
365
                case JDNS_RTYPE_SRV:
 
366
                {
 
367
                        jdns_string_t *str = _make_printable_cstr((const char *)rr->data.server->name);
 
368
                        _debug_line(s, "    SRV: [%s] port=%d priority=%d weight=%d (ttl=%d)%s", str->data, rr->data.server->port, rr->data.server->priority, rr->data.server->weight, rr->ttl, ownerstr->data);
 
369
                        jdns_string_delete(str);
 
370
                        break;
 
371
                }
 
372
                case JDNS_RTYPE_CNAME:
 
373
                {
 
374
                        jdns_string_t *str = _make_printable_cstr((const char *)rr->data.name);
 
375
                        _debug_line(s, "    CNAME: [%s] (ttl=%d)%s", str->data, rr->ttl, ownerstr->data);
 
376
                        jdns_string_delete(str);
 
377
                        break;
 
378
                }
 
379
                case JDNS_RTYPE_PTR:
 
380
                {
 
381
                        jdns_string_t *str = _make_printable_cstr((const char *)rr->data.name);
 
382
                        _debug_line(s, "    PTR: [%s] (ttl=%d)%s", str->data, rr->ttl, ownerstr->data);
 
383
                        jdns_string_delete(str);
 
384
                        break;
 
385
                }
 
386
                case JDNS_RTYPE_TXT:
 
387
                {
 
388
                        _debug_line(s, "    TXT: count=%d (ttl=%d)%s", rr->data.texts->count, rr->ttl, ownerstr->data);
 
389
                        for(n = 0; n < rr->data.texts->count; ++n)
 
390
                        {
 
391
                                jdns_string_t *str, *pstr;
 
392
                                str = rr->data.texts->item[n];
 
393
                                pstr = _make_printable_str(str);
 
394
                                _debug_line(s, "      len=%d [%s]", str->size, pstr->data);
 
395
                                jdns_string_delete(pstr);
 
396
                        }
 
397
                        break;
 
398
                }
 
399
                case JDNS_RTYPE_HINFO:
 
400
                {
 
401
                        jdns_string_t *cpu, *os;
 
402
                        cpu = _make_printable_str(rr->data.hinfo.cpu);
 
403
                        os = _make_printable_str(rr->data.hinfo.os);
 
404
                        _debug_line(s, "    HINFO: [%s] [%s] (ttl=%d)%s", cpu->data, os->data, rr->ttl, ownerstr->data);
 
405
                        jdns_string_delete(cpu);
 
406
                        jdns_string_delete(os);
 
407
                        break;
 
408
                }
 
409
                case JDNS_RTYPE_NS:
 
410
                {
 
411
                        jdns_string_t *str = _make_printable_cstr((const char *)rr->data.name);
 
412
                        _debug_line(s, "    NS: [%s] (ttl=%d)%s", str->data, rr->ttl, ownerstr->data);
 
413
                        jdns_string_delete(str);
 
414
                        break;
 
415
                }
 
416
                default:
 
417
                {
 
418
                        _debug_line(s, "    Unknown (%d): %d bytes (ttl=%d)%s", rr->type, rr->rdlength, rr->ttl, ownerstr->data);
 
419
                        break;
 
420
                }
 
421
        }
 
422
        jdns_string_delete(ownerstr);
 
423
}
 
424
 
 
425
static void _print_records(jdns_session_t *s, const jdns_response_t *r, const unsigned char *owner)
 
426
{
 
427
        int n;
 
428
        _debug_line(s, "Records:");
 
429
        _debug_line(s, "  Answer Records: %d", r->answerCount);
 
430
        for(n = 0; n < r->answerCount; ++n)
 
431
                _print_rr(s, r->answerRecords[n], owner);
 
432
        _debug_line(s, "  Authority Records: %d", r->authorityCount);
 
433
        for(n = 0; n < r->authorityCount; ++n)
 
434
                _print_rr(s, r->authorityRecords[n], owner);
 
435
        _debug_line(s, "  Additional Records: %d", r->additionalCount);
 
436
        for(n = 0; n < r->additionalCount; ++n)
 
437
                _print_rr(s, r->additionalRecords[n], owner);
 
438
}
 
439
 
 
440
static int _min(int a, int b)
 
441
{
 
442
        return (a < b) ? a : b;
 
443
}
 
444
 
 
445
//----------------------------------------------------------------------------
 
446
// jdns_event
 
447
//----------------------------------------------------------------------------
 
448
jdns_event_t *jdns_event_new()
 
449
{
 
450
        jdns_event_t *e = alloc_type(jdns_event_t);
 
451
        e->response = 0;
 
452
        return e;
 
453
}
 
454
 
 
455
void jdns_event_delete(jdns_event_t *e)
 
456
{
 
457
        if(!e)
 
458
                return;
 
459
        jdns_response_delete(e->response);
 
460
        jdns_free(e);
 
461
}
 
462
 
 
463
//----------------------------------------------------------------------------
 
464
// jdns - internal types
 
465
//----------------------------------------------------------------------------
 
466
typedef struct list_item
 
467
{
 
468
        void (*dtor)(void *);
 
469
} list_item_t;
 
470
 
 
471
typedef struct list
 
472
{
 
473
        int count;
 
474
        list_item_t **item;
 
475
} list_t;
 
476
 
 
477
list_t *list_new()
 
478
{
 
479
        list_t *l = alloc_type(list_t);
 
480
        l->count = 0;
 
481
        l->item = 0;
 
482
        return l;
 
483
}
 
484
 
 
485
void list_delete(list_t *l)
 
486
{
 
487
        int n;
 
488
        if(!l)
 
489
                return;
 
490
        for(n = 0; n < l->count; ++n)
 
491
                l->item[n]->dtor(l->item[n]);
 
492
        if(l->item)
 
493
                free(l->item);
 
494
        jdns_free(l);
 
495
}
 
496
 
 
497
void list_insert(list_t *l, void *item, int pos)
 
498
{
 
499
        list_item_t *i = (list_item_t *)item;
 
500
        if(!l->item)
 
501
                l->item = (list_item_t **)malloc(sizeof(list_item_t *));
 
502
        else
 
503
                l->item = (list_item_t **)realloc(l->item, sizeof(list_item_t *) * (l->count + 1));
 
504
        if(pos != -1)
 
505
                memmove(l->item + pos + 1, l->item + pos, (l->count - pos) * sizeof(list_item_t *));
 
506
        else
 
507
                pos = l->count;
 
508
        l->item[pos] = i;
 
509
        ++l->count;
 
510
}
 
511
 
 
512
void list_remove(list_t *l, void *item)
 
513
{
 
514
        int n;
 
515
        list_item_t *i = (list_item_t *)item;
 
516
        int pos = -1;
 
517
        for(n = 0; n < l->count; ++n)
 
518
        {
 
519
                if(l->item[n] == i)
 
520
                {
 
521
                        pos = n;
 
522
                        break;
 
523
                }
 
524
        }
 
525
        if(pos == -1)
 
526
                return;
 
527
 
 
528
        i->dtor(i);
 
529
        if(l->count > 1)
 
530
        {
 
531
                memmove(l->item + pos, l->item + pos + 1, (l->count - pos - 1) * sizeof(list_item_t *));
 
532
                --l->count;
 
533
        }
 
534
        else
 
535
        {
 
536
                free(l->item);
 
537
                l->item = 0;
 
538
                l->count = 0;
 
539
        }
 
540
}
 
541
 
 
542
typedef struct name_server
 
543
{
 
544
        void (*dtor)(struct name_server *);
 
545
        int id;
 
546
        jdns_address_t *address;
 
547
        int port;
 
548
} name_server_t;
 
549
 
 
550
void name_server_delete(name_server_t *ns);
 
551
 
 
552
name_server_t *name_server_new()
 
553
{
 
554
        name_server_t *ns = alloc_type(name_server_t);
 
555
        ns->dtor = name_server_delete;
 
556
        ns->address = 0;
 
557
        return ns;
 
558
}
 
559
 
 
560
void name_server_delete(name_server_t *ns)
 
561
{
 
562
        if(!ns)
 
563
                return;
 
564
        jdns_address_delete(ns->address);
 
565
        jdns_free(ns);
 
566
}
 
567
 
 
568
int _intarray_indexOf(int *array, int count, int val)
 
569
{
 
570
        int n;
 
571
        for(n = 0; n < count; ++n)
 
572
        {
 
573
                if(array[n] == val)
 
574
                        return n;
 
575
        }
 
576
        return -1;
 
577
}
 
578
 
 
579
int _intarray_add(int **array, int *count, int val)
 
580
{
 
581
        int *p;
 
582
        if(!*array)
 
583
                p = (int *)malloc(sizeof(int));
 
584
        else
 
585
                p = (int *)realloc(*array, sizeof(int) * (*count + 1));
 
586
        if(!p)
 
587
                return 0;
 
588
        *array = p;
 
589
        (*array)[*count] = val;
 
590
        ++(*count);
 
591
        return 1;
 
592
}
 
593
 
 
594
void _intarray_remove(int **array, int *count, int pos)
 
595
{
 
596
        int *p;
 
597
        if(*count > 1)
 
598
        {
 
599
                memmove(*array + pos, *array + pos + 1, (*count - pos - 1) * sizeof(int));
 
600
                --count;
 
601
                p = (int *)realloc(*array, sizeof(int) * (*count));
 
602
                if(p)
 
603
                        *array = p;
 
604
        }
 
605
        else
 
606
        {
 
607
                free(*array);
 
608
                *array = 0;
 
609
                *count = 0;
 
610
        }
 
611
}
 
612
 
 
613
typedef struct query
 
614
{
 
615
        void (*dtor)(struct query *);
 
616
 
 
617
        int id;
 
618
 
 
619
        // user request ids
 
620
        int req_ids_count;
 
621
        int *req_ids;
 
622
 
 
623
        // packet id
 
624
        int dns_id;
 
625
 
 
626
        // what we are looking up
 
627
        unsigned char *qname;
 
628
        int qtype;
 
629
 
 
630
        // how many transmission attempts we have done.  note this
 
631
        //  is not actually how many packets have been sent, since
 
632
        //  it is possible for the first transmission to send many
 
633
        //  at once.  this variable lets us decide when to give up.
 
634
        //  (idea taken from qdns).
 
635
        // set to -1 to deactivate (stop sending packets)
 
636
        int step;
 
637
 
 
638
        // which nameservers we've tried (stored as a list of ids)
 
639
        int servers_tried_count;
 
640
        int *servers_tried;
 
641
 
 
642
        // which servers we shouldn't try again
 
643
        int servers_failed_count;
 
644
        int *servers_failed;
 
645
 
 
646
        // flag to indicate whether or not we've tried all available
 
647
        //  nameservers already.  this means that all future
 
648
        //  transmissions are likely repeats, and should be slowed
 
649
        //  down.
 
650
        int retrying;
 
651
 
 
652
        // holds a timeout for the next step (time_start == -1 means no timer)
 
653
        int time_start;
 
654
        int time_next;
 
655
 
 
656
        // whether or not to look in the cache for this query
 
657
        int trycache;
 
658
 
 
659
        // cname subquerying.  only cname_parent or cname_child may be set,
 
660
        //  never both.
 
661
        int cname_chain_count;
 
662
        struct query *cname_parent;
 
663
        struct query *cname_child;
 
664
 
 
665
        // accumulates known multicast records to prevent duplicates
 
666
        jdns_response_t *mul_known;
 
667
} query_t;
 
668
 
 
669
void query_delete(query_t *q);
 
670
 
 
671
query_t *query_new()
 
672
{
 
673
        query_t *q = alloc_type(query_t);
 
674
        q->dtor = query_delete;
 
675
        q->req_ids_count = 0;
 
676
        q->req_ids = 0;
 
677
        q->qname = 0;
 
678
        q->servers_tried_count = 0;
 
679
        q->servers_tried = 0;
 
680
        q->servers_failed_count = 0;
 
681
        q->servers_failed = 0;
 
682
        q->cname_chain_count = 0;
 
683
        q->cname_parent = 0;
 
684
        q->cname_child = 0;
 
685
        q->mul_known = 0;
 
686
        return q;
 
687
}
 
688
 
 
689
void query_delete(query_t *q)
 
690
{
 
691
        if(!q)
 
692
                return;
 
693
        if(q->req_ids)
 
694
                free(q->req_ids);
 
695
        if(q->qname)
 
696
                free(q->qname);
 
697
        if(q->servers_tried)
 
698
                free(q->servers_tried);
 
699
        if(q->servers_failed)
 
700
                free(q->servers_failed);
 
701
        jdns_response_delete(q->mul_known);
 
702
        jdns_free(q);
 
703
}
 
704
 
 
705
int query_have_req_id(const query_t *q, int req_id)
 
706
{
 
707
        if(_intarray_indexOf(q->req_ids, q->req_ids_count, req_id) != -1)
 
708
                return 1;
 
709
        return 0;
 
710
}
 
711
 
 
712
void query_add_req_id(query_t *q, int req_id)
 
713
{
 
714
        _intarray_add(&q->req_ids, &q->req_ids_count, req_id);
 
715
}
 
716
 
 
717
void query_remove_req_id(query_t *q, int req_id)
 
718
{
 
719
        int pos;
 
720
 
 
721
        pos = _intarray_indexOf(q->req_ids, q->req_ids_count, req_id);
 
722
        if(pos != -1)
 
723
                _intarray_remove(&q->req_ids, &q->req_ids_count, pos);
 
724
}
 
725
 
 
726
int query_server_tried(const query_t *q, int ns_id)
 
727
{
 
728
        if(_intarray_indexOf(q->servers_tried, q->servers_tried_count, ns_id) != -1)
 
729
                return 1;
 
730
        return 0;
 
731
}
 
732
 
 
733
void query_add_server_tried(query_t *q, int ns_id)
 
734
{
 
735
        _intarray_add(&q->servers_tried, &q->servers_tried_count, ns_id);
 
736
}
 
737
 
 
738
void query_clear_servers_tried(query_t *q)
 
739
{
 
740
        if(q->servers_tried)
 
741
                free(q->servers_tried);
 
742
        q->servers_tried_count = 0;
 
743
        q->servers_tried = 0;
 
744
}
 
745
 
 
746
int query_server_failed(const query_t *q, int ns_id)
 
747
{
 
748
        if(_intarray_indexOf(q->servers_failed, q->servers_failed_count, ns_id) != -1)
 
749
                return 1;
 
750
        return 0;
 
751
}
 
752
 
 
753
void query_add_server_failed(query_t *q, int ns_id)
 
754
{
 
755
        _intarray_add(&q->servers_failed, &q->servers_failed_count, ns_id);
 
756
}
 
757
 
 
758
void query_name_server_gone(query_t *q, int ns_id)
 
759
{
 
760
        int pos;
 
761
 
 
762
        pos = _intarray_indexOf(q->servers_tried, q->servers_tried_count, ns_id);
 
763
        if(pos != -1)
 
764
                _intarray_remove(&q->servers_tried, &q->servers_tried_count, pos);
 
765
 
 
766
        pos = _intarray_indexOf(q->servers_failed, q->servers_failed_count, ns_id);
 
767
        if(pos != -1)
 
768
                _intarray_remove(&q->servers_failed, &q->servers_failed_count, pos);
 
769
}
 
770
 
 
771
typedef struct datagram
 
772
{
 
773
        void (*dtor)(struct datagram *);
 
774
        int handle;
 
775
        jdns_address_t *dest_address;
 
776
        int dest_port;
 
777
        unsigned char *data;
 
778
        int size;
 
779
 
 
780
        // query association
 
781
        query_t *query;
 
782
        int query_send_type; // 0 == normal, 1 == first step send-all
 
783
 
 
784
        // name server association
 
785
        int ns_id;
 
786
} datagram_t;
 
787
 
 
788
void datagram_delete(datagram_t *a);
 
789
 
 
790
datagram_t *datagram_new()
 
791
{
 
792
        datagram_t *a = alloc_type(datagram_t);
 
793
        a->dtor = datagram_delete;
 
794
        a->dest_address = 0;
 
795
        a->data = 0;
 
796
        a->size = 0;
 
797
        a->query = 0;
 
798
        return a;
 
799
}
 
800
 
 
801
void datagram_delete(datagram_t *a)
 
802
{
 
803
        if(!a)
 
804
                return;
 
805
        jdns_address_delete(a->dest_address);
 
806
        if(a->data)
 
807
                free(a->data);
 
808
        jdns_free(a);
 
809
}
 
810
 
 
811
typedef struct cache_item
 
812
{
 
813
        void (*dtor)(struct cache_item *);
 
814
        unsigned char *qname;
 
815
        int qtype;
 
816
        int time_start;
 
817
        int ttl;
 
818
        jdns_rr_t *record; // if zero, nxdomain is assumed
 
819
} cache_item_t;
 
820
 
 
821
void cache_item_delete(cache_item_t *e);
 
822
 
 
823
cache_item_t *cache_item_new()
 
824
{
 
825
        cache_item_t *a = alloc_type(cache_item_t);
 
826
        a->dtor = cache_item_delete;
 
827
        a->qname = 0;
 
828
        a->record = 0;
 
829
        return a;
 
830
}
 
831
 
 
832
void cache_item_delete(cache_item_t *a)
 
833
{
 
834
        if(!a)
 
835
                return;
 
836
        if(a->qname)
 
837
                free(a->qname);
 
838
        jdns_rr_delete(a->record);
 
839
        jdns_free(a);
 
840
}
 
841
 
 
842
typedef struct event
 
843
{
 
844
        void (*dtor)(struct event *);
 
845
        jdns_event_t *event;
 
846
} event_t;
 
847
 
 
848
void event_delete(event_t *e);
 
849
 
 
850
event_t *event_new()
 
851
{
 
852
        event_t *e = alloc_type(event_t);
 
853
        e->dtor = event_delete;
 
854
        e->event = 0;
 
855
        return e;
 
856
}
 
857
 
 
858
void event_delete(event_t *e)
 
859
{
 
860
        if(!e)
 
861
                return;
 
862
        jdns_event_delete(e->event);
 
863
        jdns_free(e);
 
864
}
 
865
 
 
866
typedef struct published_item
 
867
{
 
868
        void (*dtor)(struct published_item *);
 
869
        int id;
 
870
        int mode;
 
871
        unsigned char *qname;
 
872
        int qtype;
 
873
        mdnsdr rec;
 
874
        jdns_rr_t *rr;
 
875
} published_item_t;
 
876
 
 
877
void published_item_delete(published_item_t *a);
 
878
 
 
879
published_item_t *published_item_new()
 
880
{
 
881
        published_item_t *a = alloc_type(published_item_t);
 
882
        a->dtor = published_item_delete;
 
883
        a->qname = 0;
 
884
        a->rec = 0;
 
885
        a->rr = 0;
 
886
        return a;
 
887
}
 
888
 
 
889
void published_item_delete(published_item_t *a)
 
890
{
 
891
        if(!a)
 
892
                return;
 
893
        if(a->qname)
 
894
                free(a->qname);
 
895
        jdns_rr_delete(a->rr);
 
896
        jdns_free(a);
 
897
}
 
898
 
 
899
//----------------------------------------------------------------------------
 
900
// jdns
 
901
//----------------------------------------------------------------------------
 
902
struct jdns_session
 
903
{
 
904
        jdns_callbacks_t cb;
 
905
        int mode;
 
906
        int shutdown;
 
907
        int next_qid;
 
908
        int next_req_id;
 
909
        int next_dns_id;
 
910
        int last_time;
 
911
        int next_timer;
 
912
        int next_name_server_id;
 
913
        int handle;
 
914
        int handle_readable, handle_writable;
 
915
        int port;
 
916
        list_t *name_servers;
 
917
        list_t *queries;
 
918
        list_t *outgoing;
 
919
        list_t *events;
 
920
        list_t *cache;
 
921
 
 
922
        // mdns
 
923
        mdnsd mdns;
 
924
        list_t *published;
 
925
        jdns_address_t *maddr;
 
926
};
 
927
 
 
928
jdns_session_t *jdns_session_new(jdns_callbacks_t *callbacks)
 
929
{
 
930
        jdns_session_t *s = alloc_type(jdns_session_t);
 
931
        memcpy(&s->cb, callbacks, sizeof(jdns_callbacks_t));
 
932
        s->shutdown = 0;
 
933
        s->next_qid = 0;
 
934
        s->next_req_id = 1;
 
935
        s->next_dns_id = s->cb.rand_int(s, s->cb.app);
 
936
        s->last_time = 0;
 
937
        s->next_timer = 0;
 
938
        s->next_name_server_id = 0;
 
939
        s->handle = 0;
 
940
        s->handle_readable = 0;
 
941
        s->handle_writable = 1;
 
942
        s->port = 0;
 
943
        s->name_servers = list_new();
 
944
        s->queries = list_new();
 
945
        s->outgoing = list_new();
 
946
        s->events = list_new();
 
947
        s->cache = list_new();
 
948
 
 
949
        s->mdns = 0;
 
950
        s->published = list_new();
 
951
        s->maddr = 0;
 
952
 
 
953
        return s;
 
954
}
 
955
 
 
956
void jdns_session_delete(jdns_session_t *s)
 
957
{
 
958
        if(!s)
 
959
                return;
 
960
        if(s->handle)
 
961
                s->cb.udp_unbind(s, s->cb.app, s->handle);
 
962
        list_delete(s->name_servers);
 
963
        list_delete(s->queries);
 
964
        list_delete(s->outgoing);
 
965
        list_delete(s->events);
 
966
        list_delete(s->cache);
 
967
 
 
968
        if(s->mdns)
 
969
                mdnsd_free(s->mdns);
 
970
 
 
971
        list_delete(s->published);
 
972
        jdns_address_delete(s->maddr);
 
973
 
 
974
        free(s);
 
975
}
 
976
 
 
977
// declare some internal functions
 
978
static int _callback_time_now(mdnsd d, void *arg);
 
979
static int _callback_rand_int(mdnsd d, void *arg);
 
980
 
 
981
static void _append_event(jdns_session_t *s, jdns_event_t *event);
 
982
static void _remove_name_server_datagrams(jdns_session_t *s, int ns_id);
 
983
static void _remove_query_datagrams(jdns_session_t *s, const query_t *q);
 
984
 
 
985
static int _unicast_query(jdns_session_t *s, const unsigned char *name, int qtype);
 
986
static void _unicast_cancel(jdns_session_t *s, query_t *q);
 
987
static int _multicast_query(jdns_session_t *s, const unsigned char *name, int qtype);
 
988
static void _multicast_cancel(jdns_session_t *s, int req_id);
 
989
static int _multicast_publish(jdns_session_t *s, int mode, const jdns_rr_t *rr);
 
990
static void _multicast_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rr);
 
991
static void _multicast_cancel_publish(jdns_session_t *s, int id);
 
992
static void _multicast_flush(jdns_session_t *s);
 
993
 
 
994
static int jdns_step_unicast(jdns_session_t *s, int now);
 
995
static int jdns_step_multicast(jdns_session_t *s, int now);
 
996
 
 
997
static int _int_wrap(int *src, int start)
 
998
{
 
999
        int x;
 
1000
        x = (*src)++;
 
1001
        if(*src < start)
 
1002
                *src = start;
 
1003
        return x;
 
1004
}
 
1005
 
 
1006
// starts at 0
 
1007
static int get_next_qid(jdns_session_t *s)
 
1008
{
 
1009
        int n, id;
 
1010
        id = -1;
 
1011
        while(id == -1)
 
1012
        {
 
1013
                id = _int_wrap(&s->next_qid, 0);
 
1014
                for(n = 0; n < s->queries->count; ++n)
 
1015
                {
 
1016
                        if(((query_t *)s->queries->item[n])->id == id)
 
1017
                        {
 
1018
                                id = -1;
 
1019
                                break;
 
1020
                        }
 
1021
                }
 
1022
        }
 
1023
        return id;
 
1024
}
 
1025
 
 
1026
// starts at 1
 
1027
static int get_next_req_id(jdns_session_t *s)
 
1028
{
 
1029
        int n, k, id;
 
1030
        id = -1;
 
1031
        while(id == -1)
 
1032
        {
 
1033
                id = _int_wrap(&s->next_req_id, 1);
 
1034
 
 
1035
                // no query using this?
 
1036
                for(n = 0; n < s->queries->count; ++n)
 
1037
                {
 
1038
                        query_t *q = (query_t *)s->queries->item[n];
 
1039
                        for(k = 0; k < q->req_ids_count; ++k)
 
1040
                        {
 
1041
                                if(q->req_ids[k] == id)
 
1042
                                {
 
1043
                                        id = -1;
 
1044
                                        break;
 
1045
                                }
 
1046
                        }
 
1047
                        if(id == -1)
 
1048
                                break;
 
1049
                }
 
1050
 
 
1051
                // no publish using this?
 
1052
                for(n = 0; n < s->published->count; ++n)
 
1053
                {
 
1054
                        if(((published_item_t *)s->published->item[n])->id == id)
 
1055
                        {
 
1056
                                id = -1;
 
1057
                                break;
 
1058
                        }
 
1059
                }
 
1060
        }
 
1061
        return id;
 
1062
}
 
1063
 
 
1064
// starts at random, must fit in 16 bits
 
1065
static int get_next_dns_id(jdns_session_t *s)
 
1066
{
 
1067
        return (s->next_dns_id++ & 0xffff);
 
1068
}
 
1069
 
 
1070
// starts at 0
 
1071
static int get_next_name_server_id(jdns_session_t *s)
 
1072
{
 
1073
        int n, id;
 
1074
        id = -1;
 
1075
        while(id == -1)
 
1076
        {
 
1077
                id = _int_wrap(&s->next_name_server_id, 0);
 
1078
                for(n = 0; n < s->name_servers->count; ++n)
 
1079
                {
 
1080
                        if(((name_server_t *)s->name_servers->item[n])->id == id)
 
1081
                        {
 
1082
                                id = -1;
 
1083
                                break;
 
1084
                        }
 
1085
                }
 
1086
        }
 
1087
        return id;
 
1088
}
 
1089
 
 
1090
int jdns_init_unicast(jdns_session_t *s, const jdns_address_t *addr, int port)
 
1091
{
 
1092
        int ret;
 
1093
        s->mode = 0;
 
1094
        ret = s->cb.udp_bind(s, s->cb.app, addr, port, 0);
 
1095
        if(ret <= 0)
 
1096
                return 0;
 
1097
        s->handle = ret;
 
1098
        s->port = port;
 
1099
        return 1;
 
1100
}
 
1101
 
 
1102
int jdns_init_multicast(jdns_session_t *s, const jdns_address_t *addr, int port, const jdns_address_t *maddr)
 
1103
{
 
1104
        int ret;
 
1105
        s->mode = 1;
 
1106
        ret = s->cb.udp_bind(s, s->cb.app, addr, port, maddr);
 
1107
        if(ret <= 0)
 
1108
                return 0;
 
1109
        s->handle = ret;
 
1110
        s->port = port;
 
1111
        s->maddr = jdns_address_copy(maddr);
 
1112
 
 
1113
        // class 1.  note: frame size is ignored by the jdns version of mdnsd
 
1114
        s->mdns = mdnsd_new(0x0001, 1000, s->port, _callback_time_now, _callback_rand_int, s);
 
1115
        return 1;
 
1116
}
 
1117
 
 
1118
void jdns_shutdown(jdns_session_t *s)
 
1119
{
 
1120
        if(s->shutdown == 0)
 
1121
                s->shutdown = 1; // request shutdown
 
1122
}
 
1123
 
 
1124
void jdns_set_nameservers(jdns_session_t *s, const jdns_nameserverlist_t *nslist)
 
1125
{
 
1126
        int n, k;
 
1127
 
 
1128
        // removed?
 
1129
        for(k = 0; k < s->name_servers->count; ++k)
 
1130
        {
 
1131
                name_server_t *ns = (name_server_t *)(s->name_servers->item[k]);
 
1132
                int found = 0;
 
1133
                for(n = 0; n < nslist->count; ++n)
 
1134
                {
 
1135
                        jdns_nameserver_t *i = (jdns_nameserver_t *)nslist->item[n];
 
1136
                        if(jdns_address_cmp(ns->address, i->address) && ns->port == i->port)
 
1137
                        {
 
1138
                                found = 1;
 
1139
                                break;
 
1140
                        }
 
1141
                }
 
1142
                if(!found)
 
1143
                {
 
1144
                        int i;
 
1145
                        int ns_id;
 
1146
 
 
1147
                        // remove any pending packets to this nameserver
 
1148
                        _remove_name_server_datagrams(s, ns->id);
 
1149
 
 
1150
                        _debug_line(s, "ns [%s:%d] (id=%d) removed", ns->address->c_str, ns->port, ns->id);
 
1151
                        ns_id = ns->id;
 
1152
                        list_remove(s->name_servers, ns);
 
1153
                        --k; // adjust position
 
1154
                        for(i = 0; i < s->queries->count; ++i)
 
1155
                                query_name_server_gone((query_t *)s->queries->item[i], ns_id);
 
1156
                }
 
1157
        }
 
1158
 
 
1159
        // added?
 
1160
        for(n = 0; n < nslist->count; ++n)
 
1161
        {
 
1162
                name_server_t *ns;
 
1163
                jdns_nameserver_t *i;
 
1164
                int found;
 
1165
 
 
1166
                i = (jdns_nameserver_t *)nslist->item[n];
 
1167
                found = 0;
 
1168
                for(k = 0; k < s->name_servers->count; ++k)
 
1169
                {
 
1170
                        ns = (name_server_t *)(s->name_servers->item[k]);
 
1171
                        if(jdns_address_cmp(ns->address, i->address) && ns->port == i->port)
 
1172
                        {
 
1173
                                found = 1;
 
1174
                                break;
 
1175
                        }
 
1176
                }
 
1177
                if(found)
 
1178
                {
 
1179
                        _debug_line(s, "ns [%s:%d] (id=%d) still present", ns->address->c_str, ns->port, ns->id);
 
1180
                }
 
1181
                else
 
1182
                {
 
1183
                        ns = name_server_new();
 
1184
                        ns->id = get_next_name_server_id(s);
 
1185
                        ns->address = jdns_address_copy(i->address);
 
1186
                        ns->port = i->port;
 
1187
                        list_insert(s->name_servers, ns, -1);
 
1188
                        _debug_line(s, "ns [%s:%d] (id=%d) added", ns->address->c_str, ns->port, ns->id);
 
1189
                }
 
1190
        }
 
1191
 
 
1192
        // no nameservers?
 
1193
        if(nslist->count == 0)
 
1194
        {
 
1195
                _debug_line(s, "nameserver count is zero, invalidating any queries");
 
1196
 
 
1197
                // invalidate all of the queries!
 
1198
                for(n = 0; n < s->queries->count; ++n)
 
1199
                {
 
1200
                        query_t *q = (query_t *)s->queries->item[n];
 
1201
 
 
1202
                        // report event to any requests listening
 
1203
                        for(k = 0; k < q->req_ids_count; ++k)
 
1204
                        {
 
1205
                                jdns_event_t *event = jdns_event_new();
 
1206
                                event->type = JDNS_EVENT_RESPONSE;
 
1207
                                event->id = q->req_ids[k];
 
1208
                                event->status = JDNS_STATUS_TIMEOUT;
 
1209
                                _append_event(s, event);
 
1210
                        }
 
1211
 
 
1212
                        // this line is probably redundant, but just for
 
1213
                        //  consistency we'll do it...
 
1214
                        _remove_query_datagrams(s, q);
 
1215
 
 
1216
                        list_remove(s->queries, q);
 
1217
                        --n; // adjust position
 
1218
                }
 
1219
        }
 
1220
}
 
1221
 
 
1222
void jdns_probe(jdns_session_t *s)
 
1223
{
 
1224
        if(s->mode != 1)
 
1225
                return;
 
1226
 
 
1227
        _multicast_flush(s);
 
1228
}
 
1229
 
 
1230
int jdns_query(jdns_session_t *s, const unsigned char *name, int rtype)
 
1231
{
 
1232
        if(s->mode == 0)
 
1233
                return _unicast_query(s, name, rtype);
 
1234
        else
 
1235
                return _multicast_query(s, name, rtype);
 
1236
}
 
1237
 
 
1238
void jdns_cancel_query(jdns_session_t *s, int id)
 
1239
{
 
1240
        int n;
 
1241
 
 
1242
        // multicast
 
1243
        if(s->mode == 1)
 
1244
        {
 
1245
                _multicast_cancel(s, id);
 
1246
                return;
 
1247
        }
 
1248
 
 
1249
        // unicast
 
1250
        for(n = 0; n < s->queries->count; ++n)
 
1251
        {
 
1252
                query_t *q = (query_t *)s->queries->item[n];
 
1253
                if(query_have_req_id(q, id))
 
1254
                {
 
1255
                        query_remove_req_id(q, id);
 
1256
 
 
1257
                        // note: calling _cancel_query might remove an item
 
1258
                        //  from s->queries, thereby screwing up our iterator
 
1259
                        //  position, but that's ok because we just break
 
1260
                        //  anyway.
 
1261
 
 
1262
                        // if no one else is depending on this request, then take action
 
1263
                        if(q->req_ids_count == 0 && !q->cname_parent)
 
1264
                        {
 
1265
                                // remove a possible cname child
 
1266
                                if(q->cname_child && q->cname_child->req_ids_count == 0)
 
1267
                                {
 
1268
                                        q->cname_child->cname_parent = 0;
 
1269
                                        _unicast_cancel(s, q->cname_child);
 
1270
                                        q->cname_child = 0;
 
1271
                                }
 
1272
 
 
1273
                                _unicast_cancel(s, q);
 
1274
                        }
 
1275
                        break;
 
1276
                }
 
1277
        }
 
1278
}
 
1279
 
 
1280
int jdns_publish(jdns_session_t *s, int mode, const jdns_rr_t *rr)
 
1281
{
 
1282
        return _multicast_publish(s, mode, rr);
 
1283
}
 
1284
 
 
1285
void jdns_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rr)
 
1286
{
 
1287
        _multicast_update_publish(s, id, rr);
 
1288
}
 
1289
 
 
1290
void jdns_cancel_publish(jdns_session_t *s, int id)
 
1291
{
 
1292
        _multicast_cancel_publish(s, id);
 
1293
}
 
1294
 
 
1295
int jdns_step(jdns_session_t *s)
 
1296
{
 
1297
        int now, passed;
 
1298
        int ret;
 
1299
 
 
1300
        // session is shut down
 
1301
        if(s->shutdown == 2)
 
1302
                return 0;
 
1303
 
 
1304
        now = s->cb.time_now(s, s->cb.app);
 
1305
        passed = now - s->last_time;
 
1306
 
 
1307
        _debug_line(s, "passed: %d", passed);
 
1308
 
 
1309
        if(s->mode == 0)
 
1310
                ret = jdns_step_unicast(s, now);
 
1311
        else
 
1312
                ret = jdns_step_multicast(s, now);
 
1313
 
 
1314
        s->last_time = now;
 
1315
        return ret;
 
1316
}
 
1317
 
 
1318
int jdns_next_timer(jdns_session_t *s)
 
1319
{
 
1320
        return s->next_timer;
 
1321
}
 
1322
 
 
1323
void jdns_set_handle_readable(jdns_session_t *s, int handle)
 
1324
{
 
1325
        (void)handle;
 
1326
        s->handle_readable = 1;
 
1327
}
 
1328
 
 
1329
void jdns_set_handle_writable(jdns_session_t *s, int handle)
 
1330
{
 
1331
        (void)handle;
 
1332
        s->handle_writable = 1;
 
1333
}
 
1334
 
 
1335
jdns_event_t *jdns_next_event(jdns_session_t *s)
 
1336
{
 
1337
        jdns_event_t *event = 0;
 
1338
        if(s->events->count > 0)
 
1339
        {
 
1340
                event_t *e = (event_t *)s->events->item[0];
 
1341
                event = e->event;
 
1342
                e->event = 0;
 
1343
                list_remove(s->events, e);
 
1344
        }
 
1345
        return event;
 
1346
}
 
1347
 
 
1348
//----------------------------------------------------------------------------
 
1349
// jdns - internal functions
 
1350
//----------------------------------------------------------------------------
 
1351
 
 
1352
// we don't have vsnprintf on windows, so don't pass anything enormous to
 
1353
//   this function.  the plan is that no line should exceed 1000 bytes,
 
1354
//   although _print_rr() might get close.  a 2048 byte buffer should be
 
1355
//   plenty then.
 
1356
void _debug_line(jdns_session_t *s, const char *format, ...)
 
1357
{
 
1358
        char *buf = (char *)malloc(2048);
 
1359
        va_list ap;
 
1360
        va_start(ap, format);
 
1361
        vsprintf(buf, format, ap);
 
1362
        va_end(ap);
 
1363
        s->cb.debug_line(s, s->cb.app, buf);
 
1364
        free(buf);
 
1365
}
 
1366
 
 
1367
int _callback_time_now(mdnsd d, void *arg)
 
1368
{
 
1369
        jdns_session_t *s = (jdns_session_t *)arg;
 
1370
        (void)d;
 
1371
        // offset the time, mdnsd doesn't like starting at 0
 
1372
        return s->cb.time_now(s, s->cb.app) + 120 * 1000;
 
1373
}
 
1374
 
 
1375
int _callback_rand_int(mdnsd d, void *arg)
 
1376
{
 
1377
        jdns_session_t *s = (jdns_session_t *)arg;
 
1378
        (void)d;
 
1379
        return s->cb.rand_int(s, s->cb.app);
 
1380
}
 
1381
 
 
1382
void _append_event(jdns_session_t *s, jdns_event_t *event)
 
1383
{
 
1384
        event_t *e = event_new();
 
1385
        e->event = event;
 
1386
        list_insert(s->events, e, -1);
 
1387
}
 
1388
 
 
1389
void _remove_name_server_datagrams(jdns_session_t *s, int ns_id)
 
1390
{
 
1391
        int n;
 
1392
        for(n = 0; n < s->outgoing->count; ++n)
 
1393
        {
 
1394
                datagram_t *a = (datagram_t *)s->outgoing->item[n];
 
1395
                if(a->ns_id == ns_id)
 
1396
                {
 
1397
                        list_remove(s->outgoing, a);
 
1398
                        --n; // adjust position
 
1399
                }
 
1400
        }
 
1401
}
 
1402
 
 
1403
void _remove_query_datagrams(jdns_session_t *s, const query_t *q)
 
1404
{
 
1405
        int n;
 
1406
        for(n = 0; n < s->outgoing->count; ++n)
 
1407
        {
 
1408
                datagram_t *a = (datagram_t *)s->outgoing->item[n];
 
1409
                if(a->query == q)
 
1410
                {
 
1411
                        list_remove(s->outgoing, a);
 
1412
                        --n; // adjust position
 
1413
                }
 
1414
        }
 
1415
}
 
1416
 
 
1417
void _process_message(jdns_session_t *s, jdns_packet_t *p, int now, query_t *q, name_server_t *ns);
 
1418
 
 
1419
// return 1 if 'q' should be deleted, 0 if not
 
1420
int _process_response(jdns_session_t *s, jdns_response_t *r, int nxdomain, query_t *q);
 
1421
 
 
1422
jdns_response_t *_cache_get_response(jdns_session_t *s, const unsigned char *qname, int qtype, int *_lowest_timeleft)
 
1423
{
 
1424
        int n;
 
1425
        int lowest_timeleft = -1;
 
1426
        int now = s->cb.time_now(s, s->cb.app);
 
1427
        jdns_response_t *r = 0;
 
1428
        for(n = 0; n < s->cache->count; ++n)
 
1429
        {
 
1430
                cache_item_t *i = (cache_item_t *)s->cache->item[n];
 
1431
                if(jdns_domain_cmp(i->qname, qname) && i->qtype == qtype)
 
1432
                {
 
1433
                        int passed, timeleft;
 
1434
 
 
1435
                        if(!r)
 
1436
                                r = jdns_response_new();
 
1437
 
 
1438
                        if(i->record)
 
1439
                                jdns_response_append_answer(r, jdns_rr_copy(i->record));
 
1440
 
 
1441
                        passed = now - i->time_start;
 
1442
                        timeleft = (i->ttl * 1000) - passed;
 
1443
                        if(lowest_timeleft == -1 || timeleft < lowest_timeleft)
 
1444
                                lowest_timeleft = timeleft;
 
1445
                }
 
1446
        }
 
1447
        if(_lowest_timeleft)
 
1448
                *_lowest_timeleft = lowest_timeleft;
 
1449
        return r;
 
1450
}
 
1451
 
 
1452
query_t *_get_query(jdns_session_t *s, const unsigned char *qname, int qtype, int unique)
 
1453
{
 
1454
        int n;
 
1455
        query_t *q;
 
1456
        jdns_string_t *str;
 
1457
 
 
1458
        if(!unique)
 
1459
        {
 
1460
                // check for existing queries
 
1461
                for(n = 0; n < s->queries->count; ++n)
 
1462
                {
 
1463
                        q = (query_t *)s->queries->item[n];
 
1464
                        if(jdns_domain_cmp(q->qname, qname) && q->qtype == qtype)
 
1465
                        {
 
1466
                                // if it is inactive, just nuke it
 
1467
                                if(q->step == -1)
 
1468
                                {
 
1469
                                        _remove_query_datagrams(s, q);
 
1470
                                        list_remove(s->queries, q);
 
1471
                                        --n; // adjust position
 
1472
                                }
 
1473
                                // otherwise, latch onto the first one we find
 
1474
                                else
 
1475
                                {
 
1476
                                        str = _make_printable_cstr((const char *)q->qname);
 
1477
                                        _debug_line(s, "[%d] reusing query for: [%s] [%s]", q->id, _qtype2str(qtype), str->data);
 
1478
                                        jdns_string_delete(str);
 
1479
                                        return q;
 
1480
                                }
 
1481
                        }
 
1482
                }
 
1483
        }
 
1484
 
 
1485
        q = query_new();
 
1486
        q->id = get_next_qid(s);
 
1487
        q->qname = _ustrdup(qname);
 
1488
        q->qtype = qtype;
 
1489
        q->step = 0;
 
1490
        q->dns_id = -1;
 
1491
        q->time_start = 0;
 
1492
        q->time_next = 0;
 
1493
        q->trycache = 1;
 
1494
        q->retrying = 0;
 
1495
        list_insert(s->queries, q, -1);
 
1496
 
 
1497
        str = _make_printable_cstr((const char *)q->qname);
 
1498
        _debug_line(s, "[%d] querying: [%s] [%s]", q->id, _qtype2str(qtype), str->data);
 
1499
        jdns_string_delete(str);
 
1500
        return q;
 
1501
}
 
1502
 
 
1503
int _unicast_query(jdns_session_t *s, const unsigned char *name, int qtype)
 
1504
{
 
1505
        unsigned char *qname;
 
1506
        query_t *q;
 
1507
        int req_id;
 
1508
        jdns_string_t *str;
 
1509
 
 
1510
        str = _make_printable_cstr((const char *)name);
 
1511
        _debug_line(s, "query input: [%s]", str->data);
 
1512
        jdns_string_delete(str);
 
1513
 
 
1514
        qname = _fix_input(name);
 
1515
 
 
1516
        q = _get_query(s, qname, qtype, 0);
 
1517
        req_id = get_next_req_id(s);
 
1518
        query_add_req_id(q, req_id);
 
1519
        free(qname);
 
1520
        return req_id;
 
1521
}
 
1522
 
 
1523
void _unicast_cancel(jdns_session_t *s, query_t *q)
 
1524
{
 
1525
        // didn't even do a step yet?  just remove it
 
1526
        if(q->step == 0)
 
1527
        {
 
1528
                _remove_query_datagrams(s, q);
 
1529
                list_remove(s->queries, q);
 
1530
        }
 
1531
        // otherwise, just deactivate
 
1532
        else
 
1533
        {
 
1534
                // deactivate and remain in the background for
 
1535
                //  1 minute.  this will allow us to cache a
 
1536
                //  reply, even if the user is not currently
 
1537
                //  interested.
 
1538
                q->step = -1;
 
1539
                q->time_start = s->cb.time_now(s, s->cb.app);
 
1540
                q->time_next = 60000;
 
1541
        }
 
1542
}
 
1543
 
 
1544
void _queue_packet(jdns_session_t *s, query_t *q, const name_server_t *ns, int recurse, int query_send_type)
 
1545
{
 
1546
        jdns_packet_t *packet;
 
1547
        datagram_t *a;
 
1548
 
 
1549
        packet = jdns_packet_new();
 
1550
        packet->id = q->dns_id;
 
1551
        packet->opts.rd = recurse; // recursion desired
 
1552
        {
 
1553
                jdns_packet_question_t *question = jdns_packet_question_new();
 
1554
                question->qname = jdns_string_new();
 
1555
                jdns_string_set_cstr(question->qname, (const char *)q->qname);
 
1556
                question->qtype = q->qtype;
 
1557
                question->qclass = 0x0001;
 
1558
                jdns_list_insert(packet->questions, question, -1);
 
1559
                jdns_packet_question_delete(question);
 
1560
        }
 
1561
        if(!jdns_packet_export(packet, JDNS_UDP_UNI_OUT_MAX))
 
1562
        {
 
1563
                _debug_line(s, "outgoing packet export error, not sending");
 
1564
                jdns_packet_delete(packet);
 
1565
                return;
 
1566
        }
 
1567
 
 
1568
        a = datagram_new();
 
1569
        a->handle = s->handle;
 
1570
        a->dest_address = jdns_address_copy(ns->address);
 
1571
        a->dest_port = ns->port;
 
1572
        a->data = jdns_copy_array(packet->raw_data, packet->raw_size);
 
1573
        a->size = packet->raw_size;
 
1574
        a->query = q;
 
1575
        a->query_send_type = query_send_type;
 
1576
        a->ns_id = ns->id;
 
1577
 
 
1578
        jdns_packet_delete(packet);
 
1579
 
 
1580
        list_insert(s->outgoing, a, -1);
 
1581
}
 
1582
 
 
1583
// return 1 if packets still need to be written
 
1584
int _unicast_do_writes(jdns_session_t *s, int now);
 
1585
 
 
1586
// return 1 if packets still need to be read
 
1587
int _unicast_do_reads(jdns_session_t *s, int now);
 
1588
 
 
1589
int jdns_step_unicast(jdns_session_t *s, int now)
 
1590
{
 
1591
        int n;
 
1592
        int need_read = 0;
 
1593
        int need_write = 0;
 
1594
        int smallest_time = -1;
 
1595
        int flags;
 
1596
 
 
1597
        if(s->shutdown == 1)
 
1598
        {
 
1599
                jdns_event_t *event = jdns_event_new();
 
1600
                event->type = JDNS_EVENT_SHUTDOWN;
 
1601
                _append_event(s, event);
 
1602
                s->shutdown = 2;
 
1603
                return 0;
 
1604
        }
 
1605
 
 
1606
        // expire cached items
 
1607
        for(n = 0; n < s->cache->count; ++n)
 
1608
        {
 
1609
                cache_item_t *i = (cache_item_t *)s->cache->item[n];
 
1610
                if(now >= i->time_start + (i->ttl * 1000))
 
1611
                {
 
1612
                        jdns_string_t *str = _make_printable_cstr((const char *)i->qname);
 
1613
                        _debug_line(s, "cache exp [%s]", str->data);
 
1614
                        jdns_string_delete(str);
 
1615
                        list_remove(s->cache, i);
 
1616
                        --n; // adjust position
 
1617
                }
 
1618
        }
 
1619
 
 
1620
        need_write = _unicast_do_writes(s, now);
 
1621
        need_read = _unicast_do_reads(s, now);
 
1622
 
 
1623
        // calculate next timer (based on queries and cache)
 
1624
        for(n = 0; n < s->queries->count; ++n)
 
1625
        {
 
1626
                query_t *q = (query_t *)(s->queries->item[n]);
 
1627
                if(q->time_start != -1)
 
1628
                {
 
1629
                        int qpassed = now - q->time_start;
 
1630
                        int timeleft = q->time_next - qpassed;
 
1631
                        if(timeleft < 0)
 
1632
                                timeleft = 0;
 
1633
 
 
1634
                        if(smallest_time == -1 || timeleft < smallest_time)
 
1635
                                smallest_time = timeleft;
 
1636
                }
 
1637
        }
 
1638
        for(n = 0; n < s->cache->count; ++n)
 
1639
        {
 
1640
                cache_item_t *i = (cache_item_t *)(s->cache->item[n]);
 
1641
                int passed = now - i->time_start;
 
1642
                int timeleft = (i->ttl * 1000) - passed;
 
1643
                if(timeleft < 0)
 
1644
                        timeleft = 0;
 
1645
 
 
1646
                if(smallest_time == -1 || timeleft < smallest_time)
 
1647
                        smallest_time = timeleft;
 
1648
        }
 
1649
 
 
1650
        flags = 0;
 
1651
        if(smallest_time != -1)
 
1652
        {
 
1653
                flags |= JDNS_STEP_TIMER;
 
1654
                s->next_timer = smallest_time;
 
1655
 
 
1656
                // offset it a little bit, so that the user doesn't call
 
1657
                //  us too early, resulting in a no-op and another timer
 
1658
                //  of 1 millisecond.
 
1659
                s->next_timer += 2;
 
1660
        }
 
1661
        if(need_read || need_write)
 
1662
                flags |= JDNS_STEP_HANDLE;
 
1663
        return flags;
 
1664
}
 
1665
 
 
1666
int _unicast_do_writes(jdns_session_t *s, int now)
 
1667
{
 
1668
        int need_write = 0;
 
1669
        int n, k;
 
1670
 
 
1671
        for(n = 0; n < s->queries->count; ++n)
 
1672
        {
 
1673
                query_t *q;
 
1674
                int qpassed, timeleft;
 
1675
                int giveup;
 
1676
                name_server_t *ns;
 
1677
                int already_sending;
 
1678
 
 
1679
                q = (query_t *)s->queries->item[n];
 
1680
 
 
1681
                // nothing to do
 
1682
                if(q->time_start == -1)
 
1683
                        continue;
 
1684
 
 
1685
                qpassed = now - q->time_start;
 
1686
                timeleft = q->time_next - qpassed;
 
1687
                if(timeleft < 0)
 
1688
                        timeleft = 0;
 
1689
                _debug_line(s, "[%d] time_start/next=%d/%d (left=%d)", q->id, q->time_start, q->time_next, timeleft);
 
1690
                if(timeleft > 0)
 
1691
                        continue;
 
1692
 
 
1693
                if(q->trycache)
 
1694
                {
 
1695
                        // is it cached?
 
1696
                        int lowest_timeleft;
 
1697
                        int qtype = q->qtype;
 
1698
                        jdns_response_t *r;
 
1699
 
 
1700
                        r = _cache_get_response(s, q->qname, qtype, &lowest_timeleft);
 
1701
 
 
1702
                        // not found?  try cname
 
1703
                        if(!r)
 
1704
                        {
 
1705
                                qtype = JDNS_RTYPE_CNAME;
 
1706
                                r = _cache_get_response(s, q->qname, qtype, &lowest_timeleft);
 
1707
                        }
 
1708
 
 
1709
                        if(r)
 
1710
                        {
 
1711
                                int nxdomain;
 
1712
 
 
1713
                                _debug_line(s, "[%d] using cached answer", q->id);
 
1714
 
 
1715
                                // are any of the records about to expire in 3 minutes?
 
1716
                                //  assume the client is interested in this record and
 
1717
                                //  query it again "in the background"
 
1718
                                if(lowest_timeleft < (3 * 60 * 1000))
 
1719
                                {
 
1720
                                        query_t *new_q;
 
1721
 
 
1722
                                        _debug_line(s, "requerying for cached item about to expire");
 
1723
 
 
1724
                                        new_q = _get_query(s, q->qname, q->qtype, 1);
 
1725
                                        new_q->retrying = 1; // slow it down
 
1726
                                        new_q->trycache = 0; // don't use the cache for this
 
1727
                                }
 
1728
 
 
1729
                                nxdomain = r->answerCount == 0 ? 1 : 0;
 
1730
                                if(_process_response(s, r, nxdomain, q))
 
1731
                                {
 
1732
                                        _remove_query_datagrams(s, q);
 
1733
                                        list_remove(s->queries, q);
 
1734
                                        --n; // adjust position
 
1735
                                }
 
1736
                                continue;
 
1737
                        }
 
1738
                }
 
1739
 
 
1740
                // inactive
 
1741
                if(q->step == -1)
 
1742
                {
 
1743
                        // time up on an inactive query?  remove it
 
1744
                        _debug_line(s, "removing inactive query");
 
1745
                        _remove_query_datagrams(s, q);
 
1746
                        list_remove(s->queries, q);
 
1747
                        --n; // adjust position
 
1748
                        continue;
 
1749
                }
 
1750
 
 
1751
                giveup = 0;
 
1752
 
 
1753
                // too many tries, give up
 
1754
                if(q->step == 8)
 
1755
                        giveup = 1;
 
1756
 
 
1757
                // no nameservers, give up
 
1758
                //  (this would happen if someone removed all nameservers
 
1759
                //   during a query)
 
1760
                if(s->name_servers->count == 0)
 
1761
                        giveup = 1;
 
1762
 
 
1763
                if(giveup)
 
1764
                {
 
1765
                        // report event to any requests listening
 
1766
                        for(k = 0; k < q->req_ids_count; ++k)
 
1767
                        {
 
1768
                                jdns_event_t *event = jdns_event_new();
 
1769
                                event->type = JDNS_EVENT_RESPONSE;
 
1770
                                event->id = q->req_ids[k];
 
1771
                                event->status = JDNS_STATUS_TIMEOUT;
 
1772
                                _append_event(s, event);
 
1773
                        }
 
1774
 
 
1775
                        _remove_query_datagrams(s, q);
 
1776
                        list_remove(s->queries, q);
 
1777
                        --n; // adjust position
 
1778
                        continue;
 
1779
                }
 
1780
 
 
1781
                // assign a packet id if we don't have one yet
 
1782
                if(q->dns_id == -1)
 
1783
                        q->dns_id = get_next_dns_id(s);
 
1784
 
 
1785
                // out of name servers?
 
1786
                if(q->servers_tried_count == s->name_servers->count)
 
1787
                {
 
1788
                        // clear the 'tried' list, and start over in retry mode
 
1789
                        query_clear_servers_tried(q);
 
1790
                        q->retrying = 1;
 
1791
                }
 
1792
 
 
1793
                // find a nameserver that has not been tried or failed
 
1794
                ns = 0;
 
1795
                for(k = 0; k < s->name_servers->count; ++k)
 
1796
                {
 
1797
                        name_server_t *i = (name_server_t *)s->name_servers->item[k];
 
1798
                        if(!query_server_tried(q, i->id) && !query_server_failed(q, i->id))
 
1799
                        {
 
1800
                                ns = i;
 
1801
                                break;
 
1802
                        }
 
1803
                }
 
1804
 
 
1805
                // in theory, it is not possible for 'ns' to be null here
 
1806
 
 
1807
                // don't send the packet if there is already one in the queue
 
1808
                already_sending = 0;
 
1809
                for(k = 0; k < s->outgoing->count; ++k)
 
1810
                {
 
1811
                        datagram_t *a = (datagram_t *)s->outgoing->item[k];
 
1812
                        if(a->query == q && a->query_send_type == 0)
 
1813
                        {
 
1814
                                already_sending = 1;
 
1815
                                break;
 
1816
                        }
 
1817
                }
 
1818
 
 
1819
                // send the query, with recursion desired, normal query_send_type
 
1820
                if(!already_sending)
 
1821
                        _queue_packet(s, q, ns, 1, 0);
 
1822
 
 
1823
                query_add_server_tried(q, ns->id);
 
1824
 
 
1825
                // if there is one query, then do a trick on the first step
 
1826
                /*if(s->queries->count == 1 && q->step == 0 && !q->retrying)
 
1827
                {
 
1828
                        // query all other servers non-recursively
 
1829
                        // note: if sending fails, there is no retry
 
1830
                        for(k = 0; k < s->name_servers->count; ++k)
 
1831
                        {
 
1832
                                name_server_t *i = (name_server_t *)s->name_servers->item[k];
 
1833
                                if(!query_server_tried(q, i->id))
 
1834
                                {
 
1835
                                        // last arg sets first-step query_send_type
 
1836
                                        _queue_packet(s, q, i, 0, 1);
 
1837
                                }
 
1838
                        }
 
1839
                }*/
 
1840
 
 
1841
                // out of name servers?
 
1842
                if(q->servers_tried_count == s->name_servers->count)
 
1843
                {
 
1844
                        // clear the 'tried' list, and start over in retry mode
 
1845
                        query_clear_servers_tried(q);
 
1846
                        q->retrying = 1;
 
1847
                }
 
1848
 
 
1849
                q->time_start = now;
 
1850
                q->time_next = q->retrying ? 1500 : 800;
 
1851
                ++q->step;
 
1852
        }
 
1853
 
 
1854
        // try to send queued outgoing packets
 
1855
        for(n = 0; n < s->outgoing->count; ++n)
 
1856
        {
 
1857
                datagram_t *a = (datagram_t *)s->outgoing->item[n];
 
1858
                int ret;
 
1859
 
 
1860
                if(!s->handle_writable)
 
1861
                {
 
1862
                        need_write = 1;
 
1863
                        break;
 
1864
                }
 
1865
 
 
1866
                _debug_line(s, "SEND %s:%d (size=%d)", a->dest_address->c_str, a->dest_port, a->size);
 
1867
                _print_hexdump(s, a->data, a->size);
 
1868
 
 
1869
                ret = s->cb.udp_write(s, s->cb.app, a->handle, a->dest_address, a->dest_port, a->data, a->size);
 
1870
                if(ret == 0)
 
1871
                {
 
1872
                        s->handle_writable = 0;
 
1873
                        need_write = 1;
 
1874
                        break;
 
1875
                }
 
1876
 
 
1877
                list_remove(s->outgoing, a);
 
1878
                --n; // adjust position
 
1879
        }
 
1880
 
 
1881
        return need_write;
 
1882
}
 
1883
 
 
1884
void _cache_add(jdns_session_t *s, const unsigned char *qname, int qtype, int time_start, int ttl, const jdns_rr_t *record)
 
1885
{
 
1886
        cache_item_t *i;
 
1887
        jdns_string_t *str;
 
1888
        if(ttl == 0)
 
1889
                return;
 
1890
        i = cache_item_new();
 
1891
        i->qname = _ustrdup(qname);
 
1892
        i->qtype = qtype;
 
1893
        i->time_start = time_start;
 
1894
        i->ttl = ttl;
 
1895
        if(record)
 
1896
                i->record = jdns_rr_copy(record);
 
1897
        list_insert(s->cache, i, -1);
 
1898
 
 
1899
        str = _make_printable_cstr((const char *)i->qname);
 
1900
        _debug_line(s, "cache add [%s] for %d seconds", str->data, i->ttl);
 
1901
        jdns_string_delete(str);
 
1902
}
 
1903
 
 
1904
void _cache_remove_all_of_kind(jdns_session_t *s, const unsigned char *qname, int qtype)
 
1905
{
 
1906
        int n;
 
1907
        for(n = 0; n < s->cache->count; ++n)
 
1908
        {
 
1909
                cache_item_t *i = (cache_item_t *)s->cache->item[n];
 
1910
                if(jdns_domain_cmp(i->qname, qname) && i->qtype == qtype)
 
1911
                {
 
1912
                        jdns_string_t *str = _make_printable_cstr((const char *)i->qname);
 
1913
                        _debug_line(s, "cache del [%s]", str->data);
 
1914
                        jdns_string_delete(str);
 
1915
                        list_remove(s->cache, i);
 
1916
                        --n; // adjust position
 
1917
                }
 
1918
        }
 
1919
}
 
1920
 
 
1921
int _unicast_do_reads(jdns_session_t *s, int now)
 
1922
{
 
1923
        int need_read;
 
1924
        int n, k;
 
1925
 
 
1926
        // let's always ask for reads, just so the user doesn't have to
 
1927
        //  worry about what should happen to incoming packets otherwise
 
1928
        need_read = 1;
 
1929
 
 
1930
        if(!s->handle_readable)
 
1931
                return need_read;
 
1932
 
 
1933
        while(1)
 
1934
        {
 
1935
                unsigned char buf[JDNS_UDP_UNI_IN_MAX];
 
1936
                int bufsize = JDNS_UDP_UNI_IN_MAX;
 
1937
                int ret;
 
1938
                jdns_packet_t *packet;
 
1939
                jdns_address_t *addr;
 
1940
                int port;
 
1941
                query_t *q;
 
1942
                name_server_t *ns;
 
1943
 
 
1944
                addr = jdns_address_new();
 
1945
                ret = s->cb.udp_read(s, s->cb.app, s->handle, addr, &port, buf, &bufsize);
 
1946
 
 
1947
                // no packet?
 
1948
                if(ret == 0)
 
1949
                {
 
1950
                        s->handle_readable = 0;
 
1951
                        jdns_address_delete(addr);
 
1952
                        break;
 
1953
                }
 
1954
 
 
1955
                _debug_line(s, "RECV %s:%d (size=%d)", addr->c_str, port, bufsize);
 
1956
                _print_hexdump(s, buf, bufsize);
 
1957
 
 
1958
                if(!jdns_packet_import(&packet, buf, bufsize))
 
1959
                {
 
1960
                        _debug_line(s, "error parsing packet / too large");
 
1961
 
 
1962
                        jdns_address_delete(addr);
 
1963
                        continue;
 
1964
                }
 
1965
 
 
1966
                _print_packet(s, packet);
 
1967
 
 
1968
                if(s->queries->count == 0)
 
1969
                {
 
1970
                        _debug_line(s, "we have no queries");
 
1971
 
 
1972
                        jdns_address_delete(addr);
 
1973
                        continue;
 
1974
                }
 
1975
 
 
1976
                // who does it belong to?
 
1977
                q = 0;
 
1978
                ns = 0;
 
1979
                for(n = 0; n < s->queries->count; ++n)
 
1980
                {
 
1981
                        query_t *i = (query_t *)s->queries->item[n];
 
1982
                        if(i->dns_id == -1)
 
1983
                                continue;
 
1984
 
 
1985
                        if(i->dns_id == packet->id)
 
1986
                        {
 
1987
                                q = i;
 
1988
                                break;
 
1989
                        }
 
1990
                }
 
1991
 
 
1992
                if(q)
 
1993
                {
 
1994
                        // what name server did it come from?
 
1995
                        for(k = 0; k < s->name_servers->count; ++k)
 
1996
                        {
 
1997
                                name_server_t *i = (name_server_t *)s->name_servers->item[k];
 
1998
                                if(jdns_address_cmp(i->address, addr) && i->port == port)
 
1999
                                {
 
2000
                                        ns = i;
 
2001
                                        break;
 
2002
                                }
 
2003
                        }
 
2004
 
 
2005
                        // none? maybe that's because we're using unicast
 
2006
                        //   over multicast, where responses always come
 
2007
                        //   from an unexpected address
 
2008
                        if(!ns && s->name_servers->count > 0)
 
2009
                        {
 
2010
                                name_server_t *i;
 
2011
                                jdns_address_t *m4, *m6;
 
2012
 
 
2013
                                i = (name_server_t *)s->name_servers->item[0];
 
2014
                                m4 = jdns_address_multicast4_new();
 
2015
                                m6 = jdns_address_multicast6_new();
 
2016
                                if(jdns_address_cmp(i->address, m4) || jdns_address_cmp(i->address, m6))
 
2017
                                        ns = i;
 
2018
                                jdns_address_delete(m4);
 
2019
                                jdns_address_delete(m6);
 
2020
                        }
 
2021
 
 
2022
                        // if there is no suitable name server, don't accept
 
2023
                        //   as a reply
 
2024
                        if(!ns)
 
2025
                                q = 0;
 
2026
                }
 
2027
 
 
2028
                jdns_address_delete(addr);
 
2029
 
 
2030
                // no queries?  eat the packet
 
2031
                if(!q)
 
2032
                {
 
2033
                        _debug_line(s, "no such query for packet");
 
2034
                        jdns_packet_delete(packet);
 
2035
                        continue;
 
2036
                }
 
2037
 
 
2038
                _process_message(s, packet, now, q, ns);
 
2039
                jdns_packet_delete(packet);
 
2040
        }
 
2041
 
 
2042
        return need_read;
 
2043
}
 
2044
 
 
2045
void _process_message(jdns_session_t *s, jdns_packet_t *packet, int now, query_t *q, name_server_t *ns)
 
2046
{
 
2047
        int n;
 
2048
        int authoritative;
 
2049
        int truncated;
 
2050
        int recursion_desired;
 
2051
        int answer_section_ok;
 
2052
        int nxdomain;
 
2053
        jdns_response_t *r;
 
2054
 
 
2055
        if(packet->opts.opcode != 0)
 
2056
        {
 
2057
                _debug_line(s, "opcode != 0, discarding");
 
2058
                return;
 
2059
        }
 
2060
 
 
2061
        // we don't test RA (recursion available)
 
2062
        // we don't test the extra Z fields
 
2063
 
 
2064
        authoritative = packet->opts.aa;
 
2065
        truncated = packet->opts.tc;
 
2066
        recursion_desired = packet->opts.rd;
 
2067
        answer_section_ok = 0;
 
2068
        if(packet->qdcount == packet->questions->count && packet->ancount == packet->answerRecords->count)
 
2069
                answer_section_ok = 1;
 
2070
        nxdomain = 0;
 
2071
 
 
2072
        r = 0;
 
2073
 
 
2074
        // nxdomain
 
2075
        if(packet->opts.rcode == 3)
 
2076
        {
 
2077
                r = jdns_response_new();
 
2078
                nxdomain = 1;
 
2079
        }
 
2080
        // normal
 
2081
        else if(packet->opts.rcode == 0)
 
2082
        {
 
2083
                int at_least_something;
 
2084
                int success;
 
2085
 
 
2086
                r = _packet2response(packet, q->qname, q->qtype, 0xffff);
 
2087
                at_least_something = 0;
 
2088
                if(r->answerCount > 0)
 
2089
                        at_least_something = 1;
 
2090
                _print_records(s, r, q->qname);
 
2091
 
 
2092
                success = 0;
 
2093
                if(at_least_something)
 
2094
                {
 
2095
                        success = 1;
 
2096
                }
 
2097
                else
 
2098
                {
 
2099
                        // note: why does qdns care about recursion_desired here?
 
2100
                        if(authoritative && recursion_desired)
 
2101
                                success = 1;
 
2102
                }
 
2103
 
 
2104
                if(!success)
 
2105
                {
 
2106
                        jdns_response_delete(r);
 
2107
                        r = 0;
 
2108
                }
 
2109
        }
 
2110
 
 
2111
        // caching
 
2112
        if(r)
 
2113
        {
 
2114
                if(nxdomain)
 
2115
                {
 
2116
                        // cache nxdomain for 1 minute
 
2117
                        if(q->qtype != JDNS_RTYPE_ANY)
 
2118
                        {
 
2119
                                _cache_remove_all_of_kind(s, q->qname, q->qtype);
 
2120
                                _cache_add(s, q->qname, q->qtype, now, 60, 0);
 
2121
                        }
 
2122
                }
 
2123
                else
 
2124
                {
 
2125
                        int cache_answers;
 
2126
                        int cache_additional;
 
2127
 
 
2128
                        // clear past items
 
2129
                        _cache_remove_all_of_kind(s, q->qname, q->qtype);
 
2130
 
 
2131
                        cache_answers = 1;
 
2132
                        cache_additional = 1;
 
2133
 
 
2134
                        // if truncated, we may not want to cache
 
2135
                        if(truncated)
 
2136
                        {
 
2137
                                cache_additional = 0;
 
2138
                                if(!answer_section_ok)
 
2139
                                        cache_answers = 0;
 
2140
                        }
 
2141
 
 
2142
                        if(cache_answers)
 
2143
                        {
 
2144
                                for(n = 0; n < r->answerCount; ++n)
 
2145
                                {
 
2146
                                        jdns_rr_t *record = r->answerRecords[n];
 
2147
                                        _cache_add(s, q->qname, record->type, now, _min(record->ttl, JDNS_TTL_MAX), record);
 
2148
                                }
 
2149
                        }
 
2150
 
 
2151
                        if(cache_additional)
 
2152
                        {
 
2153
                                for(n = 0; n < r->additionalCount; ++n)
 
2154
                                {
 
2155
                                        jdns_rr_t *record = r->additionalRecords[n];
 
2156
                                        _cache_add(s, record->owner, record->type, now, _min(record->ttl, JDNS_TTL_MAX), record);
 
2157
                                }
 
2158
                        }
 
2159
                }
 
2160
        }
 
2161
 
 
2162
        // don't pass authority/additional records upwards
 
2163
        if(r)
 
2164
                jdns_response_remove_extra(r);
 
2165
 
 
2166
        // this server returned an error?
 
2167
        if(!r && ns)
 
2168
                query_add_server_failed(q, ns->id);
 
2169
 
 
2170
        if(_process_response(s, r, nxdomain, q))
 
2171
        {
 
2172
                _remove_query_datagrams(s, q);
 
2173
                list_remove(s->queries, q);
 
2174
        }
 
2175
 
 
2176
        jdns_response_delete(r);
 
2177
}
 
2178
 
 
2179
int _process_response(jdns_session_t *s, jdns_response_t *r, int nxdomain, query_t *q)
 
2180
{
 
2181
        int k;
 
2182
 
 
2183
        // error
 
2184
        if(!r)
 
2185
        {
 
2186
                int all_errored;
 
2187
 
 
2188
                // if not all servers have errored, ignore error
 
2189
                all_errored = 1;
 
2190
                for(k = 0; k < s->name_servers->count; ++k)
 
2191
                {
 
2192
                        name_server_t *ns = (name_server_t *)s->name_servers->item[k];
 
2193
                        if(!query_server_failed(q, ns->id))
 
2194
                        {
 
2195
                                all_errored = 0;
 
2196
                                break;
 
2197
                        }
 
2198
                }
 
2199
                if(!all_errored)
 
2200
                        return 0;
 
2201
 
 
2202
                // report event to any requests listening
 
2203
                for(k = 0; k < q->req_ids_count; ++k)
 
2204
                {
 
2205
                        jdns_event_t *event = jdns_event_new();
 
2206
                        event->type = JDNS_EVENT_RESPONSE;
 
2207
                        event->id = q->req_ids[k];
 
2208
                        event->status = JDNS_STATUS_ERROR;
 
2209
                        _append_event(s, event);
 
2210
                }
 
2211
 
 
2212
                // report error to parent
 
2213
                if(q->cname_parent)
 
2214
                {
 
2215
                        // report event to any requests listening
 
2216
                        query_t *cq = q->cname_parent;
 
2217
                        for(k = 0; k < cq->req_ids_count; ++k)
 
2218
                        {
 
2219
                                jdns_event_t *event = jdns_event_new();
 
2220
                                event->type = JDNS_EVENT_RESPONSE;
 
2221
                                event->id = cq->req_ids[k];
 
2222
                                event->status = JDNS_STATUS_ERROR;
 
2223
                                _append_event(s, event);
 
2224
                        }
 
2225
                        list_remove(s->queries, cq);
 
2226
                }
 
2227
 
 
2228
                return 1;
 
2229
        }
 
2230
        // nxdomain
 
2231
        else if(nxdomain)
 
2232
        {
 
2233
                // report event to any requests listening
 
2234
                for(k = 0; k < q->req_ids_count; ++k)
 
2235
                {
 
2236
                        jdns_event_t *event = jdns_event_new();
 
2237
                        event->type = JDNS_EVENT_RESPONSE;
 
2238
                        event->id = q->req_ids[k];
 
2239
                        event->status = JDNS_STATUS_NXDOMAIN;
 
2240
                        _append_event(s, event);
 
2241
                }
 
2242
 
 
2243
                // report error to parent
 
2244
                if(q->cname_parent)
 
2245
                {
 
2246
                        // report event to any requests listening
 
2247
                        query_t *cq = q->cname_parent;
 
2248
                        for(k = 0; k < cq->req_ids_count; ++k)
 
2249
                        {
 
2250
                                jdns_event_t *event = jdns_event_new();
 
2251
                                event->type = JDNS_EVENT_RESPONSE;
 
2252
                                event->id = cq->req_ids[k];
 
2253
                                event->status = JDNS_STATUS_ERROR;
 
2254
                                _append_event(s, event);
 
2255
                        }
 
2256
                        list_remove(s->queries, cq);
 
2257
                }
 
2258
 
 
2259
                return 1;
 
2260
        }
 
2261
 
 
2262
        // all we got was a cname that we didn't ask for?
 
2263
        if(r->answerCount == 1 && r->answerRecords[0]->type == JDNS_RTYPE_CNAME && q->qtype != JDNS_RTYPE_CNAME)
 
2264
        {
 
2265
                query_t *new_q;
 
2266
 
 
2267
                _debug_line(s, "all we got was a cname, following the chain ...");
 
2268
 
 
2269
                // max chain count, bail
 
2270
                if(q->cname_chain_count >= 16)
 
2271
                {
 
2272
                        // report event to any requests listening
 
2273
                        for(k = 0; k < q->req_ids_count; ++k)
 
2274
                        {
 
2275
                                jdns_event_t *event = jdns_event_new();
 
2276
                                event->type = JDNS_EVENT_RESPONSE;
 
2277
                                event->id = q->req_ids[k];
 
2278
                                event->status = JDNS_STATUS_ERROR;
 
2279
                                _append_event(s, event);
 
2280
                        }
 
2281
 
 
2282
                        // report error to parent
 
2283
                        if(q->cname_parent)
 
2284
                        {
 
2285
                                // report event to any requests listening
 
2286
                                query_t *cq = q->cname_parent;
 
2287
                                for(k = 0; k < cq->req_ids_count; ++k)
 
2288
                                {
 
2289
                                        jdns_event_t *event = jdns_event_new();
 
2290
                                        event->type = JDNS_EVENT_RESPONSE;
 
2291
                                        event->id = cq->req_ids[k];
 
2292
                                        event->status = JDNS_STATUS_ERROR;
 
2293
                                        _append_event(s, event);
 
2294
                                }
 
2295
                                list_remove(s->queries, cq);
 
2296
                        }
 
2297
 
 
2298
                        return 1;
 
2299
                }
 
2300
 
 
2301
                new_q = _get_query(s, r->answerRecords[0]->data.name, q->qtype, 1);
 
2302
                if(q->cname_parent)
 
2303
                {
 
2304
                        new_q->cname_chain_count = q->cname_chain_count + 1;
 
2305
                        new_q->cname_parent = q->cname_parent;
 
2306
                        new_q->cname_parent->cname_child = new_q;
 
2307
                }
 
2308
                else
 
2309
                {
 
2310
                        new_q->cname_chain_count = q->cname_chain_count + 1;
 
2311
                        new_q->cname_parent = q;
 
2312
                        q->cname_child = new_q;
 
2313
                        q->time_start = -1;
 
2314
                        q->dns_id = -1; // don't handle responses
 
2315
                }
 
2316
        }
 
2317
 
 
2318
        // if this query now has a child, then don't report events or delete
 
2319
        if(q->cname_child)
 
2320
                return 0;
 
2321
 
 
2322
        // report event to any requests listening
 
2323
        for(k = 0; k < q->req_ids_count; ++k)
 
2324
        {
 
2325
                jdns_event_t *event = jdns_event_new();
 
2326
                event->type = JDNS_EVENT_RESPONSE;
 
2327
                event->id = q->req_ids[k];
 
2328
                event->status = JDNS_STATUS_SUCCESS;
 
2329
                event->response = jdns_response_copy(r);
 
2330
                _append_event(s, event);
 
2331
        }
 
2332
 
 
2333
        // report to parent
 
2334
        if(q->cname_parent)
 
2335
        {
 
2336
                // report event to any requests listening
 
2337
                query_t *cq = q->cname_parent;
 
2338
                for(k = 0; k < cq->req_ids_count; ++k)
 
2339
                {
 
2340
                        jdns_event_t *event = jdns_event_new();
 
2341
                        event->type = JDNS_EVENT_RESPONSE;
 
2342
                        event->id = cq->req_ids[k];
 
2343
                        event->status = JDNS_STATUS_SUCCESS;
 
2344
                        event->response = jdns_response_copy(r);
 
2345
                        _append_event(s, event);
 
2346
                }
 
2347
                list_remove(s->queries, cq);
 
2348
        }
 
2349
 
 
2350
        return 1;
 
2351
}
 
2352
 
 
2353
//----------------------------------------------------------------------------
 
2354
// jdns - multicast
 
2355
//----------------------------------------------------------------------------
 
2356
static jdns_rr_t *_mdnsda2rr(mdnsda a)
 
2357
{
 
2358
        jdns_rr_t *rr;
 
2359
 
 
2360
        if(a->type == JDNS_RTYPE_ANY)
 
2361
                return 0;
 
2362
 
 
2363
        // for AAAA, TXT and HINFO, run the raw rdata through jdns_rr's parser
 
2364
        if(a->type == JDNS_RTYPE_AAAA || a->type == JDNS_RTYPE_TXT || a->type == JDNS_RTYPE_HINFO)
 
2365
        {
 
2366
                jdns_packet_resource_t *pr = jdns_packet_resource_new();
 
2367
                pr->qname = jdns_string_new();
 
2368
                jdns_string_set_cstr(pr->qname, (const char *)a->name);
 
2369
                pr->qtype = a->type;
 
2370
                pr->qclass = 0x0001; // class is always 1 for us
 
2371
                if(a->ttl == 0)
 
2372
                        pr->ttl = 0;
 
2373
                else
 
2374
                        pr->ttl = a->real_ttl;
 
2375
                pr->rdata = jdns_copy_array(a->rdata, a->rdlen);
 
2376
                pr->rdlength = a->rdlen;
 
2377
 
 
2378
                // we don't need a reference for these types
 
2379
                rr = jdns_rr_from_resource(pr, 0);
 
2380
        }
 
2381
        // else, pull the values out of 'a' directly
 
2382
        else
 
2383
        {
 
2384
                rr = jdns_rr_new();
 
2385
                rr->owner = _ustrdup(a->name);
 
2386
                rr->qclass = 0x0001; // class is always 1 for us
 
2387
                if(a->ttl == 0)
 
2388
                        rr->ttl = 0;
 
2389
                else
 
2390
                        rr->ttl = a->real_ttl;
 
2391
 
 
2392
                switch(a->type)
 
2393
                {
 
2394
                        case JDNS_RTYPE_A:
 
2395
                        {
 
2396
                                jdns_address_t *addr = jdns_address_new();
 
2397
                                jdns_address_set_ipv4(addr, a->ip);
 
2398
                                jdns_rr_set_A(rr, addr);
 
2399
                                jdns_address_delete(addr);
 
2400
                                break;
 
2401
                        }
 
2402
                        case JDNS_RTYPE_AAAA:
 
2403
                        {
 
2404
                                // covered earlier
 
2405
                                break;
 
2406
                        }
 
2407
                        case JDNS_RTYPE_MX:
 
2408
                        {
 
2409
                                // don't care about MX
 
2410
                                jdns_rr_delete(rr);
 
2411
                                rr = 0;
 
2412
                                break;
 
2413
                        }
 
2414
                        case JDNS_RTYPE_SRV:
 
2415
                        {
 
2416
                                jdns_rr_set_SRV(rr, a->rdname, a->srv.port, a->srv.priority, a->srv.weight);
 
2417
                                break;
 
2418
                        }
 
2419
                        case JDNS_RTYPE_CNAME:
 
2420
                        {
 
2421
                                jdns_rr_set_CNAME(rr, a->rdname);
 
2422
                                break;
 
2423
                        }
 
2424
                        case JDNS_RTYPE_PTR:
 
2425
                        {
 
2426
                                jdns_rr_set_PTR(rr, a->rdname);
 
2427
                                break;
 
2428
                        }
 
2429
                        case JDNS_RTYPE_TXT:
 
2430
                        {
 
2431
                                // covered earlier
 
2432
                                break;
 
2433
                        }
 
2434
                        case JDNS_RTYPE_HINFO:
 
2435
                        {
 
2436
                                // covered earlier
 
2437
                                break;
 
2438
                        }
 
2439
                        case JDNS_RTYPE_NS:
 
2440
                        {
 
2441
                                // don't care about NS
 
2442
                                jdns_rr_delete(rr);
 
2443
                                rr = 0;
 
2444
                                break;
 
2445
                        }
 
2446
                        default:
 
2447
                        {
 
2448
                                jdns_rr_set_record(rr, a->type, a->rdata, a->rdlen);
 
2449
                                break;
 
2450
                        }
 
2451
                }
 
2452
        }
 
2453
 
 
2454
        return rr;
 
2455
}
 
2456
 
 
2457
static int _cmp_rdata(const jdns_rr_t *a, const jdns_rr_t *b)
 
2458
{
 
2459
        if(a->rdlength != b->rdlength)
 
2460
                return 0;
 
2461
        if(memcmp(a->rdata, b->rdata, a->rdlength) != 0)
 
2462
                return 0;
 
2463
        return 1;
 
2464
}
 
2465
 
 
2466
static int _cmp_rr(const jdns_rr_t *a, const jdns_rr_t *b)
 
2467
{
 
2468
        if(a->type != b->type)
 
2469
                return 0;
 
2470
        if(!jdns_domain_cmp(a->owner, b->owner))
 
2471
                return 0;
 
2472
        switch(a->type)
 
2473
        {
 
2474
                case JDNS_RTYPE_A:
 
2475
                        if(!jdns_address_cmp(a->data.address, b->data.address))
 
2476
                                return 0;
 
2477
                        break;
 
2478
                case JDNS_RTYPE_AAAA:
 
2479
                        if(!_cmp_rdata(a, b))
 
2480
                                return 0;
 
2481
                        break;
 
2482
                case JDNS_RTYPE_MX:
 
2483
                        // unsupported
 
2484
                        return 0;
 
2485
                case JDNS_RTYPE_SRV:
 
2486
                        if(a->data.server->port != b->data.server->port
 
2487
                                || a->data.server->priority != b->data.server->priority
 
2488
                                || a->data.server->weight != b->data.server->weight
 
2489
                                || !jdns_domain_cmp(a->data.server->name, b->data.server->name)
 
2490
                        )
 
2491
                                return 0;
 
2492
                        break;
 
2493
                case JDNS_RTYPE_CNAME:
 
2494
                        if(!jdns_domain_cmp(a->data.name, b->data.name))
 
2495
                                return 0;
 
2496
                        break;
 
2497
                case JDNS_RTYPE_PTR:
 
2498
                        if(!jdns_domain_cmp(a->data.name, b->data.name))
 
2499
                                return 0;
 
2500
                        break;
 
2501
                case JDNS_RTYPE_TXT:
 
2502
                        if(!_cmp_rdata(a, b))
 
2503
                                return 0;
 
2504
                        break;
 
2505
                case JDNS_RTYPE_HINFO:
 
2506
                        if(!_cmp_rdata(a, b))
 
2507
                                return 0;
 
2508
                        break;
 
2509
                case JDNS_RTYPE_NS:
 
2510
                        // unsupported
 
2511
                        return 0;
 
2512
                default:
 
2513
                        if(!_cmp_rdata(a, b))
 
2514
                                return 0;
 
2515
                        break;
 
2516
        }
 
2517
        return 1;
 
2518
}
 
2519
 
 
2520
int _multicast_query_ans(mdnsda a, void *arg)
 
2521
{
 
2522
        int n;
 
2523
        jdns_session_t *s;
 
2524
        query_t *q;
 
2525
        jdns_response_t *r;
 
2526
        jdns_rr_t *rr;
 
2527
        jdns_event_t *event;
 
2528
 
 
2529
        s = (jdns_session_t *)arg;
 
2530
 
 
2531
        // what query is this for?
 
2532
        q = 0;
 
2533
        for(n = 0; n < s->queries->count; ++n)
 
2534
        {
 
2535
                query_t *i = (query_t *)s->queries->item[n];
 
2536
                if((i->qtype == JDNS_RTYPE_ANY || i->qtype == a->type) && jdns_domain_cmp(i->qname, a->name))
 
2537
                {
 
2538
                        q = i;
 
2539
                        break;
 
2540
                }
 
2541
        }
 
2542
 
 
2543
        // note: this can't happen, but we'll check anyway
 
2544
        if(!q)
 
2545
        {
 
2546
                _debug_line(s, "no such multicast query");
 
2547
                return 0;
 
2548
        }
 
2549
 
 
2550
        rr = _mdnsda2rr(a);
 
2551
        if(!rr)
 
2552
                return 0;
 
2553
 
 
2554
        // add/remove as a known
 
2555
        if(rr->ttl == 0)
 
2556
        {
 
2557
                for(n = 0; n < q->mul_known->answerCount; ++n)
 
2558
                {
 
2559
                        jdns_rr_t *k = q->mul_known->answerRecords[n];
 
2560
                        if(_cmp_rr(k, rr))
 
2561
                        {
 
2562
                                jdns_response_remove_answer(q->mul_known, n);
 
2563
                                break;
 
2564
                        }
 
2565
                }
 
2566
        }
 
2567
        else
 
2568
                jdns_response_append_answer(q->mul_known, rr);
 
2569
 
 
2570
        r = jdns_response_new();
 
2571
        jdns_response_append_answer(r, rr);
 
2572
        jdns_rr_delete(rr);
 
2573
 
 
2574
        // report event to any requests listening
 
2575
        for(n = 0; n < q->req_ids_count; ++n)
 
2576
        {
 
2577
                event = jdns_event_new();
 
2578
                event->type = JDNS_EVENT_RESPONSE;
 
2579
                event->id = q->req_ids[n];
 
2580
                event->status = JDNS_STATUS_SUCCESS;
 
2581
                event->response = jdns_response_copy(r);
 
2582
                _append_event(s, event);
 
2583
        }
 
2584
 
 
2585
        jdns_response_delete(r);
 
2586
        return 0;
 
2587
}
 
2588
 
 
2589
query_t *_get_multicast_query(jdns_session_t *s, const unsigned char *qname, int qtype)
 
2590
{
 
2591
        int n;
 
2592
        query_t *q;
 
2593
        jdns_string_t *str;
 
2594
 
 
2595
        // check for existing queries
 
2596
        for(n = 0; n < s->queries->count; ++n)
 
2597
        {
 
2598
                q = (query_t *)s->queries->item[n];
 
2599
                if(jdns_domain_cmp(q->qname, qname) && q->qtype == qtype)
 
2600
                {
 
2601
                        str = _make_printable_cstr((const char *)q->qname);
 
2602
                        _debug_line(s, "[%d] reusing query for: [%s] [%s]", q->id, _qtype2str(qtype), str->data);
 
2603
                        jdns_string_delete(str);
 
2604
                        return q;
 
2605
                }
 
2606
        }
 
2607
 
 
2608
        q = query_new();
 
2609
        q->id = get_next_qid(s);
 
2610
        q->qname = _ustrdup(qname);
 
2611
        q->qtype = qtype;
 
2612
        q->step = 0;
 
2613
        q->mul_known = jdns_response_new();
 
2614
        list_insert(s->queries, q, -1);
 
2615
 
 
2616
        str = _make_printable_cstr((const char *)q->qname);
 
2617
        _debug_line(s, "[%d] querying: [%s] [%s]", q->id, _qtype2str(qtype), str->data);
 
2618
        jdns_string_delete(str);
 
2619
        return q;
 
2620
}
 
2621
 
 
2622
int _multicast_query(jdns_session_t *s, const unsigned char *name, int qtype)
 
2623
{
 
2624
        unsigned char *qname;
 
2625
        query_t *q;
 
2626
        int req_id;
 
2627
        jdns_string_t *str;
 
2628
 
 
2629
        str = _make_printable_cstr((const char *)name);
 
2630
        _debug_line(s, "query input: [%s]", str->data);
 
2631
        jdns_string_delete(str);
 
2632
 
 
2633
        // add a dot to the end if needed
 
2634
        qname = _fix_input(name);
 
2635
 
 
2636
        q = _get_multicast_query(s, qname, qtype);
 
2637
        req_id = get_next_req_id(s);
 
2638
        query_add_req_id(q, req_id);
 
2639
        free(qname);
 
2640
 
 
2641
        // start the mdnsd_query if necessary
 
2642
        if(q->step == 0)
 
2643
        {
 
2644
                q->step = 1;
 
2645
                mdnsd_query(s->mdns, (char *)q->qname, q->qtype, _multicast_query_ans, s);
 
2646
        }
 
2647
        else
 
2648
        {
 
2649
                int n;
 
2650
 
 
2651
                // report the knowns
 
2652
                for(n = 0; n < q->mul_known->answerCount; ++n)
 
2653
                {
 
2654
                        const jdns_rr_t *rr;
 
2655
                        jdns_response_t *r;
 
2656
                        jdns_event_t *event;
 
2657
 
 
2658
                        rr = q->mul_known->answerRecords[n];
 
2659
                        r = jdns_response_new();
 
2660
                        jdns_response_append_answer(r, rr);
 
2661
 
 
2662
                        event = jdns_event_new();
 
2663
                        event->type = JDNS_EVENT_RESPONSE;
 
2664
                        event->id = req_id;
 
2665
                        event->status = JDNS_STATUS_SUCCESS;
 
2666
                        event->response = r;
 
2667
                        _append_event(s, event);
 
2668
                }
 
2669
        }
 
2670
        return req_id;
 
2671
}
 
2672
 
 
2673
void _multicast_cancel(jdns_session_t *s, int req_id)
 
2674
{
 
2675
        int n;
 
2676
        for(n = 0; n < s->queries->count; ++n)
 
2677
        {
 
2678
                query_t *q = (query_t *)s->queries->item[n];
 
2679
                if(query_have_req_id(q, req_id))
 
2680
                {
 
2681
                        query_remove_req_id(q, req_id);
 
2682
 
 
2683
                        // if no one else is depending on this request, then take action
 
2684
                        if(q->req_ids_count == 0)
 
2685
                        {
 
2686
                                mdnsd_query(s->mdns, (char *)q->qname, q->qtype, NULL, 0);
 
2687
                                list_remove(s->queries, q);
 
2688
                        }
 
2689
                        break;
 
2690
                }
 
2691
        }
 
2692
}
 
2693
 
 
2694
void _multicast_pubresult(int result, char *name, int type, void *arg)
 
2695
{
 
2696
        jdns_session_t *s;
 
2697
        published_item_t *pub;
 
2698
        jdns_event_t *event;
 
2699
        int n;
 
2700
 
 
2701
        s = (jdns_session_t *)arg;
 
2702
 
 
2703
        // find the associated pub item
 
2704
        pub = 0;
 
2705
        for(n = 0; n < s->published->count; ++n)
 
2706
        {
 
2707
                published_item_t *i = (published_item_t *)s->published->item[n];
 
2708
                if(strcmp((char *)i->qname, name) == 0 && i->qtype == type)
 
2709
                {
 
2710
                        pub = i;
 
2711
                        break;
 
2712
                }
 
2713
        }
 
2714
 
 
2715
        // note: this can't happen, but we'll check anyway
 
2716
        if(!pub)
 
2717
        {
 
2718
                _debug_line(s, "no such multicast published item");
 
2719
                return;
 
2720
        }
 
2721
 
 
2722
        if(result == 1)
 
2723
        {
 
2724
                jdns_string_t *str = _make_printable_cstr(name);
 
2725
                _debug_line(s, "published name %s for type %d", str->data, type);
 
2726
                jdns_string_delete(str);
 
2727
 
 
2728
                event = jdns_event_new();
 
2729
                event->type = JDNS_EVENT_PUBLISH;
 
2730
                event->id = pub->id;
 
2731
                event->status = JDNS_STATUS_SUCCESS;
 
2732
                _append_event(s, event);
 
2733
        }
 
2734
        else
 
2735
        {
 
2736
                jdns_string_t *str = _make_printable_cstr(name);
 
2737
                _debug_line(s, "conflicting name detected %s for type %d", str->data, type);
 
2738
                jdns_string_delete(str);
 
2739
 
 
2740
                event = jdns_event_new();
 
2741
                event->type = JDNS_EVENT_PUBLISH;
 
2742
                event->id = pub->id;
 
2743
                event->status = JDNS_STATUS_CONFLICT;
 
2744
                _append_event(s, event);
 
2745
 
 
2746
                // remove the item
 
2747
                list_remove(s->published, pub);
 
2748
        }
 
2749
}
 
2750
 
 
2751
static jdns_string_t *_create_text(const jdns_stringlist_t *texts)
 
2752
{
 
2753
        jdns_string_t *out;
 
2754
        int n;
 
2755
        int total;
 
2756
        unsigned char *buf;
 
2757
 
 
2758
        buf = 0;
 
2759
        total = 0;
 
2760
        for(n = 0; n < texts->count; ++n)
 
2761
                total += texts->item[n]->size + 1;
 
2762
        if(total > 0)
 
2763
        {
 
2764
                int at = 0;
 
2765
                buf = (unsigned char *)malloc(total);
 
2766
                for(n = 0; n < texts->count; ++n)
 
2767
                {
 
2768
                        unsigned int len = texts->item[n]->size;
 
2769
                        buf[at++] = len;
 
2770
                        memcpy(buf + at, texts->item[n]->data, len);
 
2771
                        at += len;
 
2772
                }
 
2773
        }
 
2774
 
 
2775
        out = jdns_string_new();
 
2776
        if(buf)
 
2777
        {
 
2778
                out->data = buf;
 
2779
                out->size = total;
 
2780
        }
 
2781
        else
 
2782
                jdns_string_set_cstr(out, "");
 
2783
        return out;
 
2784
}
 
2785
 
 
2786
static void _publish_applyrr_unknown(jdns_session_t *s, mdnsdr r, const jdns_rr_t *rr)
 
2787
{
 
2788
        // for unsupported/unknown, just take the rdata
 
2789
        // note: for this to work, the app must explicitly set the rdata.
 
2790
        //   if the record is MX or some other known but unsupported record
 
2791
        //   type, setting the known fields is not enough
 
2792
        mdnsd_set_raw(s->mdns, r, (char *)rr->rdata, rr->rdlength);
 
2793
}
 
2794
 
 
2795
static int _publish_applyrr(jdns_session_t *s, mdnsdr r, const jdns_rr_t *rr)
 
2796
{
 
2797
        if(!rr->haveKnown)
 
2798
        {
 
2799
                _publish_applyrr_unknown(s, r, rr);
 
2800
                return 1;
 
2801
        }
 
2802
 
 
2803
        // jdns_mdnsd supports: A, AAAA, SRV, CNAME, PTR, TXT, and HINFO
 
2804
        switch(rr->type)
 
2805
        {
 
2806
                case JDNS_RTYPE_A:
 
2807
                {
 
2808
                        unsigned long int ip_net = htonl(rr->data.address->addr.v4);
 
2809
                        mdnsd_set_raw(s->mdns, r, (char *)&ip_net, 4);
 
2810
                        break;
 
2811
                }
 
2812
                case JDNS_RTYPE_AAAA:
 
2813
                {
 
2814
                        mdnsd_set_raw(s->mdns, r, (char *)rr->data.address->addr.v6, 16);
 
2815
                        break;
 
2816
                }
 
2817
                case JDNS_RTYPE_SRV:
 
2818
                {
 
2819
                        mdnsd_set_srv(s->mdns, r, rr->data.server->priority, rr->data.server->weight, rr->data.server->port, (char *)rr->data.server->name);
 
2820
                        break;
 
2821
                }
 
2822
                case JDNS_RTYPE_CNAME:
 
2823
                {
 
2824
                        mdnsd_set_host(s->mdns, r, (char *)rr->data.name);
 
2825
                        break;
 
2826
                }
 
2827
                case JDNS_RTYPE_PTR:
 
2828
                {
 
2829
                        mdnsd_set_host(s->mdns, r, (char *)rr->data.name);
 
2830
                        break;
 
2831
                }
 
2832
                case JDNS_RTYPE_TXT:
 
2833
                {
 
2834
                        jdns_string_t *out = _create_text(rr->data.texts);
 
2835
                        mdnsd_set_raw(s->mdns, r, (char *)out->data, out->size);
 
2836
                        jdns_string_delete(out);
 
2837
                        break;
 
2838
                }
 
2839
                case JDNS_RTYPE_HINFO:
 
2840
                {
 
2841
                        jdns_string_t *out;
 
2842
                        jdns_stringlist_t *list;
 
2843
 
 
2844
                        list = jdns_stringlist_new();
 
2845
                        jdns_stringlist_append(list, rr->data.hinfo.cpu);
 
2846
                        jdns_stringlist_append(list, rr->data.hinfo.os);
 
2847
                        out = _create_text(list);
 
2848
                        jdns_stringlist_delete(list);
 
2849
 
 
2850
                        mdnsd_set_raw(s->mdns, r, (char *)out->data, out->size);
 
2851
                        jdns_string_delete(out);
 
2852
                        break;
 
2853
                }
 
2854
                default:
 
2855
                {
 
2856
                        _publish_applyrr_unknown(s, r, rr);
 
2857
                        break;
 
2858
                }
 
2859
        }
 
2860
 
 
2861
        return 1;
 
2862
}
 
2863
 
 
2864
static void report_published(jdns_session_t *s, published_item_t *pub)
 
2865
{
 
2866
        jdns_event_t *event;
 
2867
        jdns_string_t *str;
 
2868
 
 
2869
        str = _make_printable_cstr((char *)pub->qname);
 
2870
        _debug_line(s, "published name %s for type %d", str->data, pub->qtype);
 
2871
        jdns_string_delete(str);
 
2872
 
 
2873
        event = jdns_event_new();
 
2874
        event->type = JDNS_EVENT_PUBLISH;
 
2875
        event->id = pub->id;
 
2876
        event->status = JDNS_STATUS_SUCCESS;
 
2877
        _append_event(s, event);
 
2878
}
 
2879
 
 
2880
int _multicast_publish(jdns_session_t *s, int mode, const jdns_rr_t *rr)
 
2881
{
 
2882
        mdnsdr r;
 
2883
        published_item_t *pub;
 
2884
        int next_id;
 
2885
        jdns_event_t *event;
 
2886
        int n;
 
2887
 
 
2888
        r = 0;
 
2889
        next_id = get_next_req_id(s);
 
2890
 
 
2891
        // see if we have an item with this name+type combination already
 
2892
        pub = 0;
 
2893
        for(n = 0; n < s->published->count; ++n)
 
2894
        {
 
2895
                published_item_t *i = (published_item_t *)s->published->item[n];
 
2896
                if(i->qtype == rr->type && jdns_domain_cmp(i->qname, rr->owner))
 
2897
                {
 
2898
                        pub = i;
 
2899
                        break;
 
2900
                }
 
2901
        }
 
2902
        if(pub)
 
2903
                goto error;
 
2904
 
 
2905
        if(!jdns_rr_verify(rr))
 
2906
                goto error;
 
2907
 
 
2908
        if(mode == JDNS_PUBLISH_UNIQUE)
 
2909
                r = mdnsd_unique(s->mdns, (char *)rr->owner, rr->type, rr->ttl, _multicast_pubresult, s);
 
2910
        else
 
2911
                r = mdnsd_shared(s->mdns, (char *)rr->owner, rr->type, rr->ttl);
 
2912
 
 
2913
        if(!_publish_applyrr(s, r, rr))
 
2914
                goto error;
 
2915
 
 
2916
        pub = published_item_new();
 
2917
        pub->id = next_id;
 
2918
        pub->mode = mode;
 
2919
        pub->qname = _ustrdup(rr->owner);
 
2920
        pub->qtype = rr->type;
 
2921
        pub->rec = r;
 
2922
        pub->rr = jdns_rr_copy(rr);
 
2923
        list_insert(s->published, pub, -1);
 
2924
 
 
2925
        // mdnsd doesn't report publish events for shared, so do that here
 
2926
        if(mode == JDNS_PUBLISH_SHARED)
 
2927
                report_published(s, pub);
 
2928
 
 
2929
        return pub->id;
 
2930
 
 
2931
error:
 
2932
        _debug_line(s, "attempt to publish record, malformed, unsupported, or duplicate type");
 
2933
 
 
2934
        if(r)
 
2935
        {
 
2936
                // don't publish
 
2937
                mdnsd_done(s->mdns, r);
 
2938
        }
 
2939
 
 
2940
        // send an error to the app
 
2941
        event = jdns_event_new();
 
2942
        event->type = JDNS_EVENT_PUBLISH;
 
2943
        event->id = next_id;
 
2944
        event->status = JDNS_STATUS_ERROR;
 
2945
        _append_event(s, event);
 
2946
 
 
2947
        return next_id;
 
2948
}
 
2949
 
 
2950
void _multicast_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rr)
 
2951
{
 
2952
        mdnsdr r;
 
2953
        published_item_t *pub;
 
2954
        int qtype;
 
2955
        int n;
 
2956
 
 
2957
        pub = 0;
 
2958
        for(n = 0; n < s->published->count; ++n)
 
2959
        {
 
2960
                published_item_t *i = (published_item_t *)s->published->item[n];
 
2961
                if(i->id == id)
 
2962
                {
 
2963
                        pub = i;
 
2964
                        break;
 
2965
                }
 
2966
        }
 
2967
        if(!pub)
 
2968
                return;
 
2969
 
 
2970
        qtype = pub->qtype;
 
2971
        r = pub->rec;
 
2972
 
 
2973
        if(!_publish_applyrr(s, r, rr))
 
2974
        {
 
2975
                _debug_line(s, "attempt to update_publish an unsupported type");
 
2976
                return;
 
2977
        }
 
2978
}
 
2979
 
 
2980
void _multicast_cancel_publish(jdns_session_t *s, int id)
 
2981
{
 
2982
        int n;
 
2983
        for(n = 0; n < s->published->count; ++n)
 
2984
        {
 
2985
                published_item_t *i = (published_item_t *)s->published->item[n];
 
2986
                if(i->id == id)
 
2987
                {
 
2988
                        mdnsd_done(s->mdns, i->rec);
 
2989
                        list_remove(s->published, i);
 
2990
                        break;
 
2991
                }
 
2992
        }
 
2993
}
 
2994
 
 
2995
void _multicast_flush(jdns_session_t *s)
 
2996
{
 
2997
        int n;
 
2998
 
 
2999
        // to flush, we make like our queries and published items are all new.
 
3000
        // we'll do this by destroying/creating the mdnsd object again (so it
 
3001
        // is fresh) and then reapply all queries and published items to it.
 
3002
 
 
3003
        // start over with mdnsd
 
3004
        mdnsd_free(s->mdns);
 
3005
        s->mdns = mdnsd_new(0x0001, 1000, s->port, _callback_time_now, _callback_rand_int, s);
 
3006
 
 
3007
        // attempt to publish again
 
3008
        for(n = 0; n < s->published->count; ++n)
 
3009
        {
 
3010
                published_item_t *i;
 
3011
                mdnsdr r;
 
3012
 
 
3013
                i = (published_item_t *)s->published->item[n];
 
3014
                if(i->mode == JDNS_PUBLISH_UNIQUE)
 
3015
                        r = mdnsd_unique(s->mdns, (char *)i->rr->owner, i->rr->type, i->rr->ttl, _multicast_pubresult, s);
 
3016
                else
 
3017
                        r = mdnsd_shared(s->mdns, (char *)i->rr->owner, i->rr->type, i->rr->ttl);
 
3018
                _publish_applyrr(s, r, i->rr);
 
3019
                i->rec = r;
 
3020
        }
 
3021
 
 
3022
        // restore the queries
 
3023
        for(n = 0; n < s->queries->count; ++n)
 
3024
        {
 
3025
                query_t *q = (query_t *)s->queries->item[n];
 
3026
 
 
3027
                // issue the query
 
3028
                mdnsd_query(s->mdns, (char *)q->qname, q->qtype, _multicast_query_ans, s);
 
3029
        }
 
3030
}
 
3031
 
 
3032
int jdns_step_multicast(jdns_session_t *s, int now)
 
3033
{
 
3034
        int need_read, need_write, smallest_time;
 
3035
        struct mytimeval *tv;
 
3036
        jdns_packet_t *packet;
 
3037
        int flags;
 
3038
 
 
3039
        // not used
 
3040
        (void)now;
 
3041
 
 
3042
        need_read = 0;
 
3043
        need_write = 0;
 
3044
 
 
3045
        if(s->shutdown == 1)
 
3046
                mdnsd_shutdown(s->mdns);
 
3047
 
 
3048
        while(1)
 
3049
        {
 
3050
                jdns_address_t *addr;
 
3051
                unsigned short int port;
 
3052
                int ret;
 
3053
                unsigned char *buf;
 
3054
                int buf_len;
 
3055
 
 
3056
                if(!mdnsd_out(s->mdns, &packet, &addr, &port))
 
3057
                        break;
 
3058
 
 
3059
                if(!s->handle_writable)
 
3060
                {
 
3061
                        need_write = 1;
 
3062
                        jdns_address_delete(addr);
 
3063
                        break;
 
3064
                }
 
3065
 
 
3066
                if(!jdns_packet_export(packet, JDNS_UDP_MUL_OUT_MAX))
 
3067
                {
 
3068
                        _debug_line(s, "outgoing packet export error, not sending");
 
3069
                        jdns_packet_delete(packet);
 
3070
                        continue;
 
3071
                }
 
3072
 
 
3073
                buf = packet->raw_data;
 
3074
                buf_len = packet->raw_size;
 
3075
 
 
3076
                // multicast
 
3077
                if(!addr)
 
3078
                {
 
3079
                        addr = jdns_address_copy(s->maddr);
 
3080
                        port = s->port;
 
3081
                }
 
3082
 
 
3083
                _debug_line(s, "SEND %s:%d (size=%d)", addr->c_str, port, buf_len);
 
3084
                _print_hexdump(s, buf, buf_len);
 
3085
 
 
3086
                ret = s->cb.udp_write(s, s->cb.app, s->handle, addr, port, buf, buf_len);
 
3087
 
 
3088
                jdns_address_delete(addr);
 
3089
                jdns_packet_delete(packet);
 
3090
 
 
3091
                // if we can't write the packet, oh well
 
3092
                if(ret == 0)
 
3093
                {
 
3094
                        s->handle_writable = 0;
 
3095
                        need_write = 1;
 
3096
                        break;
 
3097
                }
 
3098
        }
 
3099
 
 
3100
        if(s->shutdown == 1)
 
3101
        {
 
3102
                jdns_event_t *event = jdns_event_new();
 
3103
                event->type = JDNS_EVENT_SHUTDOWN;
 
3104
                _append_event(s, event);
 
3105
                s->shutdown = 2;
 
3106
                return 0;
 
3107
        }
 
3108
 
 
3109
        // let's always ask for reads, just so the user doesn't have to
 
3110
        //  worry about what should happen to incoming packets otherwise
 
3111
        need_read = 1;
 
3112
 
 
3113
        if(s->handle_readable)
 
3114
        {
 
3115
                while(1)
 
3116
                {
 
3117
                        unsigned char buf[JDNS_UDP_MUL_IN_MAX];
 
3118
                        int bufsize = JDNS_UDP_MUL_IN_MAX;
 
3119
                        int ret;
 
3120
                        jdns_address_t *addr;
 
3121
                        int port;
 
3122
                        jdns_response_t *r;
 
3123
 
 
3124
                        addr = jdns_address_new();
 
3125
                        ret = s->cb.udp_read(s, s->cb.app, s->handle, addr, &port, buf, &bufsize);
 
3126
 
 
3127
                        // no packet?
 
3128
                        if(ret == 0)
 
3129
                        {
 
3130
                                s->handle_readable = 0;
 
3131
                                jdns_address_delete(addr);
 
3132
                                break;
 
3133
                        }
 
3134
 
 
3135
                        _debug_line(s, "RECV %s:%d (size=%d)", addr->c_str, port, bufsize);
 
3136
                        _print_hexdump(s, buf, bufsize);
 
3137
 
 
3138
                        if(!jdns_packet_import(&packet, buf, bufsize))
 
3139
                        {
 
3140
                                _debug_line(s, "error parsing packet / too large");
 
3141
 
 
3142
                                jdns_address_delete(addr);
 
3143
                                continue;
 
3144
                        }
 
3145
 
 
3146
                        _print_packet(s, packet);
 
3147
 
 
3148
                        r = _packet2response(packet, 0, 0, 0x7fff);
 
3149
                        _print_records(s, r, 0);
 
3150
 
 
3151
                        mdnsd_in(s->mdns, packet, r, addr, (unsigned short)port);
 
3152
 
 
3153
                        jdns_address_delete(addr);
 
3154
                        jdns_packet_delete(packet);
 
3155
                        jdns_response_delete(r);
 
3156
                }
 
3157
        }
 
3158
 
 
3159
        tv = mdnsd_sleep(s->mdns);
 
3160
        smallest_time = tv->tv_sec * 1000 + tv->tv_usec / 1000;
 
3161
 
 
3162
        flags = 0;
 
3163
        if(smallest_time != -1)
 
3164
        {
 
3165
                flags |= JDNS_STEP_TIMER;
 
3166
                s->next_timer = smallest_time;
 
3167
 
 
3168
                // offset it a little bit, so that the user doesn't call
 
3169
                //  us too early, resulting in a no-op and another timer
 
3170
                //  of 1 millisecond.
 
3171
                s->next_timer += 2;
 
3172
        }
 
3173
        if(need_read || need_write)
 
3174
                flags |= JDNS_STEP_HANDLE;
 
3175
        return flags;
 
3176
}