Coverage Report

Created: 2025-08-26 06:30

/src/open62541/deps/mdnsd/libmdnsd/mdnsd.c
Line
Count
Source (jump to first uncovered line)
1
#include "mdnsd_config.h"
2
#include "mdnsd.h"
3
#include <string.h>
4
#include <stdlib.h>
5
#include <errno.h>
6
7
212k
#define SPRIME 108    /* Size of query/publish hashes */
8
1.52M
#define LPRIME 1009    /* Size of cache hash */
9
10
1.49k
#define GC 86400                /* Brute force garbage cleanup
11
         * frequency, rarely needed (daily
12
         * default) */
13
14
#ifdef _MSC_VER
15
#include "ms_stdint.h" /* Includes stdint.h or workaround for older Visual Studios */
16
17
int gettimeofday(struct timeval * tp, struct timezone * tzp)
18
{
19
  // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
20
  static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
21
22
  SYSTEMTIME  system_time;
23
  FILETIME    file_time;
24
  uint64_t    time;
25
26
  GetSystemTime( &system_time );
27
  SystemTimeToFileTime( &system_time, &file_time );
28
  time =  ((uint64_t)file_time.dwLowDateTime )      ;
29
  time += ((uint64_t)file_time.dwHighDateTime) << 32;
30
31
  tp->tv_sec  = (long) ((time - EPOCH) / 10000000L);
32
  tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
33
  return 0;
34
}
35
#else
36
#include <sys/time.h>
37
#endif
38
39
#if defined(__MINGW32__)
40
static char *my_strdup(const char *s) {
41
    char *p = (char *)MDNSD_malloc(strlen(s) + 1);
42
    if(p) { strcpy(p, s); }
43
    return p;
44
}
45
#define STRDUP my_strdup
46
#elif defined(_WIN32)
47
#define STRDUP _strdup
48
#else
49
10.7k
#define STRDUP strdup
50
#endif
51
52
#ifndef _WIN32
53
# include <netdb.h>
54
#endif
55
56
/**
57
 * Messy, but it's the best/simplest balance I can find at the moment
58
 *
59
 * Some internal data types, and a few hashes: querys, answers, cached,
60
 * and records (published, unique and shared).  Each type has different
61
 * semantics for processing, both for timeouts, incoming, and outgoing
62
 * I/O.  They inter-relate too, like records affect the querys they are
63
 * relevant to.  Nice things about MDNS: we only publish once (and then
64
 * ask asked), and only query once, then just expire records we've got
65
 * cached
66
*/
67
68
struct query {
69
  char *name;
70
  int type;
71
  unsigned long int nexttry;
72
  int tries;
73
  int (*answer)(mdns_answer_t *, void *);
74
  void *arg;
75
  struct query *next, *list;
76
};
77
78
struct unicast {
79
  int id;
80
  struct sockaddr *to;
81
  unsigned short int port;
82
  mdns_record_t *r;
83
  struct unicast *next;
84
};
85
86
struct cached {
87
  struct mdns_answer rr;
88
  struct query *q;
89
  struct cached *next;
90
};
91
92
struct mdns_record {
93
  struct mdns_answer rr;
94
  char unique;    /* # of checks performed to ensure */
95
  int tries;
96
  void (*conflict)(char *, int, void *);
97
  void *arg;
98
  struct timeval last_sent;
99
  struct mdns_record *next, *list;
100
};
101
102
struct mdns_daemon {
103
  char shutdown;
104
  unsigned long int expireall, checkqlist;
105
  struct timeval now, sleep, pause, probe, publish;
106
  int clazz, frame;
107
  struct cached *cache[LPRIME];
108
  struct mdns_record *published[SPRIME], *probing, *a_now, *a_pause, *a_publish;
109
  struct unicast *uanswers;
110
  struct query *queries[SPRIME], *qlist;
111
  mdnsd_record_received_callback received_callback;
112
  void *received_callback_data;
113
};
114
115
static int _namehash(const char *s)
116
30.1k
{
117
30.1k
  const unsigned char *name = (const unsigned char *)s;
118
30.1k
  unsigned long h = 0;
119
120
244k
  while (*name) {   /* do some fancy bitwanking on the string */
121
214k
    unsigned long int g;
122
214k
    h = (h << 4) + (unsigned long int)(*name++);
123
214k
    if ((g = (h & 0xF0000000UL)) != 0)
124
153k
      h ^= (g >> 24);
125
214k
    h &= ~g;
126
214k
  }
127
128
30.1k
  return (int)h;
129
30.1k
}
130
131
/* Basic linked list and hash primitives */
132
static struct query *_q_next(mdns_daemon_t *d, struct query *q, const char *host, int type)
133
5.51k
{
134
5.51k
  if (q == 0)
135
5.51k
    q = d->queries[_namehash(host) % SPRIME];
136
0
  else
137
0
    q = q->next;
138
139
5.51k
  for (; q != 0; q = q->next) {
140
0
    if (q->type == type && strcmp(q->name, host) == 0)
141
0
      return q;
142
0
  }
143
144
5.51k
  return 0;
145
5.51k
}
146
147
static struct cached *_c_next(mdns_daemon_t *d, struct cached *c,const char *host, int type)
148
7.89k
{
149
7.89k
  if (c == 0)
150
5.90k
    c = d->cache[_namehash(host) % LPRIME];
151
1.98k
  else
152
1.98k
    c = c->next;
153
154
12.6k
  for (; c != 0; c = c->next) {
155
9.12k
    if ((type == c->rr.type || type == 255) && strcmp(c->rr.name, host) == 0)
156
4.34k
      return c;
157
9.12k
  }
158
159
3.54k
  return 0;
160
7.89k
}
161
162
static mdns_record_t *_r_next(mdns_daemon_t *d, mdns_record_t *r, const char *host, int type)
163
7.62k
{
164
7.62k
  if (r == 0)
165
7.62k
    r = d->published[_namehash(host) % SPRIME];
166
0
  else
167
0
    r = r->next;
168
169
7.62k
  for (; r != 0; r = r->next) {
170
0
    if (type == r->rr.type && strcmp(r->rr.name, host) == 0)
171
0
      return r;
172
0
  }
173
174
7.62k
  return 0;
175
7.62k
}
176
177
static int _rr_len(mdns_answer_t *rr)
178
0
{
179
0
  int len = 12;   /* name is always compressed (dup of earlier), plus normal stuff */
180
181
0
  if (rr->rdata)
182
0
    len += rr->rdlen;
183
0
  if (rr->rdname)
184
0
    len += (int)strlen(rr->rdname); /* worst case */
185
0
  if (rr->ip.s_addr)
186
0
    len += 4;
187
0
  if (rr->type == QTYPE_PTR)
188
0
    len += 6; /* srv record stuff */
189
190
0
  return len;
191
0
}
192
193
/* Compares new rdata with known a, painfully */
194
static int _a_match(struct resource *r, mdns_answer_t *a)
195
3.90k
{
196
3.90k
  if (!a->name)
197
0
    return 0;
198
3.90k
  if (strcmp(r->name, a->name) != 0 || r->type != a->type)
199
344
    return 0;
200
201
3.56k
  if (r->type == QTYPE_SRV && !strcmp(r->known.srv.name, a->rdname) && a->srv.port == r->known.srv.port &&
202
3.56k
    a->srv.weight == r->known.srv.weight && a->srv.priority == r->known.srv.priority)
203
75
    return 1;
204
205
3.49k
  if ((r->type == QTYPE_PTR || r->type == QTYPE_NS || r->type == QTYPE_CNAME) && !strcmp(a->rdname, r->known.ns.name))
206
525
    return 1;
207
208
2.96k
  if (r->rdlength == a->rdlen && r->rdlength == 0)
209
1.64k
      return 1;
210
211
1.32k
  if ((r->rdlength == a->rdlen) && !memcmp(r->rdata, a->rdata, r->rdlength))
212
117
    return 1;
213
214
1.20k
  return 0;
215
1.32k
}
216
217
/* Compare time values easily */
218
static int _tvdiff(struct timeval old_time, struct timeval new_time)
219
0
{
220
0
  int udiff = 0;
221
222
0
  if (old_time.tv_sec != new_time.tv_sec)
223
0
    udiff = (int)((new_time.tv_sec - old_time.tv_sec) * 1000000);
224
225
0
  return (int)((new_time.tv_usec - old_time.tv_usec) + udiff);
226
0
}
227
228
0
static void _r_remove_list(mdns_record_t **list, mdns_record_t *r) {
229
0
  if (*list == r) {
230
0
    *list = r->list;
231
0
  } else {
232
0
    mdns_record_t *tmp = *list;
233
0
    while (tmp) {
234
0
      if (tmp->list == r) {
235
0
        tmp->list = r->list;
236
0
        break;
237
0
      }
238
0
      if (tmp == tmp->list)
239
0
        break;
240
0
      tmp = tmp->list;
241
0
    }
242
0
  }
243
0
}
244
245
0
static void _r_remove_lists(mdns_daemon_t *d, mdns_record_t *r, mdns_record_t **skip) {
246
0
  if (d->probing && &d->probing != skip) {
247
0
    _r_remove_list(&d->probing, r);
248
0
  }
249
0
  if (d->a_now && &d->a_now != skip) {
250
0
    _r_remove_list(&d->a_now, r);
251
0
  }
252
0
  if (d->a_pause && &d->a_pause != skip) {
253
0
    _r_remove_list(&d->a_pause, r);
254
0
  }
255
0
  if (d->a_publish && &d->a_publish != skip) {
256
0
    _r_remove_list(&d->a_publish, r);
257
0
  }
258
0
}
259
260
/* Make sure not already on the list, then insert */
261
static void _r_push(mdns_record_t **list, mdns_record_t *r)
262
1.80k
{
263
1.80k
  mdns_record_t *cur;
264
265
3.90k
  for (cur = *list; cur != 0; cur = cur->list) {
266
2.10k
    if (cur == r)
267
0
      return;
268
2.10k
  }
269
270
1.80k
  r->list = *list;
271
1.80k
  *list = r;
272
1.80k
}
273
274
/* Force any r out right away, if valid */
275
static void _r_publish(mdns_daemon_t *d, mdns_record_t *r)
276
1.80k
{
277
1.80k
  if (r->unique && r->unique < 5)
278
600
    return;    /* Probing already */
279
280
1.20k
  r->tries = 0;
281
1.20k
  d->publish.tv_sec = d->now.tv_sec;
282
1.20k
  d->publish.tv_usec = d->now.tv_usec;
283
1.20k
  _r_push(&d->a_publish, r);
284
1.20k
}
285
286
/* send r out asap */
287
static void _r_send(mdns_daemon_t *d, mdns_record_t *r)
288
600
{
289
  /* Being published, make sure that happens soon */
290
600
  if (r->tries < 4) {
291
600
    d->publish.tv_sec = d->now.tv_sec;
292
600
    d->publish.tv_usec = d->now.tv_usec;
293
600
    return;
294
600
  }
295
296
  /* Known unique ones can be sent asap */
297
0
  if (r->unique) {
298
299
    // check if r already in other lists. If yes, remove it from there
300
0
    _r_remove_lists(d,r, &d->a_now);
301
0
    _r_push(&d->a_now, r);
302
0
    return;
303
0
  }
304
305
  /* Set d->pause.tv_usec to random 20-120 msec */
306
0
  d->pause.tv_sec = d->now.tv_sec;
307
0
  d->pause.tv_usec = d->now.tv_usec + (d->now.tv_usec % 100) + 20;
308
0
  _r_push(&d->a_pause, r);
309
0
}
310
311
/* Create generic unicast response struct */
312
static void _u_push(mdns_daemon_t *d, mdns_record_t *r, int id, struct sockaddr *to, unsigned short int port)
313
0
{
314
0
  struct unicast *u;
315
316
0
  u = (struct unicast *)MDNSD_calloc(1, sizeof(struct unicast));
317
0
  u->r = r;
318
0
  u->id = id;
319
0
  u->to = to;
320
0
  u->port = port;
321
0
  u->next = d->uanswers;
322
0
  d->uanswers = u;
323
0
}
324
325
static void _q_reset(mdns_daemon_t *d, struct query *q)
326
300
{
327
300
  struct cached *cur = 0;
328
329
300
  q->nexttry = 0;
330
300
  q->tries = 0;
331
332
300
  while ((cur = _c_next(d, cur, q->name, q->type))) {
333
0
    if (q->nexttry == 0 || cur->rr.ttl - 7 < q->nexttry)
334
0
      q->nexttry = cur->rr.ttl - 7;
335
0
  }
336
337
300
  if (q->nexttry != 0 && q->nexttry < d->checkqlist)
338
0
    d->checkqlist = q->nexttry;
339
300
}
340
341
/* No more query, update all it's cached entries, remove from lists */
342
static void _q_done(mdns_daemon_t *d, struct query *q)
343
0
{
344
0
  struct cached *c = 0;
345
0
  struct query *cur;
346
0
  int i = _namehash(q->name) % LPRIME;
347
348
0
  while ((c = _c_next(d, c, q->name, q->type)))
349
0
    c->q = 0;
350
351
0
  if (d->qlist == q) {
352
0
    d->qlist = q->list;
353
0
  } else {
354
0
    for (cur = d->qlist; cur->list != q; cur = cur->list)
355
0
      ;
356
0
    cur->list = q->list;
357
0
  }
358
359
0
  if (d->queries[i] == q) {
360
0
    d->queries[i] = q->next;
361
0
  } else {
362
0
    for (cur = d->queries[i]; cur->next != q; cur = cur->next)
363
0
      ;
364
0
    cur->next = q->next;
365
0
  }
366
367
0
  MDNSD_free(q->name);
368
0
  MDNSD_free(q);
369
0
}
370
371
/* buh-bye, remove from hash and free */
372
static void _r_done(mdns_daemon_t *d, mdns_record_t *r)
373
600
{
374
600
  mdns_record_t *cur = 0;
375
600
  int i = _namehash(r->rr.name) % SPRIME;
376
377
600
  if (d->published[i] == r)
378
300
    d->published[i] = r->next;
379
300
  else {
380
300
    for (cur = d->published[i]; cur && cur->next != r; cur = cur->next) ;
381
300
    if (cur)
382
300
      cur->next = r->next;
383
300
  }
384
600
  MDNSD_free(r->rr.name);
385
600
  MDNSD_free(r->rr.rdata);
386
600
  MDNSD_free(r->rr.rdname);
387
600
  MDNSD_free(r);
388
600
}
389
390
/* Call the answer function with this cached entry */
391
static void _q_answer(mdns_daemon_t *d, struct cached *c)
392
0
{
393
0
  if (c->rr.ttl <= (unsigned long int)d->now.tv_sec)
394
0
    c->rr.ttl = 0;
395
0
  if (c->q->answer(&c->rr, c->q->arg) == -1)
396
0
    _q_done(d, c->q);
397
0
}
398
399
static void _conflict(mdns_daemon_t *d, mdns_record_t *r)
400
0
{
401
0
  r->conflict(r->rr.name, r->rr.type, r->arg);
402
0
  mdnsd_done(d, r);
403
0
}
404
405
/* Expire any old entries in this list */
406
static void _c_expire(mdns_daemon_t *d, struct cached **list)
407
3.32k
{
408
3.32k
  struct cached *next, *cur = *list, *last = 0;
409
410
77.6k
  while (cur != 0) {
411
74.2k
    next = cur->next;
412
74.2k
    if ((unsigned long int)d->now.tv_sec >= cur->rr.ttl) {
413
2.79k
      if (last)
414
678
        last->next = next;
415
416
      /* Update list pointer if the first one expired */
417
2.79k
      if (*list == cur)
418
2.12k
        *list = next;
419
420
2.79k
      if (cur->q)
421
0
        _q_answer(d, cur);
422
423
2.79k
      MDNSD_free(cur->rr.name);
424
2.79k
      MDNSD_free(cur->rr.rdata);
425
2.79k
      MDNSD_free(cur->rr.rdname);
426
2.79k
      MDNSD_free(cur);
427
71.4k
    } else {
428
71.4k
      last = cur;
429
71.4k
    }
430
74.2k
    cur = next;
431
74.2k
  }
432
3.32k
}
433
434
/* Brute force expire any old cached records */
435
static void _gc(mdns_daemon_t *d)
436
0
{
437
0
  int i;
438
439
0
  for (i = 0; i < LPRIME; i++) {
440
0
    if (d->cache[i])
441
0
      _c_expire(d, &d->cache[i]);
442
0
  }
443
444
0
  d->expireall = (unsigned long int)(d->now.tv_sec + GC);
445
0
}
446
447
static int _cache(mdns_daemon_t *d, struct resource *r)
448
7.19k
{
449
7.19k
  struct cached *c = 0;
450
7.19k
  int i = _namehash(r->name) % LPRIME;
451
452
  /* Cache flush for unique entries */
453
7.19k
  if (r->clazz == 32768 + d->clazz) {
454
1.40k
    while ((c = _c_next(d, c, r->name, r->type)))
455
438
      c->rr.ttl = 0;
456
966
    _c_expire(d, &d->cache[i]);
457
966
  }
458
459
  /* Process deletes */
460
7.19k
  if (r->ttl == 0) {
461
5.88k
    while ((c = _c_next(d, c, r->name, r->type))) {
462
3.90k
      if (_a_match(r, &c->rr)) {
463
2.36k
        c->rr.ttl = 0;
464
2.36k
        _c_expire(d, &d->cache[i]);
465
2.36k
        c = NULL;
466
2.36k
      }
467
3.90k
    }
468
469
1.97k
    return 0;
470
1.97k
  }
471
472
  /*
473
   * XXX: The c->rr.ttl is a hack for now, BAD SPEC, start
474
   *      retrying just after half-waypoint, then expire
475
   */
476
5.21k
  c = (struct cached *)MDNSD_calloc(1, sizeof(struct cached));
477
5.21k
  c->rr.name = STRDUP(r->name);
478
5.21k
  c->rr.type = r->type;
479
5.21k
  c->rr.ttl = (unsigned int)((unsigned long)d->now.tv_sec + (r->ttl / 2) + 8);
480
5.21k
  c->rr.rdlen = r->rdlength;
481
5.21k
  if (r->rdlength && !r->rdata) {
482
    //MDNSD_LOG_ERROR("rdlength is %d but rdata is NULL for domain name %s, type: %d, ttl: %ld", r->rdlength, r->name, r->type, r->ttl);
483
0
    MDNSD_free(c->rr.name);
484
0
    MDNSD_free(c);
485
0
    return 1;
486
0
  }
487
5.21k
  if (r->rdlength) {
488
656
    c->rr.rdata = (unsigned char *)MDNSD_malloc(r->rdlength);
489
656
    memcpy(c->rr.rdata, r->rdata, r->rdlength);
490
4.55k
  } else {
491
4.55k
    c->rr.rdata = NULL;
492
4.55k
  }
493
494
5.21k
  switch (r->type) {
495
74
    case QTYPE_AAAA:
496
74
      c->rr.ip6 = r->known.aaaa.ip6;
497
74
    break;
498
499
233
    case QTYPE_A:
500
233
      c->rr.ip = r->known.a.ip;
501
233
      break;
502
503
291
    case QTYPE_NS:
504
977
    case QTYPE_CNAME:
505
1.34k
    case QTYPE_PTR:
506
1.34k
      c->rr.rdname = STRDUP(r->known.ns.name);
507
1.34k
      break;
508
509
1.17k
    case QTYPE_SRV:
510
1.17k
      c->rr.rdname = STRDUP(r->known.srv.name);
511
1.17k
      c->rr.srv.port = r->known.srv.port;
512
1.17k
      c->rr.srv.weight = r->known.srv.weight;
513
1.17k
      c->rr.srv.priority = r->known.srv.priority;
514
1.17k
      break;
515
5.21k
  }
516
517
5.21k
  c->next = d->cache[i];
518
5.21k
  d->cache[i] = c;
519
520
5.21k
  if ((c->q = _q_next(d, 0, r->name, r->type)))
521
0
    _q_answer(d, c);
522
523
5.21k
  return 0;
524
5.21k
}
525
526
/* Copy the data bits only */
527
static void _a_copy(struct message *m, mdns_answer_t *a)
528
0
{
529
0
  if (a->rdata) {
530
0
    message_rdata_raw(m, a->rdata, a->rdlen);
531
0
    return;
532
0
  }
533
534
0
  if (a->ip.s_addr)
535
0
    message_rdata_long(m, a->ip);
536
0
  if (a->type == QTYPE_SRV)
537
0
    message_rdata_srv(m, a->srv.priority, a->srv.weight, a->srv.port, a->rdname);
538
0
  else if (a->rdname)
539
0
    message_rdata_name(m, a->rdname);
540
0
}
541
542
/* Copy a published record into an outgoing message */
543
static int _r_out(mdns_daemon_t *d, struct message *m, mdns_record_t **list)
544
0
{
545
0
  mdns_record_t *r;
546
0
  int ret = 0;
547
548
0
  while ((r = *list) != 0 && message_packet_len(m) + _rr_len(&r->rr) < d->frame) {
549
0
    if (r != r->list)
550
0
      *list = r->list;
551
0
    else
552
0
      *list = NULL;
553
0
    ret++;
554
555
0
    if (r->unique)
556
0
      message_an(m, r->rr.name, r->rr.type, (unsigned short int)(d->clazz + 32768), r->rr.ttl);
557
0
    else
558
0
      message_an(m, r->rr.name, r->rr.type,  (unsigned short int)d->clazz, r->rr.ttl);
559
0
    r->last_sent = d->now;
560
561
0
    _a_copy(m, &r->rr);
562
0
    if (r->rr.ttl == 0) {
563
564
      // also remove from other lists, because record may be in multiple lists at the same time
565
0
      _r_remove_lists(d, r, list);
566
567
0
      _r_done(d, r);
568
569
0
    }
570
0
  }
571
572
0
  return ret;
573
0
}
574
575
576
mdns_daemon_t *mdnsd_new(int clazz, int frame)
577
1.49k
{
578
1.49k
  mdns_daemon_t *d;
579
580
1.49k
  d = (mdns_daemon_t *)MDNSD_calloc(1, sizeof(struct mdns_daemon));
581
1.49k
  gettimeofday(&d->now, 0);
582
1.49k
  d->expireall = (unsigned long int)(d->now.tv_sec + GC);
583
1.49k
  d->clazz = clazz;
584
1.49k
  d->frame = frame;
585
1.49k
  d->received_callback = NULL;
586
587
1.49k
  return d;
588
1.49k
}
589
590
/* Shutting down, zero out ttl and push out all records */
591
void mdnsd_shutdown(mdns_daemon_t *d)
592
300
{
593
300
  int i;
594
300
  mdns_record_t *cur, *next;
595
596
300
  d->a_now = 0;
597
32.7k
  for (i = 0; i < SPRIME; i++) {
598
33.6k
    for (cur = d->published[i]; cur != 0;) {
599
1.20k
      next = cur->next;
600
1.20k
      cur->rr.ttl = 0;
601
1.20k
      cur->list = d->a_now;
602
1.20k
      d->a_now = cur;
603
1.20k
      cur = next;
604
1.20k
    }
605
32.4k
  }
606
607
300
  d->shutdown = 1;
608
300
}
609
610
void mdnsd_flush(mdns_daemon_t *d)
611
0
{
612
0
  (void)d;
613
  /* - Set all querys to 0 tries
614
   * - Free whole cache
615
   * - Set all mdns_record_t *to probing
616
   * - Reset all answer lists
617
   */
618
0
}
619
620
void mdnsd_free(mdns_daemon_t *d)
621
1.49k
{
622
1.49k
  size_t i;
623
1.50M
  for (i = 0; i< LPRIME; i++) {
624
1.50M
    struct cached* cur = d->cache[i];
625
1.50M
    while (cur) {
626
2.41k
      struct cached* next = cur->next;
627
2.41k
      MDNSD_free(cur->rr.name);
628
2.41k
      MDNSD_free(cur->rr.rdata);
629
2.41k
      MDNSD_free(cur->rr.rdname);
630
2.41k
      MDNSD_free(cur);
631
2.41k
      cur = next;
632
2.41k
    }
633
1.50M
  }
634
635
162k
  for (i = 0; i< SPRIME; i++) {
636
161k
    struct mdns_record* cur = d->published[i];
637
161k
    struct query* curq = NULL;
638
162k
    while (cur) {
639
1.20k
      struct mdns_record* next = cur->next;
640
1.20k
      MDNSD_free(cur->rr.name);
641
1.20k
      MDNSD_free(cur->rr.rdata);
642
1.20k
      MDNSD_free(cur->rr.rdname);
643
1.20k
      MDNSD_free(cur);
644
1.20k
      cur = next;
645
1.20k
    }
646
647
648
161k
    curq = d->queries[i];
649
161k
    while (curq) {
650
300
      struct query* next = curq->next;
651
300
      MDNSD_free(curq->name);
652
300
      MDNSD_free(curq);
653
300
      curq = next;
654
300
    }
655
656
161k
  }
657
658
1.49k
  {
659
1.49k
    struct unicast *u = d->uanswers;
660
1.49k
    while (u) {
661
0
      struct unicast *next = u->next;
662
0
      MDNSD_free(u);
663
0
      u=next;
664
0
    }
665
1.49k
  }
666
667
1.49k
  MDNSD_free(d);
668
1.49k
}
669
670
671
300
void mdnsd_register_receive_callback(mdns_daemon_t *d, mdnsd_record_received_callback cb, void* data) {
672
300
  d->received_callback = cb;
673
300
  d->received_callback_data = data;
674
300
}
675
676
int mdnsd_in(mdns_daemon_t *d, struct message *m, struct sockaddr *ip, unsigned short int port)
677
1.19k
{
678
1.19k
  int i;
679
1.19k
  mdns_record_t *r = 0;
680
681
1.19k
  if (d->shutdown)
682
0
    return 1;
683
684
1.19k
  gettimeofday(&d->now, 0);
685
686
1.19k
  if (m->header.qr == 0) {
687
    /* Process each query */
688
1.17k
    for (i = 0; i < m->qdcount; i++) {
689
1.09k
      mdns_record_t *r_start, *r_next = NULL;
690
1.09k
      bool hasConflict = false;
691
1.09k
      if (m->qd[i].clazz != d->clazz || (r = _r_next(d, 0, m->qd[i].name, m->qd[i].type)) == 0)
692
1.09k
        continue;
693
0
      r_start = r;
694
695
696
      /* Check all of our potential answers */
697
0
      for (; r != 0; r = r_next) {
698
699
0
        MDNSD_LOG_TRACE("Got Query: Name: %s, Type: %d", r->rr.name, r->rr.type);
700
701
        // do this here, because _conflict deletes r and thus next is not valid anymore
702
0
        r_next = _r_next(d, r, m->qd[i].name, m->qd[i].type);
703
        /* probing state, check for conflicts */
704
0
        if (r->unique && r->unique < 5) {
705
          /* Check all to-be answers against our own */
706
0
          int j;
707
0
          for (j = 0; j < m->nscount; j++) {
708
0
            if (m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
709
0
              continue;
710
711
            /* This answer isn't ours, conflict! */
712
0
            if (!_a_match(&m->an[j], &r->rr)) {
713
0
              _conflict(d, r);
714
0
              hasConflict = true;
715
0
              break;
716
0
            }
717
0
          }
718
0
          continue;
719
0
        }
720
721
        /* Check the known answers for this question */
722
0
        {
723
0
          int j;
724
0
          for (j = 0; j < m->ancount; j++) {
725
0
            if (m->qd[i].type != m->an[j].type || strcmp(m->qd[i].name, m->an[j].name))
726
0
              continue;
727
728
0
            if (d->received_callback) {
729
0
              d->received_callback(&m->an[j], d->received_callback_data);
730
0
            }
731
732
            /* Do they already have this answer? */
733
0
            if (_a_match(&m->an[j], &r->rr))
734
0
              break;
735
0
          }
736
0
          if (j == m->ancount)
737
0
            _r_send(d, r);
738
0
        }
739
740
0
      }
741
742
      /* Send the matching unicast reply */
743
0
      if (!hasConflict && port != 5353)
744
0
        _u_push(d, r_start, m->id, ip, port);
745
0
    }
746
747
71
    return 0;
748
71
  }
749
750
  /* Process each answer, check for a conflict, and cache */
751
8.31k
  for (i = 0; i < m->ancount; i++) {
752
7.19k
    if (m->an[i].name == NULL) {
753
0
      MDNSD_LOG_ERROR("Got answer with NULL name at %p. Type: %d, TTL: %ld\n", (void*)&m->an[i], m->an[i].type, m->an[i].ttl);
754
0
      return 3;
755
0
    }
756
757
7.19k
    MDNSD_LOG_TRACE("Got Answer: Name: %s, Type: %d", m->an[i].name, m->an[i].type);
758
7.19k
    if ((r = _r_next(d, 0, m->an[i].name, m->an[i].type)) != 0 &&
759
7.19k
      r->unique && _a_match(&m->an[i], &r->rr) == 0)
760
0
      _conflict(d, r);
761
762
7.19k
    if (d->received_callback) {
763
0
      d->received_callback(&m->an[i], d->received_callback_data);
764
0
    }
765
7.19k
    if (_cache(d, &m->an[i]) != 0)
766
0
      return 2;
767
7.19k
  }
768
1.12k
  return 0;
769
1.12k
}
770
771
int mdnsd_out(mdns_daemon_t *d, struct message *m, struct sockaddr *ip, unsigned short int *port)
772
0
{
773
0
  mdns_record_t *r;
774
0
  int ret = 0;
775
776
0
  gettimeofday(&d->now, 0);
777
0
  memset(m, 0, sizeof(struct message));
778
779
  /* Defaults, multicast */
780
0
  *port = htons(5353);
781
0
  if(ip->sa_family == AF_INET6) {
782
0
    struct sockaddr_in6 addr6;
783
784
0
    memset(&addr6, 0, sizeof(addr6));
785
0
    addr6.sin6_family = AF_INET6;
786
0
    addr6.sin6_port = *port;
787
0
    inet_pton(AF_INET6, "ff02::fb", &(addr6.sin6_addr));
788
0
    memcpy(ip, &addr6, sizeof(addr6));
789
0
  } else {
790
0
      struct sockaddr_in addr;
791
792
0
      memset(&addr, 0, sizeof(addr));
793
0
      addr.sin_family = AF_INET;
794
0
      addr.sin_port = *port;
795
0
      inet_pton(AF_INET, "224.0.0.251", &(addr.sin_addr));
796
0
      memcpy(ip, &addr, sizeof(addr));
797
0
  }
798
0
  m->header.qr = 1;
799
0
  m->header.aa = 1;
800
801
  /* Send out individual unicast answers */
802
0
  if (d->uanswers) {
803
0
    struct unicast *u = d->uanswers;
804
805
0
    MDNSD_LOG_TRACE("Send Unicast Answer: Name: %s, Type: %d", u->r->rr.name, u->r->rr.type);
806
807
0
    d->uanswers = u->next;
808
0
    *port = u->port;
809
0
    ip = u->to;
810
0
    m->id = (unsigned short int)u->id;
811
0
    message_qd(m, u->r->rr.name, u->r->rr.type, (unsigned short int)d->clazz);
812
0
    message_an(m, u->r->rr.name, u->r->rr.type, (unsigned short int)d->clazz, u->r->rr.ttl);
813
0
    u->r->last_sent = d->now;
814
0
    _a_copy(m, &u->r->rr);
815
0
    MDNSD_free(u);
816
817
0
    return 1;
818
0
  }
819
820
//  printf("OUT: probing %X now %X pause %X publish %X\n",d->probing,d->a_now,d->a_pause,d->a_publish);
821
822
  /* Accumulate any immediate responses */
823
0
  if (d->a_now)
824
0
    ret += _r_out(d, m, &d->a_now);
825
826
  /* Check if it's time to send the publish retries (unlink if done) */
827
0
  if (d->a_publish && _tvdiff(d->now, d->publish) <= 0) {
828
829
0
    mdns_record_t *next, *cur = d->a_publish, *last = NULL;
830
831
0
    while (cur && message_packet_len(m) + _rr_len(&cur->rr) < d->frame) {
832
833
0
      if (cur->rr.type == QTYPE_PTR) {
834
0
        MDNSD_LOG_TRACE("Send Publish PTR: Name: %s, rdlen: %d, rdata: %.*s, rdname: %s",
835
0
                cur->rr.name,cur->rr.rdlen, cur->rr.rdlen, cur->rr.rdata, cur->rr.rdname == NULL ? "" : cur->rr.rdname);
836
0
      } else if (cur->rr.type == QTYPE_SRV) {
837
0
        MDNSD_LOG_TRACE("Send Publish SRV: Name: %s, rdlen: %d, rdata: %.*s, rdname: %s, port: %d, prio: %d, weight: %d",
838
0
                cur->rr.name,cur->rr.rdlen, cur->rr.rdlen, cur->rr.rdata, cur->rr.rdname == NULL ? "" : cur->rr.rdname,
839
0
                cur->rr.srv.port, cur->rr.srv.priority, cur->rr.srv.weight);
840
0
      } else {
841
0
        MDNSD_LOG_TRACE("Send Publish: Name: %s, Type: %d", cur->rr.name, cur->rr.type);
842
0
      }
843
0
      next = cur->list;
844
0
      ret++;
845
0
      cur->tries++;
846
847
0
      if (cur->unique)
848
0
        message_an(m, cur->rr.name, cur->rr.type, (unsigned short int)(d->clazz + 32768), cur->rr.ttl);
849
0
      else
850
0
        message_an(m, cur->rr.name, cur->rr.type, (unsigned short int)d->clazz, cur->rr.ttl);
851
0
      _a_copy(m, &cur->rr);
852
0
      cur->last_sent = d->now;
853
854
0
      if (cur->rr.ttl != 0 && cur->tries < 4) {
855
0
        last = cur;
856
0
        cur = next;
857
0
        continue;
858
0
      }
859
860
0
      if (d->a_publish == cur)
861
0
        d->a_publish = next;
862
0
      if (last)
863
0
        last->list = next;
864
0
      if (cur->rr.ttl == 0)
865
0
        _r_done(d, cur);
866
0
      cur = next;
867
0
    }
868
869
0
    if (d->a_publish) {
870
0
      d->publish.tv_sec = d->now.tv_sec + 2;
871
0
      d->publish.tv_usec = d->now.tv_usec;
872
0
    }
873
0
  }
874
875
  /* If we're in shutdown, we're done */
876
0
  if (d->shutdown)
877
0
    return ret;
878
879
  /* Check if a_pause is ready */
880
0
  if (d->a_pause && _tvdiff(d->now, d->pause) <= 0)
881
0
    ret += _r_out(d, m, &d->a_pause);
882
883
  /* Now process questions */
884
0
  if (ret > 0)
885
0
    return ret;
886
887
0
  m->header.qr = 0;
888
0
  m->header.aa = 0;
889
890
0
  if (d->probing && _tvdiff(d->now, d->probe) <= 0) {
891
0
    mdns_record_t *last = 0;
892
893
    /* Scan probe list to ask questions and process published */
894
0
    for (r = d->probing; r != 0;) {
895
      /* Done probing, publish */
896
0
      if (r->unique == 4) {
897
0
        mdns_record_t *next = r->list;
898
899
0
        if (d->probing == r)
900
0
          d->probing = r->list;
901
0
        else
902
0
          last->list = r->list;
903
904
0
        r->list = 0;
905
0
        r->unique = 5;
906
0
        _r_publish(d, r);
907
0
        r = next;
908
0
        continue;
909
0
      }
910
911
0
      MDNSD_LOG_TRACE("Send Probing: Name: %s, Type: %d", r->rr.name, r->rr.type);
912
913
0
      message_qd(m, r->rr.name, r->rr.type, (unsigned short int)d->clazz);
914
0
      r->last_sent = d->now;
915
0
      last = r;
916
0
      r = r->list;
917
0
    }
918
919
    /* Scan probe list again to append our to-be answers */
920
0
    for (r = d->probing; r != 0; r = r->list) {
921
0
      r->unique++;
922
923
0
      MDNSD_LOG_TRACE("Send Answer in Probe: Name: %s, Type: %d", r->rr.name, r->rr.type);
924
0
      message_ns(m, r->rr.name, r->rr.type, (unsigned short int)d->clazz, r->rr.ttl);
925
0
      _a_copy(m, &r->rr);
926
0
      r->last_sent = d->now;
927
0
      ret++;
928
0
    }
929
930
    /* Process probes again in the future */
931
0
    if (ret) {
932
0
      d->probe.tv_sec = d->now.tv_sec;
933
0
      d->probe.tv_usec = d->now.tv_usec + 250000;
934
0
      return ret;
935
0
    }
936
0
  }
937
938
  /* Process qlist for retries or expirations */
939
0
  if (d->checkqlist && (unsigned long int)d->now.tv_sec >= d->checkqlist) {
940
0
    struct query *q;
941
0
    struct cached *c;
942
0
    unsigned long int nextbest = 0;
943
944
    /* Ask questions first, track nextbest time */
945
0
    for (q = d->qlist; q != 0; q = q->list) {
946
0
      if (q->nexttry > 0 && q->nexttry <= (unsigned long int)d->now.tv_sec && q->tries < 3)
947
0
        message_qd(m, q->name, (unsigned short int)q->type, (unsigned short int)d->clazz);
948
0
      else if (q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest))
949
0
        nextbest = q->nexttry;
950
0
    }
951
952
    /* Include known answers, update questions */
953
0
    for (q = d->qlist; q != 0; q = q->list) {
954
0
      if (q->nexttry == 0 || q->nexttry > (unsigned long int)d->now.tv_sec)
955
0
        continue;
956
957
      /* Done retrying, expire and reset */
958
0
      if (q->tries == 3) {
959
0
        _c_expire(d, &d->cache[_namehash(q->name) % LPRIME]);
960
0
        _q_reset(d, q);
961
0
        continue;
962
0
      }
963
964
0
      ret++;
965
0
      q->nexttry = (unsigned long int)(d->now.tv_sec + ++q->tries);
966
0
      if (nextbest == 0 || q->nexttry < nextbest)
967
0
        nextbest = q->nexttry;
968
969
      /* If room, add all known good entries */
970
0
      c = 0;
971
0
      while ((c = _c_next(d, c, q->name, q->type)) != 0 && c->rr.ttl > (unsigned long int)d->now.tv_sec + 8 &&
972
0
           message_packet_len(m) + _rr_len(&c->rr) < d->frame) {
973
974
0
        MDNSD_LOG_TRACE("Add known answer: Name: %s, Type: %d", c->rr.name, c->rr.type);
975
0
        message_an(m, q->name, (unsigned short int)q->type, (unsigned short int)d->clazz, c->rr.ttl - (unsigned long int)d->now.tv_sec);
976
0
        _a_copy(m, &c->rr);
977
0
      }
978
0
    }
979
0
    d->checkqlist = nextbest;
980
0
  }
981
982
0
  if ((unsigned long int)d->now.tv_sec > d->expireall)
983
0
    _gc(d);
984
985
0
  return ret;
986
0
}
987
988
989
#define RET         \
990
0
  while (d->sleep.tv_usec > 1000000) { \
991
0
    d->sleep.tv_sec++;    \
992
0
    d->sleep.tv_usec -= 1000000;  \
993
0
  }          \
994
0
  return &d->sleep;
995
996
struct timeval *mdnsd_sleep(mdns_daemon_t *d)
997
0
{
998
0
  int usec, minExpire;
999
1000
0
  d->sleep.tv_sec = d->sleep.tv_usec = 0;
1001
1002
  /* First check for any immediate items to handle */
1003
0
  if (d->uanswers || d->a_now)
1004
0
    return &d->sleep;
1005
1006
0
  gettimeofday(&d->now, 0);
1007
1008
  /* Then check for paused answers or nearly expired records */
1009
0
  if (d->a_pause) {
1010
0
    if ((usec = _tvdiff(d->now, d->pause)) > 0)
1011
0
      d->sleep.tv_usec = usec;
1012
0
    RET;
1013
0
  }
1014
1015
  /* Now check for probe retries */
1016
0
  if (d->probing) {
1017
0
    if ((usec = _tvdiff(d->now, d->probe)) > 0)
1018
0
      d->sleep.tv_usec = usec;
1019
0
    RET;
1020
0
  }
1021
1022
  /* Now check for publish retries */
1023
0
  if (d->a_publish) {
1024
0
    if ((usec = _tvdiff(d->now, d->publish)) > 0)
1025
0
      d->sleep.tv_usec = usec;
1026
0
    RET;
1027
0
  }
1028
1029
  /* Also check for queries with known answer expiration/retry */
1030
0
  if (d->checkqlist) {
1031
0
    int sec;
1032
0
    if ((sec = (int)(d->checkqlist - (unsigned long int)d->now.tv_sec)) > 0)
1033
0
      d->sleep.tv_sec = sec;
1034
0
    RET;
1035
0
  }
1036
1037
  /* Resend published records before TTL expires */
1038
  // latest expire is garbage collection
1039
0
  minExpire = (int)(d->expireall - (unsigned long int)d->now.tv_sec);
1040
0
  if (minExpire < 0)
1041
0
    return &d->sleep;
1042
1043
0
  {
1044
0
    size_t i;
1045
0
    for (i=0; i<SPRIME; i++) {
1046
0
      int expire;
1047
0
      if (!d->published[i])
1048
0
        continue;
1049
0
      expire = (int)((d->published[i]->last_sent.tv_sec + (long int)d->published[i]->rr.ttl) - d->now.tv_sec);
1050
0
      if (expire < minExpire)
1051
0
        d->a_pause = NULL;
1052
0
      minExpire = expire < minExpire ? expire : minExpire;
1053
0
      _r_push(&d->a_pause, d->published[i]);
1054
0
    }
1055
0
  }
1056
  // publish 2 seconds before expire.
1057
0
  d->sleep.tv_sec = minExpire > 2 ? minExpire-2 : 0;
1058
0
  d->pause.tv_sec = d->now.tv_sec + d->sleep.tv_sec;
1059
0
  RET;
1060
0
}
1061
1062
void mdnsd_query(mdns_daemon_t *d, const char *host, int type, int (*answer)(mdns_answer_t *a, void *arg), void *arg)
1063
300
{
1064
300
  struct query *q;
1065
300
  int i = _namehash(host) % SPRIME;
1066
1067
300
  if (!(q = _q_next(d, 0, host, type))) {
1068
300
    if (!answer)
1069
0
      return;
1070
1071
300
    q = (struct query *)MDNSD_calloc(1, sizeof(struct query));
1072
300
    q->name = STRDUP(host);
1073
300
    q->type = type;
1074
300
    q->next = d->queries[i];
1075
300
    q->list = d->qlist;
1076
300
    d->qlist = d->queries[i] = q;
1077
1078
    /* Any cached entries should be associated */
1079
300
    {
1080
300
      struct cached *cur = 0;
1081
300
      while ((cur = _c_next(d, cur, q->name, q->type)))
1082
0
        cur->q = q;
1083
300
    }
1084
300
    _q_reset(d, q);
1085
1086
    /* New question, immediately send out */
1087
300
    q->nexttry = d->checkqlist = (unsigned long int)d->now.tv_sec;
1088
300
  }
1089
1090
  /* No answer means we don't care anymore */
1091
300
  if (!answer) {
1092
0
    _q_done(d, q);
1093
0
    return;
1094
0
  }
1095
1096
300
  q->answer = answer;
1097
300
  q->arg = arg;
1098
300
}
1099
1100
mdns_answer_t *mdnsd_list(mdns_daemon_t *d,const char *host, int type, mdns_answer_t *last)
1101
0
{
1102
0
  return (mdns_answer_t *)_c_next(d, (struct cached *)last, host, type);
1103
0
}
1104
1105
900
mdns_record_t *mdnsd_record_next(const mdns_record_t* r) {
1106
900
  return r ? r->next : NULL;
1107
900
}
1108
1109
1.20k
const mdns_answer_t *mdnsd_record_data(const mdns_record_t* r) {
1110
1.20k
  return &r->rr;
1111
1.20k
}
1112
1113
mdns_record_t *mdnsd_shared(mdns_daemon_t *d, const char *host, unsigned short int type, unsigned long int ttl)
1114
1.80k
{
1115
1.80k
  int i = _namehash(host) % SPRIME;
1116
1.80k
  mdns_record_t *r;
1117
1118
1.80k
  r = (struct mdns_record *)MDNSD_calloc(1, sizeof(struct mdns_record));
1119
1.80k
  r->rr.name = STRDUP(host);
1120
1.80k
  r->rr.type = type;
1121
1.80k
  r->rr.ttl = ttl;
1122
1.80k
  r->next = d->published[i];
1123
1.80k
  d->published[i] = r;
1124
1125
1.80k
  return r;
1126
1.80k
}
1127
1128
mdns_record_t *mdnsd_unique(mdns_daemon_t *d, const char *host, unsigned short int type, unsigned long int ttl, void (*conflict)(char *host, int type, void *arg), void *arg)
1129
600
{
1130
600
  mdns_record_t *r;
1131
1132
600
  r = mdnsd_shared(d, host, type, ttl);
1133
600
  r->conflict = conflict;
1134
600
  r->arg = arg;
1135
600
  r->unique = 1;
1136
600
  _r_push(&d->probing, r);
1137
600
  d->probe.tv_sec = d->now.tv_sec;
1138
600
  d->probe.tv_usec = d->now.tv_usec;
1139
1140
600
  return r;
1141
600
}
1142
1143
1.20k
mdns_record_t * mdnsd_get_published(const mdns_daemon_t *d, const char *host) {
1144
1.20k
  return d->published[_namehash(host) % SPRIME];
1145
1.20k
}
1146
1147
0
int mdnsd_has_query(const mdns_daemon_t *d, const char *host) {
1148
0
  return d->queries[_namehash(host) % SPRIME]!=NULL;
1149
0
}
1150
1151
void mdnsd_done(mdns_daemon_t *d, mdns_record_t *r)
1152
1.20k
{
1153
1.20k
  mdns_record_t *cur;
1154
1155
1.20k
  if (r->unique && r->unique < 5) {
1156
    /* Probing yet, zap from that list first! */
1157
600
    if (d->probing == r) {
1158
600
      d->probing = r->list;
1159
600
    } else {
1160
0
      for (cur = d->probing; cur->list != r; cur = cur->list)
1161
0
        ;
1162
0
      cur->list = r->list;
1163
0
    }
1164
1165
600
    _r_done(d, r);
1166
600
    return;
1167
600
  }
1168
1169
600
  r->rr.ttl = 0;
1170
600
  _r_send(d, r);
1171
600
}
1172
1173
void mdnsd_set_raw(mdns_daemon_t *d, mdns_record_t *r, const char *data, unsigned short int len)
1174
900
{
1175
900
  MDNSD_free(r->rr.rdata);
1176
900
  r->rr.rdata = (unsigned char *)MDNSD_malloc(len);
1177
900
  memcpy(r->rr.rdata, data, len);
1178
900
  r->rr.rdlen = len;
1179
900
  _r_publish(d, r);
1180
900
}
1181
1182
void mdnsd_set_host(mdns_daemon_t *d, mdns_record_t *r, const char *name)
1183
900
{
1184
900
  MDNSD_free(r->rr.rdname);
1185
900
  r->rr.rdname = STRDUP(name);
1186
900
  _r_publish(d, r);
1187
900
}
1188
1189
void mdnsd_set_ip(mdns_daemon_t *d, mdns_record_t *r, struct in_addr ip)
1190
0
{
1191
0
  r->rr.ip = ip;
1192
0
  _r_publish(d, r);
1193
0
}
1194
1195
void mdnsd_set_srv(mdns_daemon_t *d, mdns_record_t *r, unsigned short int priority, unsigned short int weight, unsigned short int port, char *name)
1196
300
{
1197
300
  r->rr.srv.priority = priority;
1198
300
  r->rr.srv.weight = weight;
1199
300
  r->rr.srv.port = port;
1200
300
  mdnsd_set_host(d, r, name);
1201
300
}
1202
1203
#if MDNSD_LOGLEVEL <= 100
1204
#include <ctype.h>
1205
static void dump_hex_pkg(char* buffer, int bufferLen) {
1206
  char ascii[17];
1207
  memset(ascii,0,17);
1208
  for (int i = 0; i < bufferLen; i++)
1209
  {
1210
    if (i%16 == 0)
1211
      printf("%s\n%06x ", ascii, i);
1212
    if (isprint((int)(buffer[i])))
1213
      ascii[i%16] = buffer[i];
1214
    else
1215
      ascii[i%16] = '.';
1216
    printf("%02X ", (unsigned char)buffer[i]);
1217
  }
1218
  printf("%s\n%06x ", ascii, bufferLen);
1219
  printf("\n");
1220
}
1221
#endif
1222
1223
0
unsigned short int mdnsd_step(mdns_daemon_t *d, int mdns_socket, bool processIn, bool processOut, struct timeval *nextSleep) {
1224
1225
0
  struct message m;
1226
1227
0
  if (processIn) {
1228
0
    int bsize;
1229
0
    unsigned char buf[MAX_PACKET_LEN];
1230
0
    struct sockaddr_storage from;
1231
0
    socklen_t ssize = sizeof(from);
1232
1233
0
    while ((bsize = (int)recvfrom(mdns_socket, (char*)buf, MAX_PACKET_LEN, 0, (struct sockaddr *)&from, &ssize)) > 0) {
1234
0
      memset(&m, 0, sizeof(struct message));
1235
#if MDNSD_LOGLEVEL <= 100
1236
      MDNSD_LOG_TRACE("Got Data:");
1237
      dump_hex_pkg((char*)buf, bsize);
1238
#endif
1239
#ifdef MDNSD_DEBUG_DUMP_PKGS_FILE
1240
            mdnsd_debug_dumpCompleteChunk(d, (char*)buf, (size_t) bsize);
1241
#endif
1242
0
      if (!message_parse(&m, buf, (size_t)bsize))
1243
0
          continue;
1244
1245
0
      unsigned short int fromPort;
1246
0
      if (from.ss_family == AF_INET){
1247
0
        fromPort = ((struct sockaddr_in *)&from)->sin_port;
1248
0
      } else {
1249
0
        fromPort = ((struct sockaddr_in6 *)&from)->sin6_port;
1250
0
      }
1251
0
      if (mdnsd_in(d, &m,(struct sockaddr *)&from, fromPort) !=0)
1252
0
        return 2;
1253
0
    }
1254
#ifdef _WIN32
1255
    if (bsize < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
1256
#else
1257
0
    if (bsize < 0 && errno != EAGAIN)
1258
0
#endif
1259
0
    {
1260
0
      return 1;
1261
0
    }
1262
0
  }
1263
1264
0
  if (processOut) {
1265
0
    struct sockaddr_storage addrStorage;
1266
0
    struct sockaddr *to = (struct sockaddr*)&addrStorage;
1267
0
    socklen_t addrLength = sizeof(struct sockaddr_storage);
1268
0
    unsigned short int port;
1269
0
#ifdef __clang__
1270
0
#pragma clang diagnostic push
1271
0
#pragma clang diagnostic ignored "-Wcast-align"
1272
0
#endif
1273
1274
0
    if(getsockname(mdns_socket, to, &addrLength))
1275
0
      return 2;
1276
0
    while (mdnsd_out(d, &m, to, &port)) {
1277
0
#ifdef __clang__
1278
0
#pragma clang diagnostic pop
1279
0
#endif
1280
0
      int len = message_packet_len(&m);
1281
0
      char* buf = (char*)message_packet(&m);
1282
#if MDNSD_LOGLEVEL <= 100
1283
      MDNSD_LOG_TRACE("Send Data:");
1284
      dump_hex_pkg(buf, (int)len);
1285
#endif
1286
1287
#ifdef MDNSD_DEBUG_DUMP_PKGS_FILE
1288
      mdnsd_debug_dumpCompleteChunk(d, buf, (size_t) len);
1289
#endif
1290
0
      if ((sendto(mdns_socket, buf, (unsigned int)len, 0, to,
1291
0
            addrLength)) != len) {
1292
0
        return 2;
1293
0
      }
1294
0
    }
1295
0
  }
1296
1297
0
  if (nextSleep) {
1298
0
    struct timeval *tv = mdnsd_sleep(d);
1299
0
    nextSleep->tv_sec = tv->tv_sec;
1300
0
    nextSleep->tv_usec = tv->tv_usec;
1301
0
  }
1302
1303
0
  return 0;
1304
0
}