File Coverage

Native.xs
Criterion Covered Total %
statement 292 409 71.3
branch 149 278 53.6
condition n/a
subroutine n/a
pod n/a
total 441 687 64.1


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