~ubuntu-branches/ubuntu/oneiric/psi/oneiric

« back to all changes in this revision

Viewing changes to iris/src/jdns/jdns_mdnsd.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005       Jeremie Miller
 
3
 * Copyright (C) 2005,2006  Justin Karneges
 
4
 *
 
5
 * Permission is hereby granted, free of charge, to any person obtaining a
 
6
 * copy of this software and associated documentation files (the
 
7
 * "Software"), to deal in the Software without restriction, including
 
8
 * without limitation the rights to use, copy, modify, merge, publish,
 
9
 * distribute, sublicense, and/or sell copies of the Software, and to
 
10
 * permit persons to whom the Software is furnished to do so, subject to
 
11
 * the following conditions:
 
12
 *
 
13
 * The above copyright notice and this permission notice shall be included
 
14
 * in all copies or substantial portions of the Software.
 
15
 *
 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
17
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
18
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
19
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 
20
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
21
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
22
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
23
 */
 
24
 
 
25
#include "jdns_mdnsd.h"
 
26
 
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
 
 
30
#define QTYPE_A     JDNS_RTYPE_A
 
31
#define QTYPE_AAAA  JDNS_RTYPE_AAAA
 
32
#define QTYPE_MX    JDNS_RTYPE_MX
 
33
#define QTYPE_SRV   JDNS_RTYPE_SRV
 
34
#define QTYPE_CNAME JDNS_RTYPE_CNAME
 
35
#define QTYPE_PTR   JDNS_RTYPE_PTR
 
36
#define QTYPE_TXT   JDNS_RTYPE_TXT
 
37
#define QTYPE_HINFO JDNS_RTYPE_HINFO
 
38
#define QTYPE_NS    JDNS_RTYPE_NS
 
39
#define QTYPE_ANY   JDNS_RTYPE_ANY
 
40
 
 
41
// size of query/publish hashes
 
42
#define SPRIME 108
 
43
// size of cache hash
 
44
#define LPRIME 1009
 
45
// brute force garbage cleanup frequency, rarely needed (daily default)
 
46
#define GC 86400
 
47
 
 
48
// maximum number of items to cache.  if an attacker on the LAN advertises
 
49
//   a million services, we don't want to crash our program trying to collect
 
50
//   them all.  any dns records received beyond this max are ignored.  this
 
51
//   means the attacker would succeed in DoS'ing the multicast dns network,
 
52
//   but he wouldn't succeed in running our program out of memory.
 
53
#define MAX_CACHE 16384
 
54
 
 
55
#define bzero(p, size) memset(p, 0, size)
 
56
 
 
57
/* messy, but it's the best/simplest balance I can find at the moment
 
58
Some internal data types, and a few hashes: querys, answers, cached, and records (published, unique and shared)
 
59
Each type has different semantics for processing, both for timeouts, incoming, and outgoing I/O
 
60
They inter-relate too, like records affect the querys they are relevant to
 
61
Nice things about MDNS: we only publish once (and then ask asked), and only query once, then just expire records we've got cached
 
62
*/
 
63
 
 
64
struct query
 
65
{
 
66
    char *name;
 
67
    int type;
 
68
    unsigned long int nexttry;
 
69
    int tries;
 
70
    int (*answer)(mdnsda, void *);
 
71
    void *arg;
 
72
    struct query *next, *list;
 
73
};
 
74
 
 
75
struct unicast
 
76
{
 
77
    int id;
 
78
    char ipv6;
 
79
    unsigned long int to;
 
80
    unsigned char to6[16];
 
81
    unsigned short int port;
 
82
    mdnsdr r;
 
83
    struct unicast *next;
 
84
};
 
85
 
 
86
struct cached
 
87
{
 
88
    struct mdnsda_struct rr;
 
89
    struct query *q;
 
90
    struct cached *next;
 
91
};
 
92
 
 
93
struct mdnsdr_struct
 
94
{
 
95
    struct mdnsda_struct rr;
 
96
    char unique; // # of checks performed to ensure
 
97
    int tries;
 
98
    void (*pubresult)(int, char *, int, void *);
 
99
    void *arg;
 
100
    struct mdnsdr_struct *next, *list;
 
101
};
 
102
 
 
103
struct mdnsd_struct
 
104
{
 
105
    char shutdown;
 
106
    unsigned long int expireall, checkqlist;
 
107
    struct mytimeval now, sleep, pause, probe, publish;
 
108
    int class, frame;
 
109
    struct cached *cache[LPRIME];
 
110
    int cache_count;
 
111
    struct mdnsdr_struct *published[SPRIME], *probing, *a_now, *a_pause, *a_publish;
 
112
    struct unicast *uanswers;
 
113
    struct query *queries[SPRIME], *qlist;
 
114
    int (*cb_time_now)(struct mdnsd_struct *dp, void *arg);
 
115
    int (*cb_rand_int)(struct mdnsd_struct *dp, void *arg);
 
116
    void *cb_arg;
 
117
    int port;
 
118
};
 
119
 
 
120
void mygettimeofday(mdnsd d, struct mytimeval *tv)
 
121
{
 
122
    //struct timeval t;
 
123
    //gettimeofday(&t, 0);
 
124
    //tv->tv_sec = t.tv_sec;
 
125
    //tv->tv_usec = t.tv_usec;
 
126
 
 
127
    int msec = d->cb_time_now(d, d->cb_arg);
 
128
    tv->tv_sec = msec / 1000;
 
129
    tv->tv_usec = (msec % 1000) * 1000;
 
130
}
 
131
 
 
132
void query_free(struct query *q)
 
133
{
 
134
    jdns_free(q->name);
 
135
    jdns_free(q);
 
136
}
 
137
 
 
138
void mdnsda_content_free(struct mdnsda_struct *rr)
 
139
{
 
140
    if(rr->name)
 
141
        jdns_free(rr->name);
 
142
    if(rr->rdata)
 
143
        jdns_free(rr->rdata);
 
144
    if(rr->rdname)
 
145
        jdns_free(rr->rdname);
 
146
}
 
147
 
 
148
int _namehash(const char *s)
 
