ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV-ADNS/ADNS.xs
Revision: 1.17
Committed: Sat May 17 20:37:17 2008 UTC (18 years, 4 months ago) by root
Branch: MAIN
CVS Tags: rel-2_1
Changes since 1.16: +4 -1 lines
Log Message:
*** empty log message ***

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