ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV/EV.xs
Revision: 1.11
Committed: Mon Oct 29 08:48:07 2007 UTC (16 years, 6 months ago) by root
Branch: MAIN
Changes since 1.10: +31 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5     #include <math.h>
6     #include <netinet/in.h>
7    
8     #include <sys/time.h>
9     #include <time.h>
10     #include <event.h>
11     #include <evdns.h>
12 root 1.4
13     /* workaround for evhttp.h requiring obscure bsd headers */
14     #ifndef TAILQ_ENTRY
15     #define TAILQ_ENTRY(type) \
16     struct { \
17     struct type *tqe_next; /* next element */ \
18     struct type **tqe_prev; /* address of previous next element */ \
19     }
20     #endif /* !TAILQ_ENTRY */
21     #include <evhttp.h>
22 root 1.1
23     #define EV_NONE 0
24     #define EV_UNDEF -1
25    
26     #define TIMEOUT_NONE HUGE_VAL
27    
28 root 1.11 #include "EV/EVAPI.h"
29    
30 root 1.1 typedef struct event_base *Base;
31 root 1.10 typedef int Signal;
32 root 1.1
33 root 1.11 static struct EVAPI evapi;
34    
35 root 1.1 static HV *stash_base, *stash_event;
36    
37     static double tv_get (struct timeval *tv)
38     {
39     return tv->tv_sec + tv->tv_usec * 1e-6;
40     }
41    
42     static void tv_set (struct timeval *tv, double val)
43     {
44     tv->tv_sec = (long)val;
45     tv->tv_usec = (long)((val - (double)tv->tv_sec) * 1e6);
46    
47     }
48    
49 root 1.10 static int
50     sv_signum (SV *sig)
51     {
52     int signum;
53    
54     if (SvIV (sig) > 0)
55     return SvIV (sig);
56    
57     for (signum = 1; signum < SIG_SIZE; ++signum)
58     if (strEQ (SvPV_nolen (sig), PL_sig_name [signum]))
59     return signum;
60    
61     return -1;
62     }
63    
64 root 1.11 static void
65     api_once (int fd, short events, double timeout, void (*cb)(int, short, void *), void *arg)
66     {
67     if (timeout)
68     {
69     struct timeval tv;
70     tv_set (&tv, timeout);
71     event_once (fd, events, cb, arg, &tv);
72     }
73     else
74     event_once (fd, events, cb, arg, 0);
75     }
76    
77 root 1.1 /////////////////////////////////////////////////////////////////////////////
78     // Event
79    
80     typedef struct ev {
81     struct event ev;
82     SV *cb, *fh;
83     SV *self; /* contains this struct */
84     double timeout;
85     double interval;
86     unsigned char active;
87     unsigned char abstime;
88     } *Event;
89    
90     static double
91 root 1.11 e_now (void)
92 root 1.1 {
93     struct timeval tv;
94     gettimeofday (&tv, 0);
95    
96     return tv_get (&tv);
97     }
98    
99     static void e_cb (int fd, short events, void *arg);
100    
101     static int sv_fileno (SV *fh)
102     {
103 root 1.3 SvGETMAGIC (fh);
104 root 1.1
105 root 1.3 if (SvROK (fh))
106     fh = SvRV (fh);
107 root 1.1
108 root 1.3 if (SvTYPE (fh) == SVt_PVGV)
109     return PerlIO_fileno (IoIFP (sv_2io (fh)));
110 root 1.1
111 root 1.3 if (SvIOK (fh))
112     return SvIV (fh);
113 root 1.1
114     return -1;
115     }
116    
117     static Event
118     e_new (SV *fh, short events, SV *cb)
119     {
120     int fd = sv_fileno (fh);
121     Event ev;
122     SV *self = NEWSV (0, sizeof (struct ev));
123     SvPOK_only (self);
124     SvCUR_set (self, sizeof (struct ev));
125    
126     ev = (Event)SvPVX (self);
127    
128     ev->fh = newSVsv (fh);
129     ev->cb = newSVsv (cb);
130     ev->self = self;
131     ev->timeout = TIMEOUT_NONE;
132     ev->interval = 0.;
133     ev->abstime = 0;
134     ev->active = 0;
135    
136     event_set (&ev->ev, fd, events, e_cb, (void *)ev);
137    
138     return ev;
139     }
140    
141     static struct timeval *
142     e_tv (Event ev)
143     {
144     static struct timeval tv;
145     double to = ev->timeout;
146    
147     if (to == TIMEOUT_NONE)
148     return 0;
149    
150     if (ev->abstime)
151     {
152     double now = e_now ();
153    
154 root 1.6 if (ev->interval)
155 root 1.1 ev->timeout = (to += ceil ((now - to) / ev->interval) * ev->interval);
156    
157     to -= now;
158     }
159     else if (to < 0.)
160     to = 0.;
161    
162     tv_set (&tv, to);
163    
164     return &tv;
165     }
166    
167     static SV *e_self (Event ev)
168     {
169     SV *rv;
170    
171     if (SvOBJECT (ev->self))
172     rv = newRV_inc (ev->self);
173     else
174     {
175     rv = newRV_noinc (ev->self);
176     sv_bless (rv, stash_event);
177     SvREADONLY_on (ev->self);
178     }
179    
180     return rv;
181     }
182    
183     static int
184     e_start (Event ev)
185     {
186     if (ev->active) event_del (&ev->ev);
187     ev->active = 1;
188     return event_add (&ev->ev, e_tv (ev));
189     }
190    
191     static int e_stop (Event ev)
192     {
193     return ev->active
194     ? (ev->active = 0), event_del (&ev->ev)
195     : 0;
196     }
197    
198     static void
199     e_cb (int fd, short events, void *arg)
200     {
201     struct ev *ev = (struct ev*)arg;
202     dSP;
203    
204     ENTER;
205     SAVETMPS;
206    
207 root 1.7 if (!(ev->ev.ev_events & EV_PERSIST) || (events & EV_TIMEOUT))
208 root 1.1 ev->active = 0;
209    
210     PUSHMARK (SP);
211     EXTEND (SP, 2);
212     PUSHs (sv_2mortal (e_self (ev)));
213     PUSHs (sv_2mortal (newSViv (events)));
214     PUTBACK;
215     call_sv (ev->cb, G_DISCARD | G_VOID | G_EVAL);
216    
217     if (ev->interval && !ev->active)
218     e_start (ev);
219    
220     FREETMPS;
221 root 1.8
222     if (SvTRUE (ERRSV))
223     {
224     PUSHMARK (SP);
225     PUTBACK;
226     call_sv (get_sv ("EV::DIED", 1), G_DISCARD | G_VOID | G_EVAL | G_KEEPERR);
227     }
228    
229 root 1.1 LEAVE;
230     }
231    
232     /////////////////////////////////////////////////////////////////////////////
233     // DNS
234    
235     static void
236     dns_cb (int result, char type, int count, int ttl, void *addresses, void *arg)
237     {
238     dSP;
239     SV *cb = (SV *)arg;
240    
241     ENTER;
242     SAVETMPS;
243     PUSHMARK (SP);
244     EXTEND (SP, count + 3);
245     PUSHs (sv_2mortal (newSViv (result)));
246    
247     if (result == DNS_ERR_NONE && ttl >= 0)
248     {
249     int i;
250    
251     PUSHs (sv_2mortal (newSViv (type)));
252     PUSHs (sv_2mortal (newSViv (ttl)));
253    
254     for (i = 0; i < count; ++i)
255     switch (type)
256     {
257     case DNS_IPv6_AAAA:
258     PUSHs (sv_2mortal (newSVpvn (i * 16 + (char *)addresses, 16)));
259     break;
260     case DNS_IPv4_A:
261     PUSHs (sv_2mortal (newSVpvn (i * 4 + (char *)addresses, 4)));
262     break;
263     case DNS_PTR:
264     PUSHs (sv_2mortal (newSVpv (*(char **)addresses, 0)));
265     break;
266     }
267     }
268    
269     PUTBACK;
270     call_sv (sv_2mortal (cb), G_DISCARD | G_VOID | G_EVAL);
271    
272     FREETMPS;
273 root 1.8
274     if (SvTRUE (ERRSV))
275     {
276     PUSHMARK (SP);
277     PUTBACK;
278     call_sv (get_sv ("EV::DIED", 1), G_DISCARD | G_VOID | G_EVAL | G_KEEPERR);
279     }
280    
281 root 1.1 LEAVE;
282     }
283    
284     /////////////////////////////////////////////////////////////////////////////
285     // XS interface functions
286    
287     MODULE = EV PACKAGE = EV PREFIX = event_
288    
289     BOOT:
290     {
291 root 1.10 int i;
292 root 1.1 HV *stash = gv_stashpv ("EV", 1);
293    
294     static const struct {
295     const char *name;
296     IV iv;
297     } *civ, const_iv[] = {
298     # define const_iv(pfx, name) { # name, (IV) pfx ## name },
299     const_iv (EV_, NONE)
300     const_iv (EV_, TIMEOUT)
301     const_iv (EV_, READ)
302     const_iv (EV_, WRITE)
303     const_iv (EV_, SIGNAL)
304     const_iv (EV_, PERSIST)
305     const_iv (EV, LOOP_ONCE)
306     const_iv (EV, LOOP_NONBLOCK)
307     const_iv (EV, BUFFER_READ)
308     const_iv (EV, BUFFER_WRITE)
309     const_iv (EV, BUFFER_EOF)
310     const_iv (EV, BUFFER_ERROR)
311     const_iv (EV, BUFFER_TIMEOUT)
312     };
313    
314     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
315     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
316    
317     stash_base = gv_stashpv ("EV::Base" , 1);
318     stash_event = gv_stashpv ("EV::Event", 1);
319 root 1.11
320     {
321     SV *sv = perl_get_sv ("EV::API", TRUE);
322     perl_get_sv ("EV::API", TRUE); /* silence 5.10 warning */
323    
324     evapi.ver = EV_API_VERSION;
325     evapi.rev = EV_API_REVISION;
326     evapi.now = e_now;
327     evapi.once = api_once;
328    
329     sv_setiv (sv, (IV)&evapi);
330     SvREADONLY_on (sv);
331     }
332 root 1.1 }
333    
334     double now ()
335     CODE:
336     RETVAL = e_now ();
337     OUTPUT:
338     RETVAL
339    
340     const char *version ()
341     ALIAS:
342     method = 1
343     CODE:
344     RETVAL = ix ? event_get_method () : event_get_version ();
345     OUTPUT:
346     RETVAL
347    
348     Base event_init ()
349    
350     int event_priority_init (int npri)
351    
352     int event_dispatch ()
353    
354     int event_loop (int flags = 0)
355    
356 root 1.3 int event_loopexit (double after = 0)
357 root 1.1 CODE:
358     {
359     struct timeval tv;
360     tv_set (&tv, after);
361     event_loopexit (&tv);
362     }
363    
364     Event event (SV *cb)
365     CODE:
366 root 1.3 RETVAL = e_new (NEWSV (0, 0), 0, cb);
367 root 1.1 OUTPUT:
368     RETVAL
369    
370     Event io (SV *fh, short events, SV *cb)
371     ALIAS:
372     io_ns = 1
373     CODE:
374     RETVAL = e_new (fh, events, cb);
375     if (!ix) e_start (RETVAL);
376     OUTPUT:
377     RETVAL
378    
379 root 1.9 Event timed_io (SV *fh, short events, double timeout, SV *cb)
380     ALIAS:
381     timed_io_ns = 1
382     CODE:
383     {
384     events = timeout ? events & ~EV_PERSIST : events | EV_PERSIST;
385    
386     RETVAL = e_new (fh, events, cb);
387    
388     if (timeout)
389     {
390     RETVAL->timeout = timeout;
391     RETVAL->interval = 1;
392     }
393    
394     if (!ix) e_start (RETVAL);
395     }
396     OUTPUT:
397     RETVAL
398    
399 root 1.1 Event timer (double after, int repeat, SV *cb)
400     ALIAS:
401     timer_ns = 1
402     CODE:
403 root 1.3 RETVAL = e_new (NEWSV (0, 0), 0, cb);
404 root 1.1 RETVAL->timeout = after;
405     RETVAL->interval = repeat;
406     if (!ix) e_start (RETVAL);
407     OUTPUT:
408     RETVAL
409    
410     Event timer_abs (double at, double interval, SV *cb)
411     ALIAS:
412     timer_abs_ns = 1
413     CODE:
414 root 1.3 RETVAL = e_new (NEWSV (0, 0), 0, cb);
415 root 1.1 RETVAL->timeout = at;
416     RETVAL->interval = interval;
417     RETVAL->abstime = 1;
418     if (!ix) e_start (RETVAL);
419     OUTPUT:
420     RETVAL
421    
422 root 1.10 Event signal (Signal signum, SV *cb)
423 root 1.1 ALIAS:
424     signal_ns = 1
425     CODE:
426 root 1.10 RETVAL = e_new (ST (0), EV_SIGNAL | EV_PERSIST, cb);
427     RETVAL->ev.ev_fd = signum;
428 root 1.1 if (!ix) e_start (RETVAL);
429     OUTPUT:
430     RETVAL
431    
432     PROTOTYPES: DISABLE
433    
434    
435     MODULE = EV PACKAGE = EV::Base PREFIX = event_base_
436    
437     Base new ()
438     CODE:
439     RETVAL = event_init ();
440     OUTPUT:
441     RETVAL
442    
443     int event_base_dispatch (Base base)
444    
445     int event_base_loop (Base base, int flags = 0)
446    
447     int event_base_loopexit (Base base, double after)
448     CODE:
449     {
450     struct timeval tv;
451     tv.tv_sec = (long)after;
452     tv.tv_usec = (long)(after - tv.tv_sec) * 1e6;
453     event_base_loopexit (base, &tv);
454     }
455    
456     int event_base_priority_init (Base base, int npri)
457    
458     void event_base_set (Base base, Event ev)
459     C_ARGS: base, &ev->ev
460    
461     void DESTROY (Base base)
462     CODE:
463     /*event_base_free (base);*/ /* causes too many problems */
464    
465    
466     MODULE = EV PACKAGE = EV::Event PREFIX = event_
467    
468     int event_priority_set (Event ev, int pri)
469     C_ARGS: &ev->ev, pri
470    
471     int event_add (Event ev, double timeout = TIMEOUT_NONE)
472     CODE:
473     ev->timeout = timeout;
474     ev->abstime = 0;
475     RETVAL = e_start (ev);
476     OUTPUT:
477     RETVAL
478    
479     int event_start (Event ev)
480     CODE:
481     RETVAL = e_start (ev);
482     OUTPUT:
483     RETVAL
484    
485     int event_del (Event ev)
486     ALIAS:
487     stop = 0
488     CODE:
489     RETVAL = e_stop (ev);
490     OUTPUT:
491     RETVAL
492    
493     void DESTROY (Event ev)
494     CODE:
495     e_stop (ev);
496     SvREFCNT_dec (ev->cb);
497     SvREFCNT_dec (ev->fh);
498    
499 root 1.3 SV *cb (Event ev, SV *new_cb = 0)
500 root 1.1 CODE:
501 root 1.3 RETVAL = newSVsv (ev->cb);
502     if (items > 1)
503     sv_setsv (ev->cb, new_cb);
504     OUTPUT:
505     RETVAL
506 root 1.1
507     SV *fh (Event ev, SV *new_fh = 0)
508     CODE:
509     RETVAL = newSVsv (ev->fh);
510     if (items > 1)
511     {
512     if (ev->active) event_del (&ev->ev);
513     sv_setsv (ev->fh, new_fh);
514 root 1.9 ev->ev.ev_fd = sv_fileno (ev->fh);
515 root 1.10 ev->ev.ev_events &= ev->ev.ev_events & ~EV_SIGNAL;
516 root 1.1 if (ev->active) event_add (&ev->ev, e_tv (ev));
517     }
518     OUTPUT:
519     RETVAL
520    
521 root 1.10 SV *signal (Event ev, SV *new_signal = 0)
522     CODE:
523     {
524     Signal signum;
525    
526     if (items > 1)
527     signum = sv_signum (new_signal); /* may croak here */
528    
529     RETVAL = newSVsv (ev->fh);
530    
531     if (items > 1)
532     {
533     if (ev->active) event_del (&ev->ev);
534     sv_setsv (ev->fh, new_signal);
535     ev->ev.ev_fd = signum;
536     ev->ev.ev_events |= EV_SIGNAL;
537     if (ev->active) event_add (&ev->ev, e_tv (ev));
538     }
539     }
540     OUTPUT:
541     RETVAL
542    
543 root 1.1 short events (Event ev, short new_events = EV_UNDEF)
544     CODE:
545     RETVAL = ev->ev.ev_events;
546     if (items > 1)
547     {
548     if (ev->active) event_del (&ev->ev);
549     ev->ev.ev_events = new_events;
550     if (ev->active) event_add (&ev->ev, e_tv (ev));
551     }
552     OUTPUT:
553     RETVAL
554    
555     double timeout (Event ev, double new_timeout = 0., int repeat = 0)
556     CODE:
557     RETVAL = ev->timeout;
558     if (items > 1)
559     {
560     if (ev->active) event_del (&ev->ev);
561     ev->timeout = new_timeout;
562     ev->interval = repeat;
563     ev->abstime = 0;
564     if (ev->active) event_add (&ev->ev, e_tv (ev));
565     }
566     OUTPUT:
567     RETVAL
568    
569     void timeout_abs (Event ev, double at, double interval = 0.)
570     CODE:
571     if (ev->active) event_del (&ev->ev);
572     ev->timeout = at;
573     ev->interval = interval;
574     ev->abstime = 1;
575     if (ev->active) event_add (&ev->ev, e_tv (ev));
576    
577    
578     MODULE = EV PACKAGE = EV::DNS PREFIX = evdns_
579    
580     BOOT:
581     {
582     HV *stash = gv_stashpv ("EV::DNS", 1);
583    
584     static const struct {
585     const char *name;
586     IV iv;
587     } *civ, const_iv[] = {
588     # define const_iv(pfx, name) { # name, (IV) pfx ## name },
589     const_iv (DNS_, ERR_NONE)
590     const_iv (DNS_, ERR_FORMAT)
591     const_iv (DNS_, ERR_SERVERFAILED)
592     const_iv (DNS_, ERR_NOTEXIST)
593     const_iv (DNS_, ERR_NOTIMPL)
594     const_iv (DNS_, ERR_REFUSED)
595     const_iv (DNS_, ERR_TRUNCATED)
596     const_iv (DNS_, ERR_UNKNOWN)
597     const_iv (DNS_, ERR_TIMEOUT)
598     const_iv (DNS_, ERR_SHUTDOWN)
599     const_iv (DNS_, IPv4_A)
600     const_iv (DNS_, PTR)
601     const_iv (DNS_, IPv6_AAAA)
602     const_iv (DNS_, QUERY_NO_SEARCH)
603     const_iv (DNS_, OPTION_SEARCH)
604     const_iv (DNS_, OPTION_NAMESERVERS)
605     const_iv (DNS_, OPTION_MISC)
606     const_iv (DNS_, OPTIONS_ALL)
607     const_iv (DNS_, NO_SEARCH)
608     };
609    
610     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
611     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
612     }
613    
614     int evdns_init ()
615    
616     void evdns_shutdown (int fail_requests = 1)
617    
618     const char *evdns_err_to_string (int err)
619    
620     int evdns_nameserver_add (U32 address)
621    
622     int evdns_count_nameservers ()
623    
624     int evdns_clear_nameservers_and_suspend ()
625    
626     int evdns_resume ()
627    
628     int evdns_nameserver_ip_add (char *ip_as_string)
629    
630     int evdns_resolve_ipv4 (const char *name, int flags, SV *cb)
631     C_ARGS: name, flags, dns_cb, (void *)SvREFCNT_inc (cb)
632    
633     int evdns_resolve_ipv6 (const char *name, int flags, SV *cb)
634     C_ARGS: name, flags, dns_cb, (void *)SvREFCNT_inc (cb)
635    
636     int evdns_resolve_reverse (SV *addr, int flags, SV *cb)
637     ALIAS:
638     evdns_resolve_reverse_ipv6 = 1
639     CODE:
640     {
641     STRLEN len;
642     char *data = SvPVbyte (addr, len);
643     if (len != (ix ? 16 : 4))
644 root 1.8 croak ("ipv4/ipv6 address to be resolved must be given as 4/16 byte octet string");
645 root 1.1
646     RETVAL = ix
647     ? evdns_resolve_reverse_ipv6 ((struct in6_addr *)data, flags, dns_cb, (void *)SvREFCNT_inc (cb))
648     : evdns_resolve_reverse ((struct in_addr *)data, flags, dns_cb, (void *)SvREFCNT_inc (cb));
649     }
650     OUTPUT:
651     RETVAL
652    
653     int evdns_set_option (char *option, char *val, int flags)
654    
655     int evdns_resolv_conf_parse (int flags, const char *filename)
656    
657     #ifdef MS_WINDOWS
658    
659     int evdns_config_windows_nameservers ()
660    
661     #endif
662    
663     void evdns_search_clear ()
664    
665     void evdns_search_add (char *domain)
666    
667     void evdns_search_ndots_set (int ndots)
668    
669 root 1.5
670     MODULE = EV PACKAGE = EV::HTTP PREFIX = evhttp_
671    
672     BOOT:
673     {
674     HV *stash = gv_stashpv ("EV::HTTP", 1);
675    
676     static const struct {
677     const char *name;
678     IV iv;
679     } *civ, const_iv[] = {
680     # define const_iv(pfx, name) { # name, (IV) pfx ## name },
681     const_iv (HTTP_, OK)
682     const_iv (HTTP_, NOCONTENT)
683     const_iv (HTTP_, MOVEPERM)
684     const_iv (HTTP_, MOVETEMP)
685     const_iv (HTTP_, NOTMODIFIED)
686     const_iv (HTTP_, BADREQUEST)
687     const_iv (HTTP_, NOTFOUND)
688     const_iv (HTTP_, SERVUNAVAIL)
689     const_iv (EVHTTP_, REQ_OWN_CONNECTION)
690     const_iv (EVHTTP_, PROXY_REQUEST)
691     const_iv (EVHTTP_, REQ_GET)
692     const_iv (EVHTTP_, REQ_POST)
693     const_iv (EVHTTP_, REQ_HEAD)
694     const_iv (EVHTTP_, REQUEST)
695     const_iv (EVHTTP_, RESPONSE)
696     };
697    
698     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
699     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
700     }
701    
702     MODULE = EV PACKAGE = EV::HTTP::Request PREFIX = evhttp_request_
703    
704     #HttpRequest new (SV *klass, SV *cb)
705    
706     #void DESTROY (struct evhttp_request *req);
707    
708    
709    
710    
711    
712    
713    
714