#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include "EVAPI.h" static HV *stash; static adns_state ads; struct ctx { SV *self; adns_query query; SV *cb; }; static void process () { dSP; for (;;) { adns_query q = 0; adns_answer *a; void *ctx; SV *cb; struct ctx *c; int r = adns_check (ads, &q, &a, &ctx); printf ("check %d\n", r);//D if (r) break; c = (struct ctx *)ctx; cb = c->cb; c->cb = 0; ev_unref (); PUSHMARK (SP); XPUSHs (sv_2mortal (newSViv (a->status))); free (a); PUTBACK; call_sv (cb, G_VOID | G_DISCARD | G_EVAL); SPAGAIN; SvREFCNT_dec (cb); SvREFCNT_dec (c->self); } } static struct pollfd *fds; static int nfd, mfd; static ev_io *iow; static ev_timer tw; static ev_prepare prepare_ev; static struct timeval tv_now; static void update_now (EV_P) { ev_tstamp t = ev_now (); tv_now.tv_sec = (long)t; tv_now.tv_usec = (long)((t - (ev_tstamp)tv_now.tv_sec) * 1e-6); } static void timer_cb (EV_P_ ev_timer *w, int revents) { } static void io_cb (EV_P_ ev_io *w, int revents) { update_now (EV_A); if (revents & EV_READ ) adns_processreadable (ads, w->fd, &tv_now); if (revents & EV_WRITE) adns_processwriteable (ads, w->fd, &tv_now); } // create io watchers for each fd and a timer before blocking static void prepare_cb (EV_P_ ev_prepare *w, int revents) { int i; int timeout = 3600000; ev_timer_stop (EV_A_ &tw); for (i = 0; i < nfd; ++i) ev_io_stop (EV_A_ iow + i); process (); update_now (EV_A); nfd = mfd; while (adns_beforepoll (ads, fds, &nfd, &timeout, &tv_now)) { mfd = nfd; free (iow); iow = malloc (mfd * sizeof (struct pollfd)); free (fds); fds = malloc (mfd * sizeof (ev_io)); } printf ("to %d\n", timeout);//d ev_timer_set (&tw, timeout * 1e-3, 0.); ev_timer_start (EV_A_ &tw); // create one ev_io per pollfd for (i = 0; i < nfd; ++i) { ev_io_init (iow + i, io_cb, fds [i].fd, ((fds [i].events & POLLIN ? EV_READ : 0) | (fds [i].events & POLLOUT ? EV_WRITE : 0))); ev_io_start (EV_A_ iow + i); } } MODULE = EV::ADNS PACKAGE = EV::ADNS PROTOTYPES: ENABLE BOOT: { stash = gv_stashpv ("EV::ADNS", 1); static const struct { const char *name; IV iv; } *civ, const_iv[] = { # define const_iv(name) { # name, (IV) adns_ ## name }, const_iv (if_none) const_iv (if_noenv) const_iv (if_noerrprint) const_iv (if_noserverwarn) const_iv (if_debug) const_iv (if_logpid) const_iv (if_noautosys) const_iv (if_eintr) const_iv (if_nosigpipe) const_iv (if_checkc_entex) const_iv (if_checkc_freq) const_iv (qf_none) const_iv (qf_search) const_iv (qf_usevc) const_iv (qf_owner) const_iv (qf_quoteok_query) const_iv (qf_quoteok_cname) const_iv (qf_quoteok_anshost) const_iv (qf_quotefail_cname) const_iv (qf_cname_loose) const_iv (qf_cname_forbid) const_iv (rrt_typemask) const_iv (_qtf_deref) const_iv (_qtf_mail822) const_iv (r_unknown) const_iv (r_none) const_iv (r_a) const_iv (r_ns_raw) const_iv (r_ns) const_iv (r_cname) const_iv (r_soa_raw) const_iv (r_soa) const_iv (r_ptr_raw) const_iv (r_ptr) const_iv (r_hinfo) const_iv (r_mx_raw) const_iv (r_mx) const_iv (r_txt) const_iv (r_rp_raw) const_iv (r_rp) const_iv (r_srv_raw) const_iv (r_srv) const_iv (r_addr) const_iv (s_ok) const_iv (s_nomemory) const_iv (s_unknownrrtype) const_iv (s_systemfail) const_iv (s_max_localfail) const_iv (s_timeout) const_iv (s_allservfail) const_iv (s_norecurse) const_iv (s_invalidresponse) const_iv (s_unknownformat) const_iv (s_max_remotefail) const_iv (s_rcodeservfail) const_iv (s_rcodeformaterror) const_iv (s_rcodenotimplemented) const_iv (s_rcoderefused) const_iv (s_rcodeunknown) const_iv (s_max_tempfail) const_iv (s_inconsistent) const_iv (s_prohibitedcname) const_iv (s_answerdomaininvalid) const_iv (s_answerdomaintoolong) const_iv (s_invaliddata) const_iv (s_max_misconfig) const_iv (s_querydomainwrong) const_iv (s_querydomaininvalid) const_iv (s_querydomaintoolong) const_iv (s_max_misquery) const_iv (s_nxdomain) const_iv (s_nodata) const_iv (s_max_permfail) }; for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; ) newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv)); I_EV_API ("EV::ADNS"); ev_prepare_init (&prepare_ev, prepare_cb); ev_prepare_start (EV_DEFAULT_ &prepare_ev); ev_unref (); ev_init (&tw, timer_cb); adns_init (&ads, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn | adns_if_noautosys, 0); } void submit (char *owner, int type, int flags, SV *cb) PPCODE: { SV *csv = NEWSV (0, sizeof (struct ctx)); struct ctx *c = (struct ctx *)SvPVX (csv); int r = adns_submit (ads, owner, type, flags, (void *)c, &c->query); if (r) { SvREFCNT_dec (csv); XSRETURN_EMPTY; } else { ev_ref (); SvPOK_only (csv); SvCUR_set (csv, sizeof (struct ctx)); c->self = csv; c->cb = newSVsv (cb); if (GIMME_V != G_VOID) { csv = sv_2mortal (newRV_inc (csv)); sv_bless (csv, stash); XPUSHs (csv); } } } void DESTROY (SV *req) CODE: { struct ctx *c; if (!(SvROK (req) && SvOBJECT (SvRV (req)) && (SvSTASH (SvRV (req)) == stash))) croak ("object is not of type EV::ADNS"); c = (struct ctx *)SvPVX (SvRV (req)); if (c->cb) { ev_unref (); adns_cancel (c->query); SvREFCNT_dec (c->cb); } }