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 (10 years, 11 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

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5     #include <poll.h>
6 root 1.20
7     #define ADNS_FEATURE_MANYAF
8 root 1.1 #include <adns.h>
9    
10 root 1.20 #include <sys/socket.h>
11     #include <netinet/in.h>
12     #include <arpa/inet.h>
13    
14 root 1.1 #include "EVAPI.h"
15    
16 root 1.20 #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 root 1.15 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 root 1.16 ev_prepare_start (EV_DEFAULT, &pw);
34 root 1.15 }
35    
36     static void
37     outstanding_dec (adns_state ads)
38     {
39     --outstanding;
40     }
41    
42 root 1.1 struct ctx
43     {
44 root 1.2 SV *self;
45 root 1.15 adns_state ads;
46 root 1.2 adns_query query;
47 root 1.1 SV *cb;
48     };
49    
50 root 1.6 static SV *
51 root 1.20 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 root 1.6 ha2sv (adns_rr_hostaddr *rr)
69     {
70 root 1.20 int i;
71 root 1.6 AV *av = newAV ();
72     av_push (av, newSVpv (rr->host, 0));
73 root 1.20 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 root 1.6
78     return newRV_noinc ((SV *)av);
79     }
80    
81 root 1.1 static void
82 root 1.12 process (adns_state ads)
83 root 1.1 {
84 root 1.3 dSP;
85    
86 root 1.18 ENTER;
87     SAVETMPS;
88    
89 root 1.1 for (;;)
90     {
91 root 1.6 int i;
92 root 1.4 adns_query q = 0;
93 root 1.1 adns_answer *a;
94 root 1.3 void *ctx;
95     SV *cb;
96     struct ctx *c;
97     int r = adns_check (ads, &q, &a, &ctx);
98 root 1.1
99     if (r)
100     break;
101 root 1.3
102     c = (struct ctx *)ctx;
103     cb = c->cb;
104 root 1.15 c->cb = 0; outstanding_dec (ads);
105 root 1.6 SvREFCNT_dec (c->self);
106 root 1.3
107 root 1.15 assert (cb);
108    
109 root 1.5 PUSHMARK (SP);
110    
111 root 1.6 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 root 1.8 {
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 root 1.6 break;
142    
143 root 1.17 case adns_r_addr:
144 root 1.20 sv = addr_to_sv (a->rrs.addr + i);
145 root 1.17 break;
146    
147 root 1.6 case adns_r_a:
148 root 1.20 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 root 1.6 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 root 1.8
168     sv = newRV_noinc ((SV *)av);
169 root 1.6 }
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 root 1.8
182     sv = newRV_noinc ((SV *)av);
183 root 1.6 }
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 root 1.8
194     sv = newRV_noinc ((SV *)av);
195 root 1.6 }
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 root 1.8
206     sv = newRV_noinc ((SV *)av);
207 root 1.6 }
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 root 1.8
224     sv = newRV_noinc ((SV *)av);
225 root 1.6 }
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 root 1.8
238     sv = newRV_noinc ((SV *)av);
239 root 1.6 }
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 root 1.8
252     sv = newRV_noinc ((SV *)av);
253 root 1.6 }
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 root 1.20 sv = newSV (0); /* not supported */
262 root 1.6 break;
263     }
264    
265     PUSHs (sv_2mortal (sv));
266     }
267    
268 root 1.4 free (a);
269    
270     PUTBACK;
271 root 1.5 call_sv (cb, G_VOID | G_DISCARD | G_EVAL);
272 root 1.4 SPAGAIN;
273 root 1.3
274 root 1.15 if (SvTRUE (ERRSV))
275     warn ("%s", SvPV_nolen (ERRSV));
276    
277 root 1.3 SvREFCNT_dec (cb);
278 root 1.1 }
279 root 1.18
280     FREETMPS;
281     LEAVE;
282 root 1.1 }
283    
284     static void
285     update_now (EV_P)
286     {
287 root 1.13 ev_tstamp t = ev_now (EV_A);
288 root 1.1
289 root 1.2 tv_now.tv_sec = (long)t;
290 root 1.10 tv_now.tv_usec = (long)((t - (ev_tstamp)tv_now.tv_sec) * 1e6);
291 root 1.1 }
292    
293     static void
294 root 1.9 idle_cb (EV_P_ ev_idle *w, int revents)
295     {
296 root 1.16 ev_idle_stop (EV_A, w);
297 root 1.9 }
298    
299     static void
300 root 1.1 timer_cb (EV_P_ ev_timer *w, int revents)
301     {
302 root 1.12 adns_state ads = (adns_state)w->data;
303 root 1.13 update_now (EV_A);
304 root 1.10
305     adns_processtimeouts (ads, &tv_now);
306 root 1.1 }
307    
308     static void
309     io_cb (EV_P_ ev_io *w, int revents)
310     {
311 root 1.12 adns_state ads = (adns_state)w->data;
312 root 1.1 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 root 1.12 adns_state ads = (adns_state)w->data;
325 root 1.1
326 root 1.6 if (ev_is_active (&tw))
327 root 1.16 ev_timer_stop (EV_A, &tw);
328 root 1.1
329 root 1.9 if (ev_is_active (&iw))
330 root 1.16 ev_idle_stop (EV_A, &iw);
331 root 1.9
332 root 1.1 for (i = 0; i < nfd; ++i)
333 root 1.16 ev_io_stop (EV_A, iow + i);
334 root 1.15
335     process (ads);
336    
337     if (!outstanding)
338 root 1.6 {
339 root 1.16 ev_prepare_stop (EV_A, w);
340 root 1.15 return;
341 root 1.6 }
342 root 1.1
343     update_now (EV_A);
344    
345 root 1.4 nfd = mfd;
346    
347 root 1.1 while (adns_beforepoll (ads, fds, &nfd, &timeout, &tv_now))
348     {
349 root 1.4 mfd = nfd;
350    
351 root 1.7 free (iow); iow = malloc (mfd * sizeof (ev_io));
352     free (fds); fds = malloc (mfd * sizeof (struct pollfd));
353 root 1.1 }
354    
355     ev_timer_set (&tw, timeout * 1e-3, 0.);
356 root 1.16 ev_timer_start (EV_A, &tw);
357 root 1.1
358 root 1.4 // create one ev_io per pollfd
359 root 1.1 for (i = 0; i < nfd; ++i)
360     {
361 root 1.14 ev_io *w = iow + i;
362    
363     ev_io_init (w, io_cb, fds [i].fd,
364 root 1.1 ((fds [i].events & POLLIN ? EV_READ : 0)
365     | (fds [i].events & POLLOUT ? EV_WRITE : 0)));
366    
367 root 1.14 w->data = (void *)ads;
368 root 1.16 ev_io_start (EV_A, w);
369 root 1.1 }
370     }
371    
372 root 1.12 static HV *stash;
373     static adns_state ads;
374    
375 root 1.1 MODULE = EV::ADNS PACKAGE = EV::ADNS
376    
377     PROTOTYPES: ENABLE
378    
379     BOOT:
380     {
381 root 1.2 stash = gv_stashpv ("EV::ADNS", 1);
382 root 1.1
383     static const struct {
384     const char *name;
385     IV iv;
386     } *civ, const_iv[] = {
387 root 1.3 # define const_iv(name) { # name, (IV) adns_ ## name },
388 root 1.1 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 root 1.20 const_iv (if_permit_ipv4)
400     const_iv (if_permit_ipv6)
401     const_iv (if_afmask)
402 root 1.1
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 root 1.20 const_iv (qf_cname_strict)
413 root 1.1 const_iv (qf_cname_forbid)
414 root 1.20 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 root 1.1
422     const_iv (rrt_typemask)
423 root 1.20 const_iv (rrt_reprmask)
424 root 1.1 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 root 1.20 const_iv (r_aaaa)
441 root 1.1 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 root 1.19 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 root 1.1
480     I_EV_API ("EV::ADNS");
481    
482 root 1.20 adns_init (&ads, DEFAULT_INIT_FLAGS, 0);
483 root 1.12
484     ev_prepare_init (&pw, prepare_cb);
485     pw.data = (void *)ads;
486 root 1.1
487 root 1.11 ev_init (&iw, idle_cb); ev_set_priority (&iw, EV_MINPRI);
488 root 1.12 iw.data = (void *)ads;
489 root 1.1 ev_init (&tw, timer_cb);
490 root 1.12 tw.data = (void *)ads;
491 root 1.1 }
492    
493 root 1.20 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 root 1.3 void submit (char *owner, int type, int flags, SV *cb)
503 root 1.2 PPCODE:
504 root 1.1 {
505 root 1.2 SV *csv = NEWSV (0, sizeof (struct ctx));
506 root 1.20 struct ctx *c = (struct ctx *)SvPVX (csv);
507 root 1.2 int r = adns_submit (ads, owner, type, flags, (void *)c, &c->query);
508 root 1.1
509 root 1.15 outstanding_inc (ads);
510    
511 root 1.1 if (r)
512     {
513 root 1.2 SvREFCNT_dec (csv);
514 root 1.20 croak ("EV::ADNS::submit: %s", strerror ((errno = r)));
515 root 1.1 }
516 root 1.20
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 root 1.2 {
529 root 1.20 csv = sv_2mortal (newRV_inc (csv));
530     sv_bless (csv, stash);
531     XPUSHs (csv);
532 root 1.2 }
533 root 1.1 }
534    
535 root 1.2 void DESTROY (SV *req)
536 root 1.6 ALIAS:
537     cancel = 1
538 root 1.2 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 root 1.6 SvREFCNT_dec (c->cb);
551 root 1.15 c->cb = 0; outstanding_dec (c->ads);
552 root 1.2 adns_cancel (c->query);
553 root 1.6 SvREFCNT_dec (c->self);
554 root 1.2 }
555     }
556