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