ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/EV-ADNS/ADNS.xs
Revision: 1.19
Committed: Fri Jul 29 08:35:36 2011 UTC (13 years ago) by root
Branch: MAIN
CVS Tags: rel-2_3
Changes since 1.18: +2 -2 lines
Log Message:
avoid triggering undefined behaviour

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 ENTER;
56 SAVETMPS;
57
58 for (;;)
59 {
60 int i;
61 adns_query q = 0;
62 adns_answer *a;
63 void *ctx;
64 SV *cb;
65 struct ctx *c;
66 int r = adns_check (ads, &q, &a, &ctx);
67
68 if (r)
69 break;
70
71 c = (struct ctx *)ctx;
72 cb = c->cb;
73 c->cb = 0; outstanding_dec (ads);
74 SvREFCNT_dec (c->self);
75
76 assert (cb);
77
78 PUSHMARK (SP);
79
80 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 {
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 break;
111
112 case adns_r_addr:
113 sv = newSVpv (inet_ntoa (a->rrs.addr [i].addr.inet.sin_addr), 0);
114 break;
115
116 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
133 sv = newRV_noinc ((SV *)av);
134 }
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
147 sv = newRV_noinc ((SV *)av);
148 }
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
159 sv = newRV_noinc ((SV *)av);
160 }
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
171 sv = newRV_noinc ((SV *)av);
172 }
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
189 sv = newRV_noinc ((SV *)av);
190 }
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
203 sv = newRV_noinc ((SV *)av);
204 }
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
217 sv = newRV_noinc ((SV *)av);
218 }
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 free (a);
234
235 PUTBACK;
236 call_sv (cb, G_VOID | G_DISCARD | G_EVAL);
237 SPAGAIN;
238
239 if (SvTRUE (ERRSV))
240 warn ("%s", SvPV_nolen (ERRSV));
241
242 SvREFCNT_dec (cb);
243 }
244
245 FREETMPS;
246 LEAVE;
247 }
248
249 static void
250 update_now (EV_P)
251 {
252 ev_tstamp t = ev_now (EV_A);
253
254 tv_now.tv_sec = (long)t;
255 tv_now.tv_usec = (long)((t - (ev_tstamp)tv_now.tv_sec) * 1e6);
256 }
257
258 static void
259 idle_cb (EV_P_ ev_idle *w, int revents)
260 {
261 ev_idle_stop (EV_A, w);
262 }
263
264 static void
265 timer_cb (EV_P_ ev_timer *w, int revents)
266 {
267 adns_state ads = (adns_state)w->data;
268 update_now (EV_A);
269
270 adns_processtimeouts (ads, &tv_now);
271 }
272
273 static void
274 io_cb (EV_P_ ev_io *w, int revents)
275 {
276 adns_state ads = (adns_state)w->data;
277 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 adns_state ads = (adns_state)w->data;
290
291 if (ev_is_active (&tw))
292 ev_timer_stop (EV_A, &tw);
293
294 if (ev_is_active (&iw))
295 ev_idle_stop (EV_A, &iw);
296
297 for (i = 0; i < nfd; ++i)
298 ev_io_stop (EV_A, iow + i);
299
300 process (ads);
301
302 if (!outstanding)
303 {
304 ev_prepare_stop (EV_A, w);
305 return;
306 }
307
308 update_now (EV_A);
309
310 nfd = mfd;
311
312 while (adns_beforepoll (ads, fds, &nfd, &timeout, &tv_now))
313 {
314 mfd = nfd;
315
316 free (iow); iow = malloc (mfd * sizeof (ev_io));
317 free (fds); fds = malloc (mfd * sizeof (struct pollfd));
318 }
319
320 ev_timer_set (&tw, timeout * 1e-3, 0.);
321 ev_timer_start (EV_A, &tw);
322
323 // create one ev_io per pollfd
324 for (i = 0; i < nfd; ++i)
325 {
326 ev_io *w = iow + i;
327
328 ev_io_init (w, io_cb, fds [i].fd,
329 ((fds [i].events & POLLIN ? EV_READ : 0)
330 | (fds [i].events & POLLOUT ? EV_WRITE : 0)));
331
332 w->data = (void *)ads;
333 ev_io_start (EV_A, w);
334 }
335 }
336
337 static HV *stash;
338 static adns_state ads;
339
340 MODULE = EV::ADNS PACKAGE = EV::ADNS
341
342 PROTOTYPES: ENABLE
343
344 BOOT:
345 {
346 stash = gv_stashpv ("EV::ADNS", 1);
347
348 static const struct {
349 const char *name;
350 IV iv;
351 } *civ, const_iv[] = {
352 # define const_iv(name) { # name, (IV) adns_ ## name },
353 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; civ--)
432 newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
433
434 I_EV_API ("EV::ADNS");
435
436 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
441 ev_init (&iw, idle_cb); ev_set_priority (&iw, EV_MINPRI);
442 iw.data = (void *)ads;
443 ev_init (&tw, timer_cb);
444 tw.data = (void *)ads;
445 }
446
447 void submit (char *owner, int type, int flags, SV *cb)
448 PPCODE:
449 {
450 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
454 outstanding_inc (ads);
455
456 if (r)
457 {
458 SvREFCNT_dec (csv);
459 errno = r;
460 XSRETURN_EMPTY;
461 }
462 else
463 {
464 SvPOK_only (csv);
465 SvCUR_set (csv, sizeof (struct ctx));
466
467 c->self = csv;
468 c->cb = newSVsv (cb);
469 c->ads = ads;
470
471 if (!ev_is_active (&iw))
472 ev_idle_start (EV_DEFAULT, &iw);
473
474 if (GIMME_V != G_VOID)
475 {
476 csv = sv_2mortal (newRV_inc (csv));
477 sv_bless (csv, stash);
478 XPUSHs (csv);
479 }
480 }
481 }
482
483 void DESTROY (SV *req)
484 ALIAS:
485 cancel = 1
486 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 SvREFCNT_dec (c->cb);
499 c->cb = 0; outstanding_dec (c->ads);
500 adns_cancel (c->query);
501 SvREFCNT_dec (c->self);
502 }
503 }
504