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