149
{
 
150
    const unsigned char *name = (const unsigned char *)s;
 
151
    unsigned long h = 0, g;
 
152
 
 
153
    while (*name)
 
154
    { /* do some fancy bitwanking on the string */
 
155
        h = (h << 4) + (unsigned long)(*name++);
 
156
        if ((g = (h & 0xF0000000UL))!=0)
 
157
            h ^= (g >> 24);
 
158
        h &= ~g;
 
159
    }
 
160
 
 
161
    return (int)h;
 
162
}
 
163
 
 
164
// case-insensitive hash
 
165
int _namehash_nocase(const char *s)
 
166
{
 
167
    int n, len;
 
168
    char *low = jdns_strdup(s);
 
169
    len = strlen(low);
 
170
    for(n = 0; n < len; ++n)
 
171
        low[n] = tolower(low[n]);
 
172
    n = _namehash(low);
 
173
    jdns_free(low);
 
174
    return n;
 
175
}
 
176
 
 
177
// basic linked list and hash primitives
 
178
struct query *_q_next(mdnsd d, struct query *q, char *host, int type)
 
179
{
 
180
    if(q == 0) q = d->queries[_namehash_nocase(host) % SPRIME];
 
181
    else q = q->next;
 
182
    for(;q != 0; q = q->next)
 
183
        if(q->type == type && jdns_domain_cmp((unsigned char *)q->name, (unsigned char *)host))
 
184
            return q;
 
185
    return 0;
 
186
}
 
187
struct cached *_c_next(mdnsd d, struct cached *c, char *host, int type)
 
188
{
 
189
    if(c == 0) c = d->cache[_namehash_nocase(host) % LPRIME];
 
190
    else c = c->next;
 
191
    for(;c != 0; c = c->next)
 
192
        if((type == c->rr.type || type == 255) && jdns_domain_cmp(c->rr.name, (unsigned char *)host))
 
193
            return c;
 
194
    return 0;
 
195
}
 
196
mdnsdr _r_next(mdnsd d, mdnsdr r, char *host, int type)
 
197
{
 
198
    if(r == 0) r = d->published[_namehash_nocase(host) % SPRIME];
 
199
    else r = r->next;
 
200
    for(;r != 0; r = r->next)
 
201
        if(type == r->rr.type && jdns_domain_cmp(r->rr.name, (unsigned char *)host))
 
202
            return r;
 
203
    return 0;
 
204
}
 
205
 
 
206
/*
 
207
int _rr_len(mdnsda rr)
 
208
{
 
209
    int len = 12; // name is always compressed (dup of earlier), plus normal stuff
 
210
    if(rr->rdata) len += rr->rdlen;
 
211
    if(rr->rdname) len += strlen((char *)rr->rdname); // worst case
 
212
    if(rr->ip) len += 4;
 
213
    if(rr->type == QTYPE_PTR) len += 6; // srv record stuff
 
214
    return len;
 
215
}
 
216
*/
 
217
 
 
218
/*
 
219
int _a_match(struct resource *r, mdnsda a)
 
220
{ // compares new rdata with known a, painfully
 
221
    if(strcmp((char *)r->name,(char *)a->name) || r->type != a->type) return 0;
 
222
    if(r->type == QTYPE_SRV && !strcmp((char *)r->known.srv.name,(char *)a->rdname) && a->srv.port == r->known.srv.port && a->srv.weight == r->known.srv.weight && a->srv.priority == r->known.srv.priority) return 1;
 
223
    if((r->type == QTYPE_PTR || r->type == QTYPE_NS || r->type == QTYPE_CNAME) && !strcmp((char *)a->rdname,(char *)r->known.ns.name)) return 1;
 
224
    if(r->rdlength == a->rdlen && !memcmp(r->rdata,a->rdata,r->rdlength)) return 1;
 
225
    return 0;
 
226
}
 
227
*/
 
228
 
 
229
int _a_match(const jdns_rr_t *r, mdnsda a)
 
230
{
 
231
    if(r->type != a->type || !jdns_domain_cmp(r->owner, a->name))
 
232
        return 0;
 
233
    if(r->type == JDNS_RTYPE_SRV)
 
234
    {
 
235
        if(jdns_domain_cmp(r->data.server->name, a->rdname)
 
236
            && r->data.server->port == a->srv.port
 
237
            && r->data.server->priority == a->srv.priority
 
238
            && r->data.server->weight == a->srv.weight
 
239
        )
 
240
            return 1;
 
241
    }
 
242
    else if(r->type == JDNS_RTYPE_PTR || r->type == JDNS_RTYPE_NS || r->type == JDNS_RTYPE_CNAME)
 
243
    {
 
244
        if(jdns_domain_cmp(r->data.name, a->rdname))
 
245
            return 1;
 
246
    }
 
247
    else if(r->rdlength == a->rdlen && !memcmp(r->rdata, a->rdata, r->rdlength))
 
248
        return 1;
 
249
 
 
250
    return 0;
 
251
}
 
252
 
 
253
// compare time values easily
 
254
int _tvdiff(struct mytimeval old, struct mytimeval new)
 
255
{
 
256
    int udiff = 0;
 
257
    if(old.tv_sec != new.tv_sec) udiff = (new.tv_sec - old.tv_sec) * 1000000;
 
258
    return (new.tv_usec - old.tv_usec) + udiff;
 
259
}
 
260
 
 
261
// make sure not already on the list, then insert
 
262
void _r_push(mdnsdr *list, mdnsdr r)
 
263
{
 
264
    mdnsdr cur;
 
265
    for(cur = *list; cur != 0; cur = cur->list)
 
266
        if(cur == r) return;
 
267
    r->list = *list;
 
268
    *list = r;
 
269
}
 
270
 
 
271
// set this r to probing, set next probe time
 
272
void _r_probe(mdnsd d, mdnsdr r)
 
273
{
 
274
    (void)d;
 
275
    (void)r;
 
276
}
 
277
 
 
278
// force any r out right away, if valid
 
279
void _r_publish(mdnsd d, mdnsdr r)
 
280
{
 
281
    if(r->unique && r->unique < 5) return; // probing already
 
282
    r->tries = 0;
 
283
    d->publish.tv_sec = d->now.tv_sec; d->publish.tv_usec = d->now.tv_usec;
 
284
    _r_push(&d->a_publish,r);
 
285
}
 
286
 
 
287
// send r out asap
 
