ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/EV-ADNS/ADNS.xs
Revision: 1.17
Committed: Sat May 17 20:37:17 2008 UTC (16 years, 2 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

# Content
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 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 ev_prepare_start (EV_DEFAULT, &pw);
24 }
25
26 static void
27 outstanding_dec (adns_state ads)
28 {
29 --outstanding;
30 }
31
32 struct ctx
33 {
34 SV *self;
35 adns_state ads;
36 adns_query query;
37 SV *cb;
38 };
39
40 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 static void
51 process (adns_state ads)
52 {
53 dSP;
54
55 for (;;)
56 {
57 int i;
58 adns_query q = 0;
59 adns_answer *a;
60 void *ctx;
61 SV *cb;
62 struct ctx *c;
63 int r = adns_check (ads, &q, &a, &ctx);
64
65 if (r)
66 break;
67
68 c = (struct ctx *)ctx;
69 cb = c->cb;
70 c->cb = 0; outstanding_dec (ads);
71 SvREFCNT_dec (c->self);
72
73 assert (cb);
74
75 PUSHMARK (SP);
76
77 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 {
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 break;
108
109 case adns_r_addr:
110 sv = newSVpv (inet_ntoa (a->rrs.addr [i].addr.inet.sin_addr), 0);
111 break;
112
113 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
130 sv = newRV_noinc ((SV *)av);
131 }
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
144 sv = newRV_noinc ((SV *)av);
145 }
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
156 sv = newRV_noinc ((SV *)av);
157 }
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
168 sv = newRV_noinc ((SV *)av);
169 }
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
186 sv = newRV_noinc ((SV *)av);
187 }
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
200 sv = newRV_noinc ((SV *)av);
201 }
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
214 sv = newRV_noinc ((SV *)av);
215 }
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 free (a);
231
232 PUTBACK;
233 call_sv (cb, G_VOID | G_DISCARD | G_EVAL);
234 SPAGAIN;
235
236 if (SvTRUE (ERRSV))
237 warn ("%s", SvPV_nolen (ERRSV));
238
239 SvREFCNT_dec (cb);
240 }
241 }
242
243 static void
244 update_now (EV_P)
245 {
246 ev_tstamp t = ev_now (EV_A);
247
248 tv_now.tv_sec = (long)t;
249 tv_now.tv_usec = (long)((t - (ev_tstamp)tv_now.tv_sec) * 1e6);
250 }
251
252 static void
253 idle_cb (EV_P_ ev_idle *w, int revents)
254 {
255 ev_idle_stop (EV_A, w);
256 }
257
258 static void
259 timer_cb (EV_P_ ev_timer *w, int revents)
260 {
261 adns_state ads = (adns_state)w->data;
262 update_now (EV_A);
263
264 adns_processtimeouts (ads, &tv_now);
265 }
266
267 static void
268 io_cb (EV_P_ ev_io *w, int revents)
269 {
270 adns_state ads = (adns_state)w->data;
271 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 adns_state ads = (adns_state)w->data;
284
285 if (ev_is_active (&tw))
286 ev_timer_stop (EV_A, &tw);
287
288 if (ev_is_active (&iw))
289 ev_idle_stop (EV_A, &iw);
290
291 for (i = 0; i < nfd; ++i)
292 ev_io_stop (EV_A, iow + i);
293
294 process (ads);
295
296 if (!outstanding)
297 {
298 ev_prepare_stop (EV_A, w);
299 return;
300 }
301
302 update_now (EV_A);
303
304 nfd = mfd;
305
306 while (adns_beforepoll (ads, fds, &nfd, &timeout, &tv_now))
307 {
308 mfd = nfd;
309
310 free (iow); iow = malloc (mfd * sizeof (ev_io));
311 free (fds); fds = malloc (mfd * sizeof (struct pollfd));
312 }
313
314 ev_timer_set (&tw, timeout * 1e-3, 0.);
315 ev_timer_start (EV_A, &tw);
316
317 // create one ev_io per pollfd
318 for (i = 0; i < nfd; ++i)
319 {
320 ev_io *w = iow + i;
321
322 ev_io_init (w, io_cb, fds [i].fd,
323 ((fds [i].events & POLLIN ? EV_READ : 0)
324 | (fds [i].events & POLLOUT ? EV_WRITE : 0)));
325
326 w->data = (void *)ads;
327 ev_io_start (EV_A, w);
328 }
329 }
330
331 static HV *stash;
332 static adns_state ads;
333
334 MODULE = EV::ADNS PACKAGE = EV::ADNS
335
336 PROTOTYPES: ENABLE
337
338 BOOT:
339 {
340 stash = gv_stashpv ("EV::ADNS", 1);
341
342 static const struct {
343 const char *name;
344 IV iv;
345 } *civ, const_iv[] = {
346 # define const_iv(name) { # name, (IV) adns_ ## name },
347 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 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
435 ev_init (&iw, idle_cb); ev_set_priority (&iw, EV_MINPRI);
436 iw.data = (void *)ads;
437 ev_init (&tw, timer_cb);
438 tw.data = (void *)ads;
439 }
440
441 void submit (char *owner, int type, int flags, SV *cb)
442 PPCODE:
443 {
444 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
448 outstanding_inc (ads);
449
450 if (r)
451 {
452 SvREFCNT_dec (csv);
453 errno = r;
454 XSRETURN_EMPTY;
455 }
456 else
457 {
458 SvPOK_only (csv);
459 SvCUR_set (csv, sizeof (struct ctx));
460
461 c->self = csv;
462 c->cb = newSVsv (cb);
463 c->ads = ads;
464
465 if (!ev_is_active (&iw))
466 ev_idle_start (EV_DEFAULT, &iw);
467
468 if (GIMME_V != G_VOID)
469 {
470 csv = sv_2mortal (newRV_inc (csv));
471 sv_bless (csv, stash);
472 XPUSHs (csv);
473 }
474 }
475 }
476
477 void DESTROY (SV *req)
478 ALIAS:
479 cancel = 1
480 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 SvREFCNT_dec (c->cb);
493 c->cb = 0; outstanding_dec (c->ads);
494 adns_cancel (c->query);
495 SvREFCNT_dec (c->self);
496 }
497 }
498
499
500
501