File Coverage

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