File Coverage

Native.xs
Criterion Covered Total %
statement 272 367 74.1
branch 141 258 54.6
condition n/a
subroutine n/a
pod n/a
total 413 625 66.0


line stmt bran cond sub pod time code
1             #ifdef __linux__
2             # define _GNU_SOURCE
3             #endif
4             #include
5             #include
6             #include
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10             #include "ppport.h"
11             #include "bstree.h"
12              
13             #pragma push_macro("free")
14             #pragma push_macro("malloc")
15             #undef free
16             #undef malloc
17             #include "queue.h" // will be used outside of the main thread
18             #pragma pop_macro("free")
19             #pragma pop_macro("malloc")
20              
21             // write() is deprecated in favor of _write() - windows way
22             #if defined(WIN32) && !defined(UNDER_CE)
23             # include
24             # define write _write
25             # define read _read
26             #endif
27              
28             // unnamed semaphores are not implemented in this POSIX compatible UNIX system
29             #ifdef PERL_DARWIN
30             # include "mysemaphore.h"
31             # define sem_t my_sem_t
32             # define sem_init my_sem_init
33             # define sem_wait my_sem_wait
34             # define sem_post my_sem_post
35             # define sem_destroy my_sem_destroy
36             #endif
37              
38             #ifdef __linux__
39             # include
40 0           int _dl_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
41             int i;
42 0           char *found = (char*)data;
43            
44 0 0         if (*found) {
45 0           return *found;
46             }
47            
48 0 0         for (i=0; i < info->dlpi_phnum; i++) {
49 0 0         if (instr(info->dlpi_name, "libnss_files") != NULL) {
50 0           *found = 1;
51 0           break;
52             }
53             }
54            
55 0           return *found;
56             }
57             #endif
58              
59             typedef struct DNS_result DNS_result;
60              
61             typedef struct {
62             pthread_mutex_t mutex;
63             pthread_attr_t thread_attrs;
64             pthread_t *threads_pool;
65             #ifndef WIN32
66             sigset_t blocked_sig;
67             #endif
68             sem_t semaphore;
69             bstree* fd_map;
70             queue* in_queue;
71             int pool;
72             char extra_thread;
73             char notify_on_begin;
74             int extra_threads_cnt;
75             int busy_threads;
76             queue* tout_queue;
77             char forked;
78             char need_pool_reinit;
79             PerlInterpreter *perl;
80             } Net_DNS_Native;
81              
82             typedef struct {
83             Net_DNS_Native *self;
84             char *host;
85             char *service;
86             struct addrinfo *hints;
87             char extra;
88             char pool;
89             DNS_result *res;
90             } DNS_thread_arg;
91              
92             struct DNS_result {
93             int fd1;
94             int error;
95             struct addrinfo *hostinfo;
96             int type;
97             DNS_thread_arg *arg;
98             char dequeued;
99             };
100              
101             queue *DNS_instances = NULL;
102              
103 314           void *DNS_getaddrinfo(void *v_arg) {
104 314           DNS_thread_arg *arg = (DNS_thread_arg *)v_arg;
105             #ifndef WIN32
106 314 100         if (!arg->pool)
107 280           pthread_sigmask(SIG_BLOCK, &arg->self->blocked_sig, NULL);
108             #endif
109            
110 314 100         if (arg->self->notify_on_begin)
111 16           write(arg->res->fd1, "1", 1);
112 314           arg->res->error = getaddrinfo(arg->host, arg->service, arg->hints, &arg->res->hostinfo);
113            
114 314           pthread_mutex_lock(&arg->self->mutex);
115 314           arg->res->arg = arg;
116 314 100         if (arg->extra) arg->self->extra_threads_cnt--;
117 314           write(arg->res->fd1, "2", 1);
118 314           pthread_mutex_unlock(&arg->self->mutex);
119            
120 314           return NULL;
121             }
122              
123 16           void *DNS_pool_worker(void *v_arg) {
124 16           Net_DNS_Native *self = (Net_DNS_Native*)v_arg;
125             #ifndef WIN32
126 16           pthread_sigmask(SIG_BLOCK, &self->blocked_sig, NULL);
127             #endif
128            
129 50 50         while (sem_wait(&self->semaphore) == 0) {
130 49           pthread_mutex_lock(&self->mutex);
131 49           void *arg = queue_shift(self->in_queue);
132 49 100         if (arg != NULL) self->busy_threads++;
133 49           pthread_mutex_unlock(&self->mutex);
134            
135 49 100         if (arg == NULL) {
136             // this was request to quit thread
137 15           break;
138             }
139            
140 34           DNS_getaddrinfo(arg);
141            
142 34           pthread_mutex_lock(&self->mutex);
143 34           self->busy_threads--;
144 34           pthread_mutex_unlock(&self->mutex);
145             }
146            
147 15           return NULL;
148             }
149              
150 332           void DNS_free_timedout(Net_DNS_Native *self, char force) {
151 332 100         if (queue_size(self->tout_queue)) {
152 48           queue_iterator *it = queue_iterator_new(self->tout_queue);
153             int fd;
154             DNS_result *res;
155            
156 96 100         while (!queue_iterator_end(it)) {
157 48           fd = (intptr_t)queue_at(self->tout_queue, it);
158 48           res = bstree_get(self->fd_map, fd);
159 48 50         if (res == NULL) {
160 0           goto FREE_TOUT;
161             }
162            
163 48 50         if (force || res->arg) {
    100          
164 9           bstree_del(self->fd_map, fd);
165 9 100         if (!res->error && res->hostinfo)
    50          
166 6           freeaddrinfo(res->hostinfo);
167            
168 9           close(fd);
169 9           close(res->fd1);
170 9 50         if (res->arg) {
171 9 50         if (res->arg->hints) free(res->arg->hints);
172 9 50         if (res->arg->host) Safefree(res->arg->host);
173 9 50         if (res->arg->service) Safefree(res->arg->service);
174 9           free(res->arg);
175             }
176 9           free(res);
177            
178             FREE_TOUT:
179 9           queue_del(self->tout_queue, it);
180 9           continue;
181             }
182            
183 39           queue_iterator_next(it);
184             }
185            
186 48           queue_iterator_destroy(it);
187             }
188 332           }
189              
190 3           void DNS_lock_semaphore(sem_t *s) {
191             #ifdef PERL_DARWIN
192             pthread_mutex_lock(&s->lock);
193             #endif
194 3           }
195              
196 3           void DNS_unlock_semaphore(sem_t *s) {
197             #ifdef PERL_DARWIN
198             pthread_mutex_unlock(&s->lock);
199             #endif
200 3           }
201              
202 5           void DNS_before_fork_handler() {
203 5 50         if (queue_size(DNS_instances) == 0) {
204 0           return;
205             }
206            
207             Net_DNS_Native *self;
208 5           queue_iterator *it = queue_iterator_new(DNS_instances);
209 10 100         while (!queue_iterator_end(it)) {
210 5           self = queue_at(DNS_instances, it);
211 5           pthread_mutex_lock(&self->mutex);
212 5 100         if (self->pool) DNS_lock_semaphore(&self->semaphore);
213 5           queue_iterator_next(it);
214             }
215 5           queue_iterator_destroy(it);
216             }
217              
218 3           void DNS_after_fork_handler_parent() {
219 3 50         if (queue_size(DNS_instances) == 0) {
220 0           return;
221             }
222            
223             Net_DNS_Native *self;
224 3           queue_iterator *it = queue_iterator_new(DNS_instances);
225 6 100         while (!queue_iterator_end(it)) {
226 3           self = queue_at(DNS_instances, it);
227 3           pthread_mutex_unlock(&self->mutex);
228 3 100         if (self->pool) DNS_unlock_semaphore(&self->semaphore);
229 3           queue_iterator_next(it);
230             }
231 3           queue_iterator_destroy(it);
232             }
233              
234 1           void DNS_reinit_pool(Net_DNS_Native *self) {
235             pthread_t tid;
236             int i, rc;
237            
238 2 100         for (i=0; ipool; i++) {
239 1           rc = pthread_create(&tid, NULL, DNS_pool_worker, (void*)self);
240 1 50         if (rc == 0) {
241 1           self->threads_pool[i] = tid;
242             }
243             else {
244 0           croak("Can't recreate thread #%d after fork: %s", i+1, strerror(rc));
245             }
246             }
247 1           }
248              
249 2           void DNS_after_fork_handler_child() {
250 2 50         if (queue_size(DNS_instances) == 0) {
251 0           return;
252             }
253            
254             Net_DNS_Native *self;
255 2           queue_iterator *it = queue_iterator_new(DNS_instances);
256            
257 4 100         while (!queue_iterator_end(it)) {
258 2           self = queue_at(DNS_instances, it);
259 2           pthread_mutex_unlock(&self->mutex);
260 2 100         if (self->pool) DNS_unlock_semaphore(&self->semaphore);
261            
262             // reinitialize stuff
263 2           DNS_free_timedout(self, 1);
264            
265 2           self->extra_threads_cnt = 0;
266 2           self->busy_threads = 0;
267 2           self->perl = PERL_GET_THX;
268 2           self->forked = 1;
269            
270 2 100         if (self->pool) {
271             #ifdef __NetBSD__
272             // unfortunetly under NetBSD threads created here will misbehave
273             self->need_pool_reinit = 1;
274             #else
275 1           DNS_reinit_pool(self);
276             #endif
277             }
278            
279 2           queue_iterator_next(it);
280             }
281            
282 2           queue_iterator_destroy(it);
283             }
284              
285             MODULE = Net::DNS::Native PACKAGE = Net::DNS::Native
286              
287             PROTOTYPES: DISABLE
288              
289             SV*
290             new(char* class, ...)
291             PREINIT:
292             Net_DNS_Native *self;
293             CODE:
294 16 50         if (items % 2 == 0)
295 0           croak("odd number of parameters");
296            
297 16           Newx(self, 1, Net_DNS_Native);
298            
299             int i, rc;
300 16           self->pool = 0;
301 16           self->notify_on_begin = 0;
302 16           self->extra_thread = 0;
303 16           self->extra_threads_cnt = 0;
304 16           self->busy_threads = 0;
305 16           self->forked = 0;
306 16           self->need_pool_reinit = 0;
307 16           self->perl = PERL_GET_THX;
308             #ifndef WIN32
309 16           sigfillset(&self->blocked_sig);
310             #endif
311             char *opt;
312            
313 31 100         for (i=1; i
314 15 50         opt = SvPV_nolen(ST(i));
315            
316 15 100         if (strEQ(opt, "pool")) {
317 9 50         self->pool = SvIV(ST(i+1));
318 9 50         if (self->pool < 0) self->pool = 0;
319             }
320 6 100         else if (strEQ(opt, "extra_thread")) {
321 3 50         self->extra_thread = SvIV(ST(i+1));
322             }
323 3 50         else if (strEQ(opt, "notify_on_begin")) {
324 3 50         self->notify_on_begin = SvIV(ST(i+1));
325             }
326             else {
327 0 0         warn("unsupported option: %s", SvPV_nolen(ST(i)));
328             }
329             }
330            
331 16           char attr_ok = 0, mutex_ok = 0, sem_ok = 0;
332            
333 16           rc = pthread_attr_init(&self->thread_attrs);
334 16 50         if (rc != 0) {
335 0           warn("pthread_attr_init(): %s", strerror(rc));
336 0           goto FAIL;
337             }
338 16           attr_ok = 1;
339 16           rc = pthread_attr_setdetachstate(&self->thread_attrs, PTHREAD_CREATE_DETACHED);
340 16 50         if (rc != 0) {
341 0           warn("pthread_attr_setdetachstate(): %s", strerror(rc));
342 0           goto FAIL;
343             }
344 16           rc = pthread_mutex_init(&self->mutex, NULL);
345 16 50         if (rc != 0) {
346 0           warn("pthread_mutex_init(): %s", strerror(rc));
347 0           goto FAIL;
348             }
349 16           mutex_ok = 1;
350            
351 16           self->in_queue = NULL;
352 16           self->threads_pool = NULL;
353            
354 16 100         if (DNS_instances == NULL) {
355 5           DNS_instances = queue_new();
356             #ifndef WIN32
357 5           rc = pthread_atfork(DNS_before_fork_handler, DNS_after_fork_handler_parent, DNS_after_fork_handler_child);
358 5 50         if (rc != 0) {
359 0           warn("Can't install fork handler: %s", strerror(rc));
360 0           goto FAIL;
361             }
362             #endif
363             }
364            
365 16 100         if (self->pool) {
366 9 50         if (sem_init(&self->semaphore, 0, 0) != 0) {
367 0           warn("sem_init(): %s", strerror(errno));
368 0           goto FAIL;
369             }
370 9           sem_ok = 1;
371            
372 9           self->threads_pool = malloc(self->pool*sizeof(pthread_t));
373             pthread_t tid;
374 9           int j = 0;
375            
376 24 100         for (i=0; ipool; i++) {
377 15           rc = pthread_create(&tid, NULL, DNS_pool_worker, (void*)self);
378 15 50         if (rc == 0) {
379 15           self->threads_pool[j++] = tid;
380             }
381             else {
382 0           warn("Can't create thread #%d: %s", i+1, strerror(rc));
383             }
384             }
385            
386 9 50         if (j == 0) {
387 0           goto FAIL;
388             }
389            
390 9           self->pool = j;
391 9           self->in_queue = queue_new();
392             }
393            
394 16           self->fd_map = bstree_new();
395 16           self->tout_queue = queue_new();
396 16           RETVAL = newSV(0);
397 16           sv_setref_pv(RETVAL, class, (void *)self);
398            
399             if (0) {
400             FAIL:
401 0 0         if (attr_ok) pthread_attr_destroy(&self->thread_attrs);
402 0 0         if (mutex_ok) pthread_mutex_destroy(&self->mutex);
403 0 0         if (sem_ok) sem_destroy(&self->semaphore);
404 0 0         if (self->threads_pool) free(self->threads_pool);
405 0           Safefree(self);
406 0           RETVAL = &PL_sv_undef;
407             }
408            
409 16           queue_push(DNS_instances, self);
410             OUTPUT:
411             RETVAL
412              
413             int
414             _getaddrinfo(Net_DNS_Native *self, char *host, SV* sv_service, SV* sv_hints, int type)
415             INIT:
416             int fd[2];
417             CODE:
418             #ifdef __NetBSD__
419             if (self->need_pool_reinit) {
420             self->need_pool_reinit = 0;
421             DNS_reinit_pool(self);
422             }
423             #endif
424 314 50         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC, fd) != 0)
425 0           croak("socketpair(): %s", strerror(errno));
426            
427 314 50         char *service = SvOK(sv_service) ? SvPV_nolen(sv_service) : "";
    50          
    50          
    0          
428 314           struct addrinfo *hints = NULL;
429            
430 314 100         if (SvOK(sv_hints)) {
    50          
    50          
431             // defined
432 81 50         if (!SvROK(sv_hints) || SvTYPE(SvRV(sv_hints)) != SVt_PVHV) {
    50          
433             // not reference or not a hash inside reference
434 0           croak("hints should be reference to hash");
435             }
436            
437 81           hints = malloc(sizeof(struct addrinfo));
438 81           hints->ai_flags = 0;
439 81           hints->ai_family = AF_UNSPEC;
440 81           hints->ai_socktype = 0;
441 81           hints->ai_protocol = 0;
442 81           hints->ai_addrlen = 0;
443 81           hints->ai_addr = NULL;
444 81           hints->ai_canonname = NULL;
445 81           hints->ai_next = NULL;
446            
447 81           HV* hv_hints = (HV*)SvRV(sv_hints);
448            
449 81           SV **flags_ptr = hv_fetch(hv_hints, "flags", 5, 0);
450 81 100         if (flags_ptr != NULL) {
451 45 50         hints->ai_flags = SvIV(*flags_ptr);
452             }
453            
454 81           SV **family_ptr = hv_fetch(hv_hints, "family", 6, 0);
455 81 50         if (family_ptr != NULL) {
456 81 50         hints->ai_family = SvIV(*family_ptr);
457             }
458            
459 81           SV **socktype_ptr = hv_fetch(hv_hints, "socktype", 8, 0);
460 81 50         if (socktype_ptr != NULL) {
461 81 50         hints->ai_socktype = SvIV(*socktype_ptr);
462             }
463            
464 81           SV **protocol_ptr = hv_fetch(hv_hints, "protocol", 8, 0);
465 81 50         if (protocol_ptr != NULL) {
466 0 0         hints->ai_protocol = SvIV(*protocol_ptr);
467             }
468             }
469            
470 314           DNS_result *res = malloc(sizeof(DNS_result));
471 314           res->fd1 = fd[1];
472 314           res->error = 0;
473 314           res->hostinfo = NULL;
474 314           res->type = type;
475 314           res->arg = NULL;
476 314           res->dequeued = 0;
477            
478 314           DNS_thread_arg *arg = malloc(sizeof(DNS_thread_arg));
479 314           arg->self = self;
480 314 50         arg->host = strlen(host) ? savepv(host) : NULL;
481 314 50         arg->service = strlen(service) ? savepv(service) : NULL;
482 314           arg->hints = hints;
483 314           arg->extra = 0;
484 314           arg->pool = 0;
485 314           arg->res = res;
486            
487 314           pthread_mutex_lock(&self->mutex);
488 314           DNS_free_timedout(self, 0);
489 314           bstree_put(self->fd_map, fd[0], res);
490 314 100         if (self->pool) {
491 52 100         if (self->busy_threads == self->pool && (self->extra_thread || queue_size(self->tout_queue) > self->extra_threads_cnt)) {
    100          
    100          
492 18           arg->extra = 1;
493 18           self->extra_threads_cnt++;
494             }
495             else {
496 34           arg->pool = 1;
497 34           queue_push(self->in_queue, arg);
498 34           sem_post(&self->semaphore);
499             }
500             }
501 314           pthread_mutex_unlock(&self->mutex);
502            
503 314 100         if (!self->pool || arg->extra) {
    100          
504             pthread_t tid;
505 280           int rc = pthread_create(&tid, &self->thread_attrs, DNS_getaddrinfo, (void *)arg);
506 280 50         if (rc != 0) {
507 0 0         if (arg->host) Safefree(arg->host);
508 0 0         if (arg->service) Safefree(arg->service);
509 0           free(arg);
510 0           free(res);
511 0 0         if (hints) free(hints);
512 0           pthread_mutex_lock(&self->mutex);
513 0           bstree_del(self->fd_map, fd[0]);
514 0           pthread_mutex_unlock(&self->mutex);
515 0           close(fd[0]);
516 0           close(fd[1]);
517 280           croak("pthread_create(): %s", strerror(rc));
518             }
519             }
520            
521 314           RETVAL = fd[0];
522             OUTPUT:
523             RETVAL
524              
525             void
526             _get_result(Net_DNS_Native *self, int fd)
527             PPCODE:
528 317           pthread_mutex_lock(&self->mutex);
529 317           DNS_result *res = bstree_get(self->fd_map, fd);
530 317           bstree_del(self->fd_map, fd);
531 317           pthread_mutex_unlock(&self->mutex);
532            
533 317 100         if (res == NULL) croak("attempt to get result which doesn't exists");
534 305 50         if (!res->arg) {
535 0           pthread_mutex_lock(&self->mutex);
536 0           bstree_put(self->fd_map, fd, res);
537 0           pthread_mutex_unlock(&self->mutex);
538 0           croak("attempt to get not ready result");
539             }
540            
541 305 50         XPUSHs(sv_2mortal(newSViv(res->type)));
542 305           SV *err = newSV(0);
543 305           sv_setiv(err, (IV)res->error);
544 305 100         sv_setpv(err, res->error ? gai_strerror(res->error) : "");
545 305           SvIOK_on(err);
546 305 50         XPUSHs(sv_2mortal(err));
547            
548 305 100         if (!res->error) {
549             struct addrinfo *info;
550 1677 100         for (info = res->hostinfo; info != NULL; info = info->ai_next) {
551 1401           HV *hv_info = newHV();
552 1401           hv_store(hv_info, "family", 6, newSViv(info->ai_family), 0);
553 1401           hv_store(hv_info, "socktype", 8, newSViv(info->ai_socktype), 0);
554 1401           hv_store(hv_info, "protocol", 8, newSViv(info->ai_protocol), 0);
555 1401           hv_store(hv_info, "addr", 4, newSVpvn((char*)info->ai_addr, info->ai_addrlen), 0);
556 1401 100         hv_store(hv_info, "canonname", 9, info->ai_canonname ? newSVpv(info->ai_canonname, 0) : newSV(0), 0);
557 1401 50         XPUSHs(sv_2mortal(newRV_noinc((SV*)hv_info)));
558             }
559            
560 276 50         if (res->hostinfo) freeaddrinfo(res->hostinfo);
561             }
562            
563 305           close(fd);
564 305           close(res->fd1);
565 305 100         if (res->arg->hints) free(res->arg->hints);
566 305 50         if (res->arg->host) Safefree(res->arg->host);
567 305 50         if (res->arg->service) Safefree(res->arg->service);
568 305           free(res->arg);
569 305           free(res);
570              
571             void
572             _timedout(Net_DNS_Native *self, int fd)
573             PPCODE:
574 9           char unknown = 0;
575            
576 9           pthread_mutex_lock(&self->mutex);
577 9 50         if (bstree_get(self->fd_map, fd) == NULL) {
578 0           unknown = 1;
579             }
580             else {
581 9           queue_push(self->tout_queue, (void*)(intptr_t)fd);
582             }
583 9           pthread_mutex_unlock(&self->mutex);
584            
585 9 50         if (unknown)
586 0           croak("attempt to set timeout on unknown source");
587              
588             void
589             DESTROY(Net_DNS_Native *self)
590             CODE:
591 16 50         if (PERL_GET_THX != self->perl) {
592             // attempt to destroy from another perl thread
593 0           return;
594             }
595            
596 16 100         if (self->pool) {
597 9           pthread_mutex_lock(&self->mutex);
598 9 50         if (queue_size(self->in_queue) > 0) {
599             // warnings are useless in global destruction
600 0 0         if (!PL_dirty)
601 0           warn("destroying Net::DNS::Native object while queue for resolver has %d elements", queue_size(self->in_queue));
602            
603 0           queue_iterator *it = queue_iterator_new(self->in_queue);
604             DNS_thread_arg *arg;
605            
606 0 0         while (!queue_iterator_end(it)) {
607 0           arg = queue_at(self->in_queue, it);
608 0           arg->res->dequeued = 1;
609 0           free(arg);
610 0           queue_iterator_next(it);
611             }
612            
613 0           queue_iterator_destroy(it);
614 0           queue_clear(self->in_queue);
615             }
616 9           pthread_mutex_unlock(&self->mutex);
617            
618             int i;
619 24 100         for (i=0; ipool; i++) {
620 15           sem_post(&self->semaphore);
621             }
622            
623             void *rv;
624            
625 24 100         for (i=0; ipool; i++) {
626             #ifdef __NetBSD__
627             // unfortunetly NetBSD can join only first thread after fork
628             if (self->forked && i > 0) break;
629             #endif
630 15           pthread_join(self->threads_pool[i], &rv);
631             }
632            
633 9           queue_destroy(self->in_queue);
634 9           free(self->threads_pool);
635 9           sem_destroy(&self->semaphore);
636             }
637            
638 16           pthread_mutex_lock(&self->mutex);
639 16           DNS_free_timedout(self, 0);
640 16           pthread_mutex_unlock(&self->mutex);
641            
642 16 50         if (bstree_size(self->fd_map) > 0) {
643 0 0         if (!PL_dirty)
644 0           warn("destroying Net::DNS::Native object with %d non-received results", bstree_size(self->fd_map));
645            
646 0           int *fds = bstree_keys(self->fd_map);
647             int i, l, j;
648             char buf[1];
649            
650 0 0         for (i=0, l=bstree_size(self->fd_map); i
651 0           DNS_result *res = bstree_get(self->fd_map, fds[i]);
652            
653 0 0         if (!res->dequeued) {
654 0 0         for (j=0; j<2; j++) {
655 0           read(fds[i], buf, 1);
656             // notify_on_begin may send 1
657 0 0         if (buf[0] == '2') break;
658             }
659            
660 0 0         if (!res->error && res->hostinfo) freeaddrinfo(res->hostinfo);
    0          
661 0 0         if (res->arg->hints) free(res->arg->hints);
662 0 0         if (res->arg->host) Safefree(res->arg->host);
663 0 0         if (res->arg->service) Safefree(res->arg->service);
664 0           free(res->arg);
665             }
666            
667 0           close(res->fd1);
668 0           close(fds[i]);
669 0           free(res);
670             }
671            
672 0           free(fds);
673             }
674            
675 16           queue_iterator *it = queue_iterator_new(DNS_instances);
676 16 50         while (!queue_iterator_end(it)) {
677 16 50         if (queue_at(DNS_instances, it) == self) {
678 16           queue_del(DNS_instances, it);
679 16           break;
680             }
681 0           queue_iterator_next(it);
682             }
683 16           queue_iterator_destroy(it);
684            
685 16           pthread_attr_destroy(&self->thread_attrs);
686 16           pthread_mutex_destroy(&self->mutex);
687 16           bstree_destroy(self->fd_map);
688 16           queue_destroy(self->tout_queue);
689 16           Safefree(self);
690              
691             void
692             pack_sockaddr_in6(int port, SV *sv_address)
693             PPCODE:
694             STRLEN len;
695 0 0         char *address = SvPV(sv_address, len);
696 0 0         if (len != 16)
697 0           croak("address length is %lu should be 16", len);
698            
699 0           struct sockaddr_in6 *addr = malloc(sizeof(struct sockaddr_in6));
700 0           memcpy(addr->sin6_addr.s6_addr, address, 16);
701 0           addr->sin6_family = AF_INET6;
702 0           addr->sin6_port = port;
703            
704 0 0         XPUSHs(sv_2mortal(newSVpvn((char*) addr, sizeof(struct sockaddr_in6))));
705              
706             void
707             unpack_sockaddr_in6(SV *sv_addr)
708             PPCODE:
709             STRLEN len;
710 6 50         char *addr = SvPV(sv_addr, len);
711 6 50         if (len != sizeof(struct sockaddr_in6))
712 0           croak("address length is %lu should be %lu", len, sizeof(struct sockaddr_in6));
713            
714 6           struct sockaddr_in6 *struct_addr = (struct sockaddr_in6*) addr;
715 6 50         XPUSHs(sv_2mortal(newSViv(struct_addr->sin6_port)));
716 6 50         XPUSHs(sv_2mortal(newSVpvn((char*)struct_addr->sin6_addr.s6_addr, 16)));
717              
718             int
719             _is_non_safe_symbols_loaded()
720             INIT:
721 0           char found = 0;
722             CODE:
723             #ifdef __linux__
724 0           dl_iterate_phdr(_dl_phdr_cb, (void*)&found);
725             #endif
726 0           RETVAL = found;
727             OUTPUT:
728             RETVAL