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