ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV-ADNS/ADNS.xs
Revision: 1.20
Committed: Fri Oct 16 22:58:35 2015 UTC (8 years, 7 months ago) by root
Branch: MAIN
CVS Tags: rel-3_0, HEAD
Changes since 1.19: +79 -27 lines
Log Message:
3.0

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include <poll.h>
6
7 #define ADNS_FEATURE_MANYAF
8 #include <adns.h>
9
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13
14 #include "EVAPI.h"
15
16 #define DEFAULT_INIT_FLAGS \
17 adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn \
18 | adns_if_noautosys | adns_if_permit_ipv4 | adns_if_permit_ipv6
19
20 static struct pollfd *fds;
21 static int nfd, mfd;
22 static ev_io *iow;
23 static ev_timer tw;
24 static ev_idle iw;
25 static ev_prepare pw;
26 static struct timeval tv_now;
27 static int outstanding;
28
29 static void
30 outstanding_inc (adns_state ads)
31 {
32 if (!outstanding++)
33 ev_prepare_start (EV_DEFAULT, &pw);
34 }
35
36 static void
37 outstanding_dec (adns_state ads)
38 {
39 --outstanding;
40 }
41
42 struct ctx
43 {
44 SV *self;
45 adns_state ads;
46 adns_query query;
47 SV *cb;
48 };
49
50 static SV *
51 ip_to_sv (int family, void *addr)
52 {
53 char buf[128];
54
55 return newSVpv (inet_ntop (family, addr, buf, sizeof buf), 0);
56 }
57
58 static SV *
59 addr_to_sv (adns_rr_addr *addr)
60 {
61 return ip_to_sv (addr->addr.sa.sa_family,
62 addr->addr.sa.sa_family == AF_INET6
63 ? (void *)&addr->addr.inet6.sin6_addr
64 : (void *)&addr->addr.inet.sin_addr);
65 }
66
67 static SV *
68 ha2sv (adns_rr_hostaddr *rr)
69 {
70 int i;
71 AV *av = newAV ();
72 av_push (av, newSVpv (rr->host, 0));
73 av_push (av, newSViv (rr->astatus));
74
75 for (i = 0; i < rr->naddrs; ++i)
76 av_push (av, addr_to_sv (rr->addrs + i));
77
78 return newRV_noinc ((SV *)av);
79 }
80
81 static void
82 process (adns_state ads)
83 {
84 dSP;
85
86 ENTER;
87 SAVETMPS;
88
89 for (;;)
90 {
91 int i;
92 adns_query q = 0;
93 adns_answer *a;
94 void *ctx;
95 SV *cb;
96 struct ctx *c;
97 int r = adns_check (ads, &q, &a, &ctx);
98
99 if (r)
100 break;
101
102 c = (struct ctx *)ctx;
103 cb = c->cb;
104 c->cb = 0; outstanding_dec (ads);
105 SvREFCNT_dec (c->self);
106
107 assert (cb);
108
109 PUSHMARK (SP);
110
111 EXTEND (SP, a->nrrs + 2);
112 PUSHs (sv_2mortal (newSViv (a->status)));
113 PUSHs (sv_2mortal (newSViv (a->expires)));
114
115 for (i = 0; i < a->nrrs; ++i)
116 {
117 SV *sv;
118
119 switch (a->type & adns_r_unknown ? adns_r_unknown : a->type)
120 {
121 case adns_r_ns_raw:
122 case adns_r_cname:
123 case adns_r_ptr:
124 case adns_r_ptr_raw:
125 sv = newSVpv (a->rrs.str [i], 0);
126 break;
127
128 case adns_r_txt:
129 {
130 AV *av = newAV ();
131 adns_rr_intstr *rr = a->rrs.manyistr [i];
132
133 while (rr->str)
134 {
135 av_push (av, newSVpvn (rr->str, rr->i));
136 ++rr;
137 }
138
139 sv = newRV_noinc ((SV *)av);
140 }
141 break;
142
143 case adns_r_addr:
144 sv = addr_to_sv (a->rrs.addr + i);
145 break;
146
147 case adns_r_a:
148 sv = ip_to_sv (AF_INET, a->rrs.inaddr + i);
149 break;
150
151 case adns_r_aaaa:
152 sv = ip_to_sv (AF_INET6, a->rrs.in6addr + i);
153 break;
154
155 case adns_r_ns:
156 sv = ha2sv (a->rrs.hostaddr + i);
157 break;
158
159 case adns_r_hinfo:
160 {
161 /* untested */
162 AV *av = newAV ();
163 adns_rr_intstrpair *rr = a->rrs.intstrpair + i;
164
165 av_push (av, newSVpvn (rr->array [0].str, rr->array [0].i));
166 av_push (av, newSVpvn (rr->array [1].str, rr->array [1].i));
167
168 sv = newRV_noinc ((SV *)av);
169 }
170 break;
171
172 case adns_r_rp:
173 case adns_r_rp_raw:
174 {
175 /* untested */
176 AV *av = newAV ();
177 adns_rr_strpair *rr = a->rrs.strpair + i;
178
179 av_push (av, newSVpv (rr->array [0], 0));
180 av_push (av, newSVpv (rr->array [1], 0));
181
182 sv = newRV_noinc ((SV *)av);
183 }
184 break;
185
186 case adns_r_mx:
187 {
188 AV *av = newAV ();
189 adns_rr_inthostaddr *rr = a->rrs.inthostaddr + i;
190
191 av_push (av, newSViv (rr->i));
192 av_push (av, ha2sv (&rr->ha));
193
194 sv = newRV_noinc ((SV *)av);
195 }
196 break;
197
198 case adns_r_mx_raw:
199 {
200 AV *av = newAV ();
201 adns_rr_intstr *rr = a->rrs.intstr + i;
202
203 av_push (av, newSViv (rr->i));
204 av_push (av, newSVpv (rr->str, 0));
205
206 sv = newRV_noinc ((SV *)av);
207 }
208 break;
209
210 case adns_r_soa:
211 case adns_r_soa_raw:
212 {
213 AV *av = newAV ();
214 adns_rr_soa *rr = a->rrs.soa + i;
215
216 av_push (av, newSVpv (rr->mname, 0));
217 av_push (av, newSVpv (rr->rname, 0));
218 av_push (av, newSVuv (rr->serial));
219 av_push (av, newSVuv (rr->refresh));
220 av_push (av, newSVuv (rr->retry));
221 av_push (av, newSVuv (rr->expire));
222 av_push (av, newSVuv (rr->minimum));
223
224 sv = newRV_noinc ((SV *)av);
225 }
226 break;
227
228 case adns_r_srv_raw:
229 {
230 AV *av = newAV ();
231 adns_rr_srvraw *rr = a->rrs.srvraw + i;
232
233 av_push (av, newSViv (rr->priority));
234 av_push (av, newSViv (rr->weight));
235 av_push (av, newSViv (rr->port));
236 av_push (av, newSVpv (rr->host, 0));
237
238 sv = newRV_noinc ((SV *)av);
239 }
240 break;
241
242 case adns_r_srv:
243 {
244 AV *av = newAV ();
245 adns_rr_srvha *rr = a->rrs.srvha + i;
246
247 av_push (av, newSViv (rr->priority));
248 av_push (av, newSViv (rr->weight));
249 av_push (av, newSViv (rr->port));
250 av_push (av, ha2sv (&rr->ha));
251
252 sv = newRV_noinc ((SV *)av);
253 }
254 break;
255
256 case adns_r_unknown:
257 sv = newSVpvn (a->rrs.byteblock [i].data, a->rrs.byteblock [i].len);
258 break;
259
260 default:
261 sv = newSV (0); /* not supported */
262 break;
263 }
264
265 PUSHs (sv_2mortal (sv));
266 }
267
268 free (a);
269
270 PUTBACK;
271 call_sv (cb, G_VOID | G_DISCARD | G_EVAL);
272 SPAGAIN;
273
274 if (SvTRUE (ERRSV))
275 warn ("%s", SvPV_nolen (ERRSV));
276
277 SvREFCNT_dec (cb);
278 }
279
280 FREETMPS;
281 LEAVE;
282 }
283
284 static void
285 update_now (EV_P)
286 {
287 ev_tstamp t = ev_now (EV_A);
288
289 tv_now.tv_sec = (long)t;
290 tv_now.tv_usec = (long)((t - (ev_tstamp)tv_now.tv_sec) * 1e6);
291 }
292
293 static void
294 idle_cb (EV_P_ ev_idle *w, int revents)
295 {
296 ev_idle_stop (EV_A, w);
297 }
298
299 static void
300 timer_cb (EV_P_ ev_timer *w, int revents)
301 {
302 adns_state ads = (adns_state)w->data;
303 update_now (EV_A);
304
305 adns_processtimeouts (ads, &tv_now);
306 }
307
308 static void
309 io_cb (EV_P_ ev_io *w, int revents)
310 {
311 adns_state ads = (adns_state)w->data;
312 update_now (EV_A);
313
314 if (revents & EV_READ ) adns_processreadable (ads, w->fd, &tv_now);
315 if (revents & EV_WRITE) adns_processwriteable (ads, w->fd, &tv_now);
316 }
317
318 // create io watchers for each fd and a timer before blocking
319 static void
320 prepare_cb (EV_P_ ev_prepare *w, int revents)
321 {
322 int i;
323 int timeout = 3600000;
324 adns_state ads = (adns_state)w->data;
325
326 if (ev_is_active (&tw))
327 ev_timer_stop (EV_A, &tw);
328
329 if (ev_is_active (&iw))
330 ev_idle_stop (EV_A, &iw);
331
332 for (i = 0; i < nfd; ++i)
333 ev_io_stop (EV_A, iow + i);
334
335 process (ads);
336
337 if (!outstanding)
338 {
339 ev_prepare_stop (EV_A, w);
340 return;
341 }
342
343 update_now (EV_A);
344
345 nfd = mfd;
346
347 while (adns_beforepoll (ads, fds, &nfd, &timeout, &tv_now))
348 {
349 mfd = nfd;
350
351 free (iow); iow = malloc (mfd * sizeof (ev_io));
352 free (fds); fds = malloc (mfd * sizeof (struct pollfd));
353 }
354
355 ev_timer_set (&tw, timeout * 1e-3, 0.);
356 ev_timer_start (EV_A, &tw);
357
358 // create one ev_io per pollfd
359 for (i = 0; i < nfd; ++i)
360 {
361 ev_io *w = iow + i;
362
363 ev_io_init (w, io_cb, fds [i].fd,
364 ((fds [i].events & POLLIN ? EV_READ : 0)
365 | (fds [i].events & POLLOUT ? EV_WRITE : 0)));
366
367 w->data = (void *)ads;
368 ev_io_start (EV_A, w);
369 }
370 }
371
372 static HV *stash;
373 static adns_state ads;
374
375 MODULE = EV::ADNS PACKAGE = EV::ADNS
376
377 PROTOTYPES: ENABLE
378
379 BOOT:
380 {
381 stash = gv_stashpv ("EV::ADNS", 1);
382
383 static const struct {
384 const char *name;
385 IV iv;
386 } *civ, const_iv[] = {
387 # define const_iv(name) { # name, (IV) adns_ ## name },
388 const_iv (if_none)
389 const_iv (if_noenv)
390 const_iv (if_noerrprint)
391 const_iv (if_noserverwarn)
392 const_iv (if_debug)
393 const_iv (if_logpid)
394 const_iv (if_noautosys)
395 const_iv (if_eintr)
396 const_iv (if_nosigpipe)
397 const_iv (if_checkc_entex)
398 const_iv (if_checkc_freq)
399 const_iv (if_permit_ipv4)
400 const_iv (if_permit_ipv6)
401 const_iv (if_afmask)
402
403 const_iv (qf_none)
404 const_iv (qf_search)
405 const_iv (qf_usevc)
406 const_iv (qf_owner)
407 const_iv (qf_quoteok_query)
408 const_iv (qf_quoteok_cname)
409 const_iv (qf_quoteok_anshost)
410 const_iv (qf_quotefail_cname)
411 const_iv (qf_cname_loose)
412 const_iv (qf_cname_strict)
413 const_iv (qf_cname_forbid)
414 const_iv (qf_want_ipv4)
415 const_iv (qf_want_ipv6)
416 const_iv (qf_want_allaf)
417 const_iv (qf_ipv6_mapv4)
418 const_iv (qf_addrlit_scope_forbid)
419 const_iv (qf_addrlit_scope_numeric)
420 const_iv (qf_addrlit_ipv4_quadonly)
421
422 const_iv (rrt_typemask)
423 const_iv (rrt_reprmask)
424 const_iv (r_unknown)
425 const_iv (r_none)
426 const_iv (r_a)
427 const_iv (r_ns_raw)
428 const_iv (r_ns)
429 const_iv (r_cname)
430 const_iv (r_soa_raw)
431 const_iv (r_soa)
432 const_iv (r_ptr_raw)
433 const_iv (r_ptr)
434 const_iv (r_hinfo)
435 const_iv (r_mx_raw)
436 const_iv (r_mx)
437 const_iv (r_txt)
438 const_iv (r_rp_raw)
439 const_iv (r_rp)
440 const_iv (r_aaaa)
441 const_iv (r_srv_raw)
442 const_iv (r_srv)
443 const_iv (r_addr)
444
445 const_iv (s_ok)
446 const_iv (s_nomemory)
447 const_iv (s_unknownrrtype)
448 const_iv (s_systemfail)
449 const_iv (s_max_localfail)
450 const_iv (s_timeout)
451 const_iv (s_allservfail)
452 const_iv (s_norecurse)
453 const_iv (s_invalidresponse)
454 const_iv (s_unknownformat)
455 const_iv (s_max_remotefail)
456 const_iv (s_rcodeservfail)
457 const_iv (s_rcodeformaterror)
458 const_iv (s_rcodenotimplemented)
459 const_iv (s_rcoderefused)
460 const_iv (s_rcodeunknown)
461 const_iv (s_max_tempfail)
462 const_iv (s_inconsistent)
463 const_iv (s_prohibitedcname)
464 const_iv (s_answerdomaininvalid)
465 const_iv (s_answerdomaintoolong)
466 const_iv (s_invaliddata)
467 const_iv (s_max_misconfig)
468 const_iv (s_querydomainwrong)
469 const_iv (s_querydomaininvalid)
470 const_iv (s_querydomaintoolong)
471 const_iv (s_max_misquery)
472 const_iv (s_nxdomain)
473 const_iv (s_nodata)
474 const_iv (s_max_permfail)
475 };
476
477 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
478 newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
479
480 I_EV_API ("EV::ADNS");
481
482 adns_init (&ads, DEFAULT_INIT_FLAGS, 0);
483
484 ev_prepare_init (&pw, prepare_cb);
485 pw.data = (void *)ads;
486
487 ev_init (&iw, idle_cb); ev_set_priority (&iw, EV_MINPRI);
488 iw.data = (void *)ads;
489 ev_init (&tw, timer_cb);
490 tw.data = (void *)ads;
491 }
492
493 int
494 reinit (SV *flags = &PL_sv_undef, SV *str = &PL_sv_undef)
495 CODE:
496 {
497 int initflags = SvOK (flags) ? SvIV (flags) : DEFAULT_INIT_FLAGS;
498 adns_finish (ads);
499 adns_init_logfn (&ads, initflags, SvOK (str) ? SvPVbyte_nolen (str) : 0, 0, 0);
500 }
501
502 void submit (char *owner, int type, int flags, SV *cb)
503 PPCODE:
504 {
505 SV *csv = NEWSV (0, sizeof (struct ctx));
506 struct ctx *c = (struct ctx *)SvPVX (csv);
507 int r = adns_submit (ads, owner, type, flags, (void *)c, &c->query);
508
509 outstanding_inc (ads);
510
511 if (r)
512 {
513 SvREFCNT_dec (csv);
514 croak ("EV::ADNS::submit: %s", strerror ((errno = r)));
515 }
516
517 SvPOK_only (csv);
518 SvCUR_set (csv, sizeof (struct ctx));
519
520 c->self = csv;
521 c->cb = newSVsv (cb);
522 c->ads = ads;
523
524 if (!ev_is_active (&iw))
525 ev_idle_start (EV_DEFAULT, &iw);
526
527 if (GIMME_V != G_VOID)
528 {
529 csv = sv_2mortal (newRV_inc (csv));
530 sv_bless (csv, stash);
531 XPUSHs (csv);
532 }
533 }
534
535 void DESTROY (SV *req)
536 ALIAS:
537 cancel = 1
538 CODE:
539 {
540 struct ctx *c;
541
542 if (!(SvROK (req) && SvOBJECT (SvRV (req))
543 && (SvSTASH (SvRV (req)) == stash)))
544 croak ("object is not of type EV::ADNS");
545
546 c = (struct ctx *)SvPVX (SvRV (req));
547
548 if (c->cb)
549 {
550 SvREFCNT_dec (c->cb);
551 c->cb = 0; outstanding_dec (c->ads);
552 adns_cancel (c->query);
553 SvREFCNT_dec (c->self);
554 }
555 }
556