288
void _r_send(mdnsd d, mdnsdr r)
 
289
{
 
290
    // removing record
 
291
    if(r->rr.ttl == 0)
 
292
    {
 
293
        if(d->a_publish == r)
 
294
            d->a_publish = r->list;
 
295
        _r_push(&d->a_now, r);
 
296
        return;
 
297
    }
 
298
 
 
299
    if(r->tries < 4)
 
300
    { // being published, make sure that happens soon
 
301
        d->publish.tv_sec = d->now.tv_sec; d->publish.tv_usec = d->now.tv_usec;
 
302
        return;
 
303
    }
 
304
    if(r->unique)
 
305
    { // known unique ones can be sent asap
 
306
        _r_push(&d->a_now,r);
 
307
        return;
 
308
    }
 
309
    // set d->pause.tv_usec to random 20-120 msec
 
310
    d->pause.tv_sec = d->now.tv_sec;
 
311
    //d->pause.tv_usec = d->now.tv_usec + ((d->now.tv_usec % 100) + 20) * 1000;
 
312
    d->pause.tv_usec = d->now.tv_usec;
 
313
    d->pause.tv_usec += ((d->cb_rand_int(d, d->cb_arg) % 100) + 20) * 1000;
 
314
    _r_push(&d->a_pause,r);
 
315
}
 
316
 
 
317
// create generic unicast response struct
 
318
void _u_push(mdnsd d, mdnsdr r, int id, const jdns_address_t *addr, unsigned short int port)
 
319
{
 
320
    struct unicast *u;
 
321
    u = (struct unicast *)jdns_alloc(sizeof(struct unicast));
 
322
    bzero(u,sizeof(struct unicast));
 
323
    u->r = r;
 
324
    u->id = id;
 
325
    if(addr->isIpv6)
 
326
    {
 
327
        u->ipv6 = 1;
 
328
        memcpy(u->to6, addr->addr.v6, 16);
 
329
    }
 
330
    else
 
331
    {
 
332
        u->ipv6 = 0;
 
333
        u->to = addr->addr.v4;
 
334
    }
 
335
    u->port = port;
 
336
    u->next = d->uanswers;
 
337
    d->uanswers = u;
 
338
}
 
339
 
 
340
void _q_reset(mdnsd d, struct query *q)
 
341
{
 
342
    struct cached *cur = 0;
 
343
    q->nexttry = 0;
 
344
    q->tries = 0;
 
345
    while((cur = _c_next(d,cur,q->name,q->type)))
 
346
        if(q->nexttry == 0 || cur->rr.ttl - 7 < q->nexttry) q->nexttry = cur->rr.ttl - 7;
 
347
    if(q->nexttry != 0 && q->nexttry < d->checkqlist) d->checkqlist = q->nexttry;
 
348
}
 
349
 
 
350
void _q_done(mdnsd d, struct query *q)
 
351
{ // no more query, update all it's cached entries, remove from lists
 
352
    struct cached *c = 0;
 
353
    struct query *cur;
 
354
    int i = _namehash_nocase(q->name) % SPRIME;
 
355
    while((c = _c_next(d,c,q->name,q->type))) c->q = 0;
 
356
    if(d->qlist == q) d->qlist = q->list;
 
357
    else {
 
358
        for(cur=d->qlist;cur->list != q;cur = cur->list);
 
359
        cur->list = q->list;
 
360
    }
 
361
    if(d->queries[i] == q) d->queries[i] = q->next;
 
362
    else {
 
363
        for(cur=d->queries[i];cur->next != q;cur = cur->next);
 
364
        cur->next = q->next;
 
365
    }
 
366
    query_free(q);
 
367
}
 
368
 
 
369
void _r_done(mdnsd d, mdnsdr r)
 
370
{ // buh-bye, remove from hash and free
 
371
    mdnsdr cur = 0;
 
372
    int i = _namehash_nocase((char *)r->rr.name) % SPRIME;
 
373
    if(d->a_now == r)
 
374
        d->a_now = r->list;
 
375
    if(d->a_pause == r)
 
376
        d->a_pause = r->list;
 
377
    if(d->a_publish == r)
 
378
        d->a_publish = r->list;
 
379
    if(d->published[i] == r) d->published[i] = r->next;
 
380
    else {
 
381
        for(cur=d->published[i];cur && cur->next != r;cur = cur->next);
 
382
        if(cur) cur->next = r->next;
 
383
    }
 
384
    mdnsda_content_free(&r->rr);
 
385
    jdns_free(r);
 
386
}
 
387
 
 
388
void _q_answer(mdnsd d, struct cached *c)
 
389
{ // call the answer function with this cached entry
 
390
    if(c->rr.ttl <= d->now.tv_sec) c->rr.ttl = 0;
 
391
    if(c->q->answer(&c->rr,c->q->arg) == -1) _q_done(d, c->q);
 
392
}
 
393
 
 
394
void _conflict(mdnsd d, mdnsdr r)
 
395
{
 
396
    r->pubresult(0, (char *)r->rr.name,r->rr.type,r->arg);
 
397
    mdnsd_done(d,r);
 
398
}
 
399
 
 
400
void _published(mdnsd d, mdnsdr r)
 
401
{
 
402
    (void)d;
 
403
    r->pubresult(1, (char *)r->rr.name,r->rr.type,r->arg);
 
404
}
 
405
 
 
406
void _c_expire(mdnsd d, struct cached **list)
 
407
{ // expire any old entries in this list
 
408
    struct cached *next, *cur = *list, *last = 0;
 
409
    while(cur != 0)
 
410
    {
 
411
        next = cur->next;
 
412
        if(d->now.tv_sec >= cur->rr.ttl)
 
413
        {
 
414
            if(last) last->next = next;
 
415
            if(*list == cur) *list = next; // update list pointer if the first one expired
 
416
            --(d->cache_count);
 
417
            if(cur->q) _q_answer(d,cur);
 
418
            mdnsda_content_free(&cur->rr);
 
419
            jdns_free(cur);
 
420
        }else{
 
421
            last = cur;
 
422
        }
 
423
        cur = next;
 
424
    }
 
425
}
 
426
 
 
427
// brute force expire any old cached records
 
428
void _gc(mdnsd d)
 
429
{
 
430
    int i;
 
431
    for(i=0;i<LPRIME;i++)
 
432
        if(d->cache[i]) _c_expire(d,&d->cache[i]);
 
433
    d->expireall = d->now.tv_sec + GC;
 
434
}
 
435
 
 
436
struct cached *_find_exact(mdnsd d, const jdns_rr_t *r)
 
437
{
 
438
    struct cached *c = 0;
 
439
    while(1)
 
440
    {
 
441
        c = _c_next(d, c, (char *)r->owner, r->type);
 
442
        if(!c)
 
443
            break;
 
444
        if(_a_match(r, &c->rr))
 
445
            return c;
 
446
    }
 
447
    return 0;
 
448
}
 
449
 
 
450
void _cache(mdnsd d, const jdns_rr_t *r)
 
451
{
 
452
    struct cached *c;
 
453
    int i = _namehash_nocase((char *)r->owner) % LPRIME;
 
454
    struct cached *same_value;
 
455
 
 
456
    // do we already have it?
 
457
    //printf("cache: checking for entry: [%s] [%d]\n", r->owner, r->type);
 
458
    same_value = _find_exact(d, r);
 
459
    if(same_value)
 
460
    {
 
461
        //printf("already have entry of same value\n");
 
462
    }
 
463
 
 
464
    if(r->qclass == 32768 + d->class)
 
465
    { // cache flush
 
466
        // simulate removal of all records for this question,
 
467
        //   except if the value hasn't changed
 
468
        c = 0;
 
469
        while((c = _c_next(d,c,(char *)r->owner,r->type)))
 
470
        {
 
471
            if(c != same_value)
 
472
                c->rr.ttl = 0;
 
473
        }
 
474
        _c_expire(d,&d->cache[i]);
 
475
 
 
476
        // we may have expired same_value here, so check for it again
 
477
        same_value = _find_exact(d, r);
 
478
    }
 
479
 
 
480
    if(r->ttl == 0)
 
481
    { // process deletes
 
482
        if(same_value)
 
483
            same_value->rr.ttl = 0;
 
484
        _c_expire(d,&d->cache[i]);
 
485
        return;
 
486
    }
 
487
 
 
488
    if(same_value)
 
489
    {
 
490
        //printf("updating ttl only\n");
 
491
 
 
492
        // only update ttl (this code directly copied from below)
 
493
        same_value->rr.ttl = d->now.tv_sec + (r->ttl / 2) + 8;
 
494
        same_value->rr.real_ttl = r->ttl;
 
495
        return;
 
496
    }
 
497
 
 
498
    //printf("cache: inserting entry:    [%s] [%d]\n", r->owner, r->type);
 
499
    if(d->cache_count >= MAX_CACHE)
 
500
        return;
 
501
 
 
502
    c = (struct cached *)jdns_alloc(sizeof(struct cached));
 
503
    bzero(c,sizeof(struct cached));
 
504
    c->rr.name = (unsigned char *)jdns_strdup((char *)r->owner);
 
505
    c->rr.type = r->type;
 
506
    c->rr.ttl = d->now.tv_sec + (r->ttl / 2) + 8; // XXX hack for now, BAD SPEC, start retrying just after half-waypoint, then expire
 
507
    c->rr.real_ttl = r->ttl;
 
508
    c->rr.rdlen = r->rdlength;
 
509
    c->rr.rdata = jdns_copy_array(r->rdata, r->rdlength);
 
510
    switch(r->type)
 
511
    {
 
512
    case QTYPE_A:
 
513
        c->rr.ip = r->data.address->addr.v4;
 
514
        break;
 
515
    case QTYPE_NS:
 
516
    case QTYPE_CNAME:
 
517
    case QTYPE_PTR:
 
518
        c->rr.rdname = (unsigned char *)jdns_strdup((const char *)r->data.name);
 
519
        break;
 
520
    case QTYPE_SRV:
 
521
        c->rr.rdname = (unsigned char *)jdns_strdup((const char *)r->data.server->name);
 
522
        c->rr.srv.port = r->data.server->port;
 
523
        c->rr.srv.weight = r->data.server->weight;
 
524
        c->rr.srv.priority = r->data.server->priority;
 
525
        break;
 
526
    }
 
527
    c->next = d->cache[i];
 
528
    d->cache[i] = c;
 
529
    if((c->q = _q_next(d, 0, (char *)r->owner, r->type)))
 
530
        _q_answer(d,c);
 
531
    if(c->q && c->q->nexttry == 0)
 
532
    {
 
533
        //printf("cache insert, but nexttry == 0\n");
 
534
        _q_reset(d,c->q);
 
535
        if(d->checkqlist == 0)
 
536
            d->checkqlist = c->q->nexttry;
 
537
        //printf("after reset: q->nexttry=%d d->checkqlist=%d\n", c->q->nexttry, d->checkqlist);
 
538
    }
 
539
}
 
540
 
 
541
/*
 
542
void _a_copy(struct message *m, mdnsda a)
 
543
{ // copy the data bits only
 
544
    if(a->rdata) { message_rdata_raw(m, a->rdata, a->rdlen); return; }
 
545
    if(a->ip) message_rdata_long(m, a->ip);
 
546
    if(a->type == QTYPE_SRV) message_rdata_srv(m, a->srv.priority, a->srv.weight, a->srv.port, a->rdname);
 
547
    else if(a->rdname) message_rdata_name(m, a->rdname);
 
548
}
 
549
*/
 
550
 
 
551
void _a_copyq(jdns_list_t *dest, unsigned char *name, unsigned short type, unsigned short class)
 
552
{
 
553
    jdns_packet_question_t *q = jdns_packet_question_new();
 
554
    q->qname = jdns_string_new();
 
555
    jdns_string_set_cstr(q->qname, (char *)name);
 
556
    q->qtype = type;
 
557
    q->qclass = class;
 
558
    jdns_list_insert(dest, q, -1);
 
559
    jdns_packet_question_delete(q);
 
560
}
 
561
 
 
562
void _a_copy(jdns_list_t *dest, unsigned char *name, unsigned short type, unsigned short class, unsigned long int ttl, mdnsda a)
 
563
{
 
564
    jdns_packet_resource_t *r = jdns_packet_resource_new();
 
565
    r->qname = jdns_string_new();
 
566
    jdns_string_set_cstr(r->qname, (char *)name);
 
567
    r->qtype = type;
 
568
    r->qclass = class;
 
569
    r->ttl = ttl;
 
570
    if(a->rdata)
 
571
        jdns_packet_resource_add_bytes(r, a->rdata, a->rdlen);
 
572
    else if(a->ip)
 
573
    {
 
574
        unsigned long int ip;
 
575
        ip = htonl(a->ip);
 
576
        jdns_packet_resource_add_bytes(r, (unsigned char *)&ip, 4);
 
577
    }
 
578
    else if(a->type == QTYPE_SRV)
 
579
    {
 
580
        unsigned short priority, weight, port;
 
581
        jdns_string_t *name;
 
582
        priority = htons(a->srv.priority);
 
583
        weight = htons(a->srv.weight);
 
584
        port = htons(a->srv.port);
 
585
        name = jdns_string_new();
 
586
        jdns_string_set_cstr(name, (const char *)a->rdname);
 
587
        jdns_packet_resource_add_bytes(r, (unsigned char *)&priority, 2);
 
588
        jdns_packet_resource_add_bytes(r, (unsigned char *)&weight, 2);
 
589
        jdns_packet_resource_add_bytes(r, (unsigned char *)&port, 2);
 
590
        jdns_packet_resource_add_name(r, name);
 
591
        jdns_string_delete(name);
 
592
    }
 
593
    else if(a->rdname)
 
594
    {
 
595
        jdns_string_t *name;
 
596
        name = jdns_string_new();
 
597
        jdns_string_set_cstr(name, (const char *)a->rdname);
 
598
        jdns_packet_resource_add_name(r, name);
 
599
        jdns_string_delete(name);
 
600
    }
 
601
    jdns_list_insert(dest, r, -1);
 
602
    jdns_packet_resource_delete(r);
 
603
}
 
604
 
 
605
/*
 
606
int _r_out(mdnsd d, struct message *m, mdnsdr *list)
 
607
{ // copy a published record into an outgoing message
 
608
    mdnsdr r; //, next;
 
609
    int ret = 0;
 
610
    while((r = *list) != 0 && message_packet_len(m) + _rr_len(&r->rr) < d->frame)
 
611
    {
 
612
        *list = r->list;
 
613
        ret++;
 
614
        if(r->unique)
 
615
            message_an(m, r->rr.name, r->rr.type, (unsigned short)(d->class + 32768), r->rr.ttl);
 
616
        else
 
617
            message_an(m, r->rr.name, r->rr.type, (unsigned short)d->class, r->rr.ttl);
 
618
        _a_copy(m, &r->rr);
 
619
        if(r->rr.ttl == 0) _r_done(d,r);
 
620
    }
 
621
    return ret;
 
622
}
 
623
*/
 
624
 
 
625
int _r_out(mdnsd d, jdns_packet_t *m, mdnsdr *list)
 
626
{ // copy a published record into an outgoing message
 
627
    mdnsdr r; //, next;
 
628
    unsigned short class;
 
629
    int ret = 0;
 
630
    while((r = *list) != 0)
 
631
    {
 
632
        *list = r->list;
 
633
        ret++;
 
634
        class = r->unique ? d->class | 0x8000 : d->class;
 
635
        _a_copy(m->answerRecords, r->rr.name, r->rr.type, class, r->rr.ttl, &r->rr);
 
636
        if(r->rr.ttl == 0) _r_done(d,r);
 
637
    }
 
638
    return ret;
 
639
}
 
640
 
 
641
 
 
642
mdnsd mdnsd_new(int class, int frame, int port, int (*time_now)(mdnsd d, void *arg), int (*rand_int)(mdnsd d, void *arg), void *arg)
 
643
{
 
644
    //int i;
 
645
    mdnsd d;
 
646
    d = (mdnsd)jdns_alloc(sizeof(struct mdnsd_struct));
 
647
    bzero(d,sizeof(struct mdnsd_struct));
 
648
    d->cb_time_now = time_now;
 
649
    d->cb_rand_int = rand_int;
 
650
    d->cb_arg = arg;
 
651
    mygettimeofday(d, &d->now);
 
652
    d->expireall = d->now.tv_sec + GC;
 
653
    d->class = class;
 
654
    d->frame = frame;
 
655
    d->cache_count = 0;
 
656
    d->port = port;
 
657
    return d;
 
658
}
 
659
 
 
660
void mdnsd_shutdown(mdnsd d)
 
661
{ // shutting down, zero out ttl and push out all records
 
662
    int i;
 
663
    mdnsdr cur,next;
 
664
    d->a_now = 0;
 
665
    for(i=0;i<SPRIME;i++)
 
666
        for(cur = d->published[i]; cur != 0;)
 
667
        {
 
668
            next = cur->next;
 
669
            cur->rr.ttl = 0;
 
670
            cur->list = d->a_now;
 
671
            d->a_now = cur;
 
672
            cur = next;
 
673
        }
 
674
    d->shutdown = 1;
 
675
}
 
676
 
 
677
void mdnsd_flush(mdnsd d)
 
678
{
 
679
    // set all querys to 0 tries
 
680
    // free whole cache
 
681
    // set all mdnsdr to probing
 
682
    // reset all answer lists
 
683
 
 
684
    (void)d;
 
685
}
 
686
 
 
687
void mdnsd_free(mdnsd d)
 
688
{
 
689
    int i;
 
690
 
 
691
    // loop through all hashes, free everything
 
692
    // free answers if any
 
693
 
 
694
    for(i = 0; i < LPRIME; ++i)
 
695
    {
 
696
        while(d->cache[i])
 
697
        {
 
698
            struct cached *cur = d->cache[i];
 
699
            d->cache[i] = cur->next;
 
700
            mdnsda_content_free(&cur->rr);
 
701
            jdns_free(cur);
 
702
        }
 
703
    }
 
704
 
 
705
    for(i = 0; i < SPRIME; ++i)
 
706
    {
 
707
        while(d->published[i])
 
708
        {
 
709
            struct mdnsdr_struct *cur = d->published[i];
 
710
            d->published[i] = cur->next;
 
711
            mdnsda_content_free(&cur->rr);
 
712
            jdns_free(cur);
 
713
        }
 
714
    }
 
715
 
 
716
    while(d->uanswers)
 
717
    {
 
718
        struct unicast *u = d->uanswers;
 
719
        d->uanswers = u->next;
 
720
        jdns_free(u);
 
721
    }
 
722
 
 
723
    for(i = 0; i < SPRIME; ++i)
 
724
    {
 
725
        while(d->queries[i])
 
726
        {
 
727
            struct query *cur = d->queries[i];
 
728
            d->queries[i] = cur->next;
 
729
            query_free(cur);
 
730
        }
 
731
    }
 
732
 
 
733
    jdns_free(d);
 
734
}
 
735
 
 
736
void mdnsd_in(mdnsd d, const jdns_packet_t *m, const jdns_response_t *resp, const jdns_address_t *addr, unsigned short int port)
 
737
{
 
738
    int i, j;
 
739
    mdnsdr r = 0;
 
740
 
 
741
    if(d->shutdown) return;
 
742
 
 
743
    mygettimeofday(d, &d->now);
 
744
 
 
745
    if(m->opts.qr == 0)
 
746
    {
 
747
        for(i=0;i<m->questions->count;i++)
 
748
        { // process each query
 
749
            jdns_packet_question_t *pq = (jdns_packet_question_t *)m->questions->item[i];
 
750
 
 
751
            if(pq->qclass != d->class || (r = _r_next(d,0,(char *)pq->qname->data,pq->qtype)) == 0) continue;
 
752
 
 
753
            // send the matching unicast reply
 
754
            if(port != d->port) _u_push(d,r,m->id,addr,port);
 
755
 
 
756
            for(;r != 0; r = _r_next(d,r,(char *)pq->qname->data,pq->qtype))
 
757
            { // check all of our potential answers
 
758
                if(r->unique && r->unique < 5)
 
759
                { // probing state, check for conflicts
 
760
                    for(j=0;j<resp->authorityCount;j++)
 
761
                    { // check all to-be answers against our own
 
762
                        jdns_rr_t *ns = resp->authorityRecords[j];
 
763
                        if(pq->qtype != ns->type || !jdns_domain_cmp(pq->qname->data, ns->owner)) continue;
 
764
                        if(!_a_match(ns,&r->rr))
 
765
                        {
 
766
                            _conflict(d,r); // answer isn't ours, conflict!
 
767
 
 
768
                            // r is invalid after conflict, start all over
 
769
                            r = 0;
 
770
                            break;
 
771
                        }
 
772
                    }
 
773
                    continue;
 
774
                }
 
775
                for(j=0;j<resp->answerCount;j++)
 
776
                { // check the known answers for this question
 
777
                    jdns_rr_t *an = resp->answerRecords[j];
 
778
                    if(pq->qtype != an->type || !jdns_domain_cmp(pq->qname->data, an->owner)) continue;
 
779
                    if(_a_match(an,&r->rr)) break; // they already have this answer
 
780
                }
 
781
                if(j == resp->answerCount) _r_send(d,r);
 
782
            }
 
783
        }
 
784
        return;
 
785
    }
 
786
 
 
787
    for(i=0;i<resp->answerCount;i++)
 
788
    { // process each answer, check for a conflict, and cache
 
789
        jdns_rr_t *an = resp->answerRecords[i];
 
790
        if((r = _r_next(d,0,(char *)an->owner,an->type)) != 0 && r->unique && _a_match(an,&r->rr) == 0) _conflict(d,r);
 
791
        _cache(d,an);
 
792
    }
 
793
 
 
794
    // cache additional records
 
795
    for(i=0;i<resp->additionalCount;i++)
 
796
    {
 
797
        jdns_rr_t *an = resp->additionalRecords[i];
 
798
        _cache(d,an);
 
799
    }
 
800
}
 
801
 
 
802
int mdnsd_out(mdnsd d, jdns_packet_t **_m, jdns_address_t **addr, unsigned short int *port)
 
803
{
 
804
    mdnsdr r;
 
805
    int ret = 0;
 
806
    jdns_packet_t *m;
 
807
 
 
808
    mygettimeofday(d, &d->now);
 
809
    //bzero(m,sizeof(struct message));
 
810
    m = jdns_packet_new();
 
811
 
 
812
    // defaults, multicast
 
813
    *port = 0; //htons(5353);
 
814
    *addr = 0;
 
815
    // *ip = 0; //inet_addr("224.0.0.251");
 
816
    m->opts.qr = 1;
 
817
    m->opts.aa = 1;
 
818
 
 
819
    if(d->uanswers)
 
820
    { // send out individual unicast answers
 
821
        struct unicast *u = d->uanswers;
 
822
        d->uanswers = u->next;
 
823
        *port = u->port;
 
824
        // *ip = u->to;
 
825
        *addr = jdns_address_new();
 
826
        if(u->ipv6)
 
827
            jdns_address_set_ipv6(*addr, u->to6);
 
828
        else
 
829
            jdns_address_set_ipv4(*addr, u->to);
 
830
        m->id = u->id;
 
831
        _a_copyq(m->questions, u->r->rr.name, u->r->rr.type, (unsigned short)d->class);
 
832
        _a_copy(m->answerRecords, u->r->rr.name, u->r->rr.type, (unsigned short)d->class, u->r->rr.ttl, &u->r->rr);
 
833
        jdns_free(u);
 
834
        ret = 1;
 
835
        goto end;
 
836
    }
 
837
 
 
838
//printf("OUT: probing %X now %X pause %X publish %X\n",d->probing,d->a_now,d->a_pause,d->a_publish);
 
839
 
 
840
    // accumulate any immediate responses
 
841
    if(d->a_now) { ret += _r_out(d, m, &d->a_now); }
 
842
 
 
843
    if(d->a_publish && _tvdiff(d->now,d->publish) <= 0)
 
844
    { // check to see if it's time to send the publish retries (and unlink if done)
 
845
        mdnsdr next, cur = d->a_publish, last = 0;
 
846
        unsigned short class;
 
847
        while(cur /*&& message_packet_len(m) + _rr_len(&cur->rr) < d->frame*/ )
 
848
        {
 
849
            next = cur->list;
 
850
            ret++; cur->tries++;
 
851
            class = cur->unique ? d->class | 0x8000 : d->class;
 
852
            _a_copy(m->answerRecords, cur->rr.name, cur->rr.type, class, cur->rr.ttl, &cur->rr);
 
853
 
 
854
            if(cur->rr.ttl != 0 && cur->tries < 4)
 
855
            {
 
856
                last = cur;
 
857
                cur = next;
 
858
                continue;
 
859
            }
 
860
            if(d->a_publish == cur) d->a_publish = next;
 
861
            if(last) last->list = next;
 
862
            if(cur->rr.ttl == 0) _r_done(d,cur);
 
863
            cur = next;
 
864
        }
 
865
        if(d->a_publish)
 
866
        {
 
867
            d->publish.tv_sec = d->now.tv_sec + 2;
 
868
            d->publish.tv_usec = d->now.tv_usec;
 
869
        }
 
870
    }
 
871
 
 
872
    // if we're in shutdown, we're done
 
873
    if(d->shutdown)
 
874
        goto end;
 
875
 
 
876
    // check if a_pause is ready
 
877
    if(d->a_pause && _tvdiff(d->now, d->pause) <= 0) ret += _r_out(d, m, &d->a_pause);
 
878
 
 
879
    // now process questions
 
880
    if(ret)
 
881
        goto end;
 
882
    m->opts.qr = 0;
 
883
    m->opts.aa = 0;
 
884
 
 
885
    if(d->probing && _tvdiff(d->now,d->probe) <= 0)
 
886
    {
 
887
        mdnsdr last = 0;
 
888
        for(r = d->probing; r != 0;)
 
889
        { // scan probe list to ask questions and process published
 
890
            if(r->unique == 4)
 
891
            { // done probing, publish
 
892
                mdnsdr next = r->list;
 
893
                if(d->probing == r)
 
894
                    d->probing = r->list;
 
895
                else
 
896
                    last->list = r->list;
 
897
                r->list = 0;
 
898
                r->unique = 5;
 
899
                _r_publish(d,r);
 
900
                _published(d,r);
 
901
                r = next;
 
902
                continue;
 
903
            }
 
904
            //message_qd(m, r->rr.name, r->rr.type, (unsigned short)d->class);
 
905
            _a_copyq(m->questions, r->rr.name, r->rr.type, (unsigned short)d->class);
 
906
            last = r;
 
907
            r = r->list;
 
908
        }
 
909
        for(r = d->probing; r != 0; last = r, r = r->list)
 
910
        { // scan probe list again to append our to-be answers
 
911
            r->unique++;
 
912
            _a_copy(m->authorityRecords, r->rr.name, r->rr.type, (unsigned short)d->class, r->rr.ttl, &r->rr);
 
913
            ret++;
 
914
        }
 
915
        if(ret)
 
916
        { // process probes again in the future
 
917
            d->probe.tv_sec = d->now.tv_sec;
 
918
            d->probe.tv_usec = d->now.tv_usec + 250000;
 
919
            goto end;
 
920
        }
 
921
    }
 
922
 
 
923
    if(d->checkqlist && d->now.tv_sec >= d->checkqlist)
 
924
    { // process qlist for retries or expirations
 
925
        struct query *q;
 
926
        struct cached *c;
 
927
        unsigned long int nextbest = 0;
 
928
 
 
929
        // ask questions first, track nextbest time
 
930
        for(q = d->qlist; q != 0; q = q->list)
 
931
            if(q->nexttry > 0 && q->nexttry <= d->now.tv_sec && q->tries < 3)
 
932
                _a_copyq(m->questions, (unsigned char *)q->name, (unsigned short)q->type, (unsigned short)d->class);
 
933
            else if(q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest))
 
934
                nextbest = q->nexttry;
 
935
 
 
936
        // include known answers, update questions
 
937
        for(q = d->qlist; q != 0; q = q->list)
 
938
        {
 
939
            if(q->nexttry == 0 || q->nexttry > d->now.tv_sec) continue;
 
940
            if(q->tries == 3)
 
941
            { // done retrying, expire and reset
 
942
                _c_expire(d,&d->cache[_namehash_nocase(q->name) % LPRIME]);
 
943
                _q_reset(d,q);
 
944
                continue;
 
945
            }
 
946
            ret++;
 
947
            q->nexttry = d->now.tv_sec + ++q->tries;
 
948
            if(nextbest == 0 || q->nexttry < nextbest)
 
949
                nextbest = q->nexttry;
 
950
            // if room, add all known good entries
 
951
            c = 0;
 
952
            while((c = _c_next(d,c,q->name,q->type)) != 0 && c->rr.ttl > d->now.tv_sec + 8 /* && message_packet_len(m) + _rr_len(&c->rr) < d->frame */)
 
953
            {
 
954
                _a_copy(m->answerRecords, (unsigned char *)q->name, (unsigned short)q->type, (unsigned short)d->class, (unsigned long int)(c->rr.ttl - d->now.tv_sec), &c->rr);
 
955
            }
 
956
        }
 
957
        d->checkqlist = nextbest;
 
958
    }
 
959
 
 
960
    if(d->now.tv_sec > d->expireall)
 
961
        _gc(d);
 
962
 
 
963
end:
 
964
    if(ret)
 
965
        *_m = m;
 
966
    else
 
967
        jdns_packet_delete(m);
 
968
 
 
969
    return ret;
 
970
}
 
971
 
 
972
struct mytimeval *mdnsd_sleep(mdnsd d)
 
973
{
 
974
    int sec, usec;
 
975
    //mdnsdr r;
 
976
    d->sleep.tv_sec = d->sleep.tv_usec = 0;
 
977
    #define RET while(d->sleep.tv_usec > 1000000) {d->sleep.tv_sec++;d->sleep.tv_usec -= 1000000;} return &d->sleep;
 
978
 
 
979
    // first check for any immediate items to handle
 
980
    if(d->uanswers || d->a_now) return &d->sleep;
 
981
 
 
982
    mygettimeofday(d, &d->now);
 
983
 
 
984
    if(d->a_pause)
 
985
    { // then check for paused answers
 
986
        if((usec = _tvdiff(d->now,d->pause)) > 0) d->sleep.tv_usec = usec;
 
987
        RET;
 
988
    }
 
989
 
 
990
    if(d->probing)
 
991
    { // now check for probe retries
 
992
        if((usec = _tvdiff(d->now,d->probe)) > 0) d->sleep.tv_usec = usec;
 
993
        RET;
 
994
    }
 
995
 
 
996
    if(d->a_publish)
 
997
    { // now check for publish retries
 
998
        if((usec = _tvdiff(d->now,d->publish)) > 0) d->sleep.tv_usec = usec;
 
999
        RET;
 
1000
    }
 
1001
 
 
1002
    if(d->checkqlist)
 
1003
    { // also check for queries with known answer expiration/retry
 
1004
        if((sec = d->checkqlist - d->now.tv_sec) > 0) d->sleep.tv_sec = sec;
 
1005
        RET;
 
1006
    }
 
1007
 
 
1008
    // last resort, next gc expiration
 
1009
    if((sec = d->expireall - d->now.tv_sec) > 0) d->sleep.tv_sec = sec;
 
1010
    RET;
 
1011
}
 
1012
 
 
1013
void mdnsd_query(mdnsd d, char *host, int type, int (*answer)(mdnsda a, void *arg), void *arg)
 
1014
{
 
1015
    struct query *q;
 
1016
    struct cached *cur = 0;
 
1017
    int i = _namehash_nocase(host) % SPRIME;
 
1018
    if(!(q = _q_next(d,0,host,type)))
 
1019
    {
 
1020
        if(!answer) return;
 
1021
        q = (struct query *)jdns_alloc(sizeof(struct query));
 
1022
        bzero(q,sizeof(struct query));
 
1023
        q->name = jdns_strdup(host);
 
1024
        q->type = type;
 
1025
        q->next = d->queries[i];
 
1026
        q->list = d->qlist;
 
1027
        d->qlist = d->queries[i] = q;
 
1028
        q->answer = answer;
 
1029
        q->arg = arg;
 
1030
        while((cur = _c_next(d,cur,q->name,q->type)))
 
1031
        {
 
1032
            cur->q = q; // any cached entries should be associated
 
1033
            _q_answer(d,cur); // and reported!
 
1034
        }
 
1035
        _q_reset(d,q);
 
1036
        q->nexttry = d->checkqlist = d->now.tv_sec; // new questin, immediately send out
 
1037
        return;
 
1038
    }
 
1039
    if(!answer)
 
1040
    { // no answer means we don't care anymore
 
1041
        _q_done(d,q);
 
1042
        return;
 
1043
    }
 
1044
    q->answer = answer;
 
1045
    q->arg = arg;
 
1046
}
 
1047
 
 
1048
mdnsda mdnsd_list(mdnsd d, char *host, int type, mdnsda last)
 
1049
{
 
1050
    return (mdnsda)_c_next(d,(struct cached *)last,host,type);
 
1051
}
 
1052
 
 
1053
mdnsdr mdnsd_shared(mdnsd d, char *host, int type, long int ttl)
 
1054
{
 
1055
    int i = _namehash_nocase(host) % SPRIME;
 
1056
    mdnsdr r;
 
1057
    r = (mdnsdr)jdns_alloc(sizeof(struct mdnsdr_struct));
 
1058
    bzero(r,sizeof(struct mdnsdr_struct));
 
1059
    r->rr.name = (unsigned char *)jdns_strdup(host);
 
1060
    r->rr.type = type;
 
1061
    r->rr.ttl = ttl;
 
1062
    r->next = d->published[i];
 
1063
    d->published[i] = r;
 
1064
    return r;
 
1065
}
 
1066
 
 
1067
mdnsdr mdnsd_unique(mdnsd d, char *host, int type, long int ttl, void (*pubresult)(int result, char *host, int type, void *arg), void *arg)
 
1068
{
 
1069
    mdnsdr r;
 
1070
    r = mdnsd_shared(d,host,type,ttl);
 
1071
    r->pubresult = pubresult;
 
1072
    r->arg = arg;
 
1073
    r->unique = 1;
 
1074
    _r_push(&d->probing,r);
 
1075
    d->probe.tv_sec = d->now.tv_sec;
 
1076
    d->probe.tv_usec = d->now.tv_usec;
 
1077
    return r;
 
1078
}
 
1079
 
 
1080
void mdnsd_done(mdnsd d, mdnsdr r)
 
1081
{
 
1082
    mdnsdr cur;
 
1083
    if(r->unique && r->unique < 5)
 
1084
    { // probing yet, zap from that list first!
 
1085
        if(d->probing == r) d->probing = r->list;
 
1086
        else {
 
1087
            for(cur=d->probing;cur->list != r;cur = cur->list);
 
1088
            cur->list = r->list;
 
1089
        }
 
1090
        _r_done(d,r);
 
1091
        return;
 
1092
    }
 
1093
    r->rr.ttl = 0;
 
1094
    _r_send(d,r);
 
1095
}
 
1096
 
 
1097
void mdnsd_set_raw(mdnsd d, mdnsdr r, char *data, int len)
 
1098
{
 
1099
    if(r->rr.rdata)
 
1100
        jdns_free(r->rr.rdata);
 
1101
    r->rr.rdata = jdns_copy_array((unsigned char*)data, len);
 
1102
    r->rr.rdlen = len;
 
1103
    _r_publish(d,r);
 
1104
}
 
1105
 
 
1106
void mdnsd_set_host(mdnsd d, mdnsdr r, char *name)
 
1107
{
 
1108
    jdns_free(r->rr.rdname);
 
1109
    r->rr.rdname = (unsigned char *)jdns_strdup(name);
 
1110
    _r_publish(d,r);
 
1111
}
 
1112
 
 
1113
void mdnsd_set_ip(mdnsd d, mdnsdr r, unsigned long int ip)
 
1114
{
 
1115
    r->rr.ip = ip;
 
1116
    _r_publish(d,r);
 
1117
}
 
1118
 
 
1119
void mdnsd_set_srv(mdnsd d, mdnsdr r, int priority, int weight, int port, char *name)
 
1120
{
 
1121
    r->rr.srv.priority = priority;
 
1122
    r->rr.srv.weight = weight;
 
1123
    r->rr.srv.port = port;
 
1124
    mdnsd_set_host(d,r,name);
 
1125
}