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

# 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 struct ctx
11 {
12 SV *self;
13 adns_query query;
14 SV *cb;
15 };
16
17 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 static void
28 process (adns_state ads)
29 {
30 dSP;
31
32 for (;;)
33 {
34 int i;
35 adns_query q = 0;
36 adns_answer *a;
37 void *ctx;
38 SV *cb;
39 struct ctx *c;
40 int r = adns_check (ads, &q, &a, &ctx);
41
42 if (r)
43 break;
44
45 c = (struct ctx *)ctx;
46 cb = c->cb;
47 c->cb = 0;
48 ev_unref (EV_A);
49 SvREFCNT_dec (c->self);
50
51 PUSHMARK (SP);
52
53 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 {
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 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
102 sv = newRV_noinc ((SV *)av);
103 }
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
116 sv = newRV_noinc ((SV *)av);
117 }
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
128 sv = newRV_noinc ((SV *)av);
129 }
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
140 sv = newRV_noinc ((SV *)av);
141 }
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
158 sv = newRV_noinc ((SV *)av);
159 }
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
172 sv = newRV_noinc ((SV *)av);
173 }
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
186 sv = newRV_noinc ((SV *)av);
187 }
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 free (a);
204
205 PUTBACK;
206 call_sv (cb, G_VOID | G_DISCARD | G_EVAL);
207 SPAGAIN;
208
209 SvREFCNT_dec (cb);
210 }
211 }
212
213 static struct pollfd *fds;
214 static int nfd, mfd;
215 static ev_io *iow;
216 static ev_timer tw;
217 static ev_idle iw;
218 static ev_prepare pw;
219 static struct timeval tv_now;
220
221 static void
222 update_now (EV_P)
223 {
224 ev_tstamp t = ev_now (EV_A);
225
226 tv_now.tv_sec = (long)t;
227 tv_now.tv_usec = (long)((t - (ev_tstamp)tv_now.tv_sec) * 1e6);
228 }
229
230 static void
231 idle_cb (EV_P_ ev_idle *w, int revents)
232 {
233 ev_idle_stop (EV_A_ w);
234 }
235
236 static void
237 timer_cb (EV_P_ ev_timer *w, int revents)
238 {
239 adns_state ads = (adns_state)w->data;
240 update_now (EV_A);
241
242 adns_processtimeouts (ads, &tv_now);
243 }
244
245 static void
246 io_cb (EV_P_ ev_io *w, int revents)
247 {
248 adns_state ads = (adns_state)w->data;
249 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 adns_state ads = (adns_state)w->data;
262
263 if (ev_is_active (&tw))
264 {
265 ev_ref (EV_A);
266 ev_timer_stop (EV_A_ &tw);
267 }
268
269 if (ev_is_active (&iw))
270 ev_idle_stop (EV_A_ &iw);
271
272 for (i = 0; i < nfd; ++i)
273 {
274 ev_ref (EV_A);
275 ev_io_stop (EV_A_ iow + i);
276 }
277
278 process (ads);
279 update_now (EV_A);
280
281 nfd = mfd;
282
283 while (adns_beforepoll (ads, fds, &nfd, &timeout, &tv_now))
284 {
285 mfd = nfd;
286
287 free (iow); iow = malloc (mfd * sizeof (ev_io));
288 free (fds); fds = malloc (mfd * sizeof (struct pollfd));
289 }
290
291 ev_timer_set (&tw, timeout * 1e-3, 0.);
292 ev_timer_start (EV_A_ &tw);
293 ev_unref (EV_A);
294
295 // create one ev_io per pollfd
296 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 ev_unref (EV_A);
304 }
305 }
306
307 static HV *stash;
308 static adns_state ads;
309
310 MODULE = EV::ADNS PACKAGE = EV::ADNS
311
312 PROTOTYPES: ENABLE
313
314 BOOT:
315 {
316 stash = gv_stashpv ("EV::ADNS", 1);
317
318 static const struct {
319 const char *name;
320 IV iv;
321 } *civ, const_iv[] = {
322 # define const_iv(name) { # name, (IV) adns_ ## name },
323 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 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 ev_unref (EV_A);
412
413 ev_init (&iw, idle_cb); ev_set_priority (&iw, EV_MINPRI);
414 iw.data = (void *)ads;
415 ev_init (&tw, timer_cb);
416 tw.data = (void *)ads;
417 }
418
419 void submit (char *owner, int type, int flags, SV *cb)
420 PPCODE:
421 {
422 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
426 if (r)
427 {
428 SvREFCNT_dec (csv);
429 errno = r;
430 XSRETURN_EMPTY;
431 }
432 else
433 {
434 ev_ref (EV_A);
435 SvPOK_only (csv);
436 SvCUR_set (csv, sizeof (struct ctx));
437
438 c->self = csv;
439 c->cb = newSVsv (cb);
440
441 if (!ev_is_active (&iw))
442 ev_idle_start (EV_A_ &iw);
443
444 if (GIMME_V != G_VOID)
445 {
446 csv = sv_2mortal (newRV_inc (csv));
447 sv_bless (csv, stash);
448 XPUSHs (csv);
449 }
450 }
451 }
452
453 void DESTROY (SV *req)
454 ALIAS:
455 cancel = 1
456 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 ev_unref (EV_A);
469 SvREFCNT_dec (c->cb);
470 c->cb = 0;
471 adns_cancel (c->query);
472 SvREFCNT_dec (c->self);
473 }
474 }
475
476
477
478