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