ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV-ADNS/ADNS.xs
Revision: 1.18
Committed: Fri May 7 21:42:36 2010 UTC (16 years, 4 months ago) by root
Branch: MAIN
CVS Tags: rel-2_2
Changes since 1.17: +6 -3 lines
Log Message:
2.2

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