ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV/EV.xs
Revision: 1.4
Committed: Fri Oct 26 18:21:32 2007 UTC (16 years, 6 months ago) by root
Branch: MAIN
Changes since 1.3: +10 -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     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     if (now > to && ev->interval)
122     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     if (!(ev->ev.ev_events & EV_PERSIST))
175     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     /*TODO: if err, call some logging function */
184    
185     if (ev->interval && !ev->active)
186     e_start (ev);
187    
188     FREETMPS;
189     LEAVE;
190     }
191    
192     /////////////////////////////////////////////////////////////////////////////
193     // DNS
194    
195     static void
196     dns_cb (int result, char type, int count, int ttl, void *addresses, void *arg)
197     {
198     dSP;
199     SV *cb = (SV *)arg;
200    
201     ENTER;
202     SAVETMPS;
203     PUSHMARK (SP);
204     EXTEND (SP, count + 3);
205     PUSHs (sv_2mortal (newSViv (result)));
206    
207     if (result == DNS_ERR_NONE && ttl >= 0)
208     {
209     int i;
210    
211     PUSHs (sv_2mortal (newSViv (type)));
212     PUSHs (sv_2mortal (newSViv (ttl)));
213    
214     for (i = 0; i < count; ++i)
215     switch (type)
216     {
217     case DNS_IPv6_AAAA:
218     PUSHs (sv_2mortal (newSVpvn (i * 16 + (char *)addresses, 16)));
219     break;
220     case DNS_IPv4_A:
221     PUSHs (sv_2mortal (newSVpvn (i * 4 + (char *)addresses, 4)));
222     break;
223     case DNS_PTR:
224     PUSHs (sv_2mortal (newSVpv (*(char **)addresses, 0)));
225     break;
226     }
227     }
228    
229     PUTBACK;
230     call_sv (sv_2mortal (cb), G_DISCARD | G_VOID | G_EVAL);
231    
232     FREETMPS;
233     LEAVE;
234     }
235    
236     /////////////////////////////////////////////////////////////////////////////
237     // XS interface functions
238    
239     MODULE = EV PACKAGE = EV PREFIX = event_
240    
241     BOOT:
242     {
243     HV *stash = gv_stashpv ("EV", 1);
244    
245     static const struct {
246     const char *name;
247     IV iv;
248     } *civ, const_iv[] = {
249     # define const_iv(pfx, name) { # name, (IV) pfx ## name },
250     const_iv (EV_, NONE)
251     const_iv (EV_, TIMEOUT)
252     const_iv (EV_, READ)
253     const_iv (EV_, WRITE)
254     const_iv (EV_, SIGNAL)
255     const_iv (EV_, PERSIST)
256     const_iv (EV, LOOP_ONCE)
257     const_iv (EV, LOOP_NONBLOCK)
258     const_iv (EV, BUFFER_READ)
259     const_iv (EV, BUFFER_WRITE)
260     const_iv (EV, BUFFER_EOF)
261     const_iv (EV, BUFFER_ERROR)
262     const_iv (EV, BUFFER_TIMEOUT)
263     };
264    
265     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
266     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
267    
268     stash_base = gv_stashpv ("EV::Base" , 1);
269     stash_event = gv_stashpv ("EV::Event", 1);
270     }
271    
272     double now ()
273     CODE:
274     RETVAL = e_now ();
275     OUTPUT:
276     RETVAL
277    
278     const char *version ()
279     ALIAS:
280     method = 1
281     CODE:
282     RETVAL = ix ? event_get_method () : event_get_version ();
283     OUTPUT:
284     RETVAL
285    
286     Base event_init ()
287    
288     int event_priority_init (int npri)
289    
290     int event_dispatch ()
291    
292     int event_loop (int flags = 0)
293    
294 root 1.3 int event_loopexit (double after = 0)
295 root 1.1 CODE:
296     {
297     struct timeval tv;
298     tv_set (&tv, after);
299     event_loopexit (&tv);
300     }
301    
302     Event event (SV *cb)
303     CODE:
304 root 1.3 RETVAL = e_new (NEWSV (0, 0), 0, cb);
305 root 1.1 OUTPUT:
306     RETVAL
307    
308     Event io (SV *fh, short events, SV *cb)
309     ALIAS:
310     io_ns = 1
311     CODE:
312     RETVAL = e_new (fh, events, cb);
313     if (!ix) e_start (RETVAL);
314     OUTPUT:
315     RETVAL
316    
317     Event timer (double after, int repeat, SV *cb)
318     ALIAS:
319     timer_ns = 1
320     CODE:
321 root 1.3 RETVAL = e_new (NEWSV (0, 0), 0, cb);
322 root 1.1 RETVAL->timeout = after;
323     RETVAL->interval = repeat;
324     if (!ix) e_start (RETVAL);
325     OUTPUT:
326     RETVAL
327    
328     Event timer_abs (double at, double interval, SV *cb)
329     ALIAS:
330     timer_abs_ns = 1
331     CODE:
332 root 1.3 RETVAL = e_new (NEWSV (0, 0), 0, cb);
333 root 1.1 RETVAL->timeout = at;
334     RETVAL->interval = interval;
335     RETVAL->abstime = 1;
336     if (!ix) e_start (RETVAL);
337     OUTPUT:
338     RETVAL
339    
340     Event signal (SV *signal, SV *cb)
341     ALIAS:
342     signal_ns = 1
343     CODE:
344     RETVAL = e_new (signal, EV_SIGNAL | EV_PERSIST, cb);
345     if (!ix) e_start (RETVAL);
346     OUTPUT:
347     RETVAL
348    
349     PROTOTYPES: DISABLE
350    
351    
352     MODULE = EV PACKAGE = EV::Base PREFIX = event_base_
353    
354     Base new ()
355     CODE:
356     RETVAL = event_init ();
357     OUTPUT:
358     RETVAL
359    
360     int event_base_dispatch (Base base)
361    
362     int event_base_loop (Base base, int flags = 0)
363    
364     int event_base_loopexit (Base base, double after)
365     CODE:
366     {
367     struct timeval tv;
368     tv.tv_sec = (long)after;
369     tv.tv_usec = (long)(after - tv.tv_sec) * 1e6;
370     event_base_loopexit (base, &tv);
371     }
372    
373     int event_base_priority_init (Base base, int npri)
374    
375     void event_base_set (Base base, Event ev)
376     C_ARGS: base, &ev->ev
377    
378     void DESTROY (Base base)
379     CODE:
380     /*event_base_free (base);*/ /* causes too many problems */
381    
382    
383     MODULE = EV PACKAGE = EV::Event PREFIX = event_
384    
385     int event_priority_set (Event ev, int pri)
386     C_ARGS: &ev->ev, pri
387    
388     int event_add (Event ev, double timeout = TIMEOUT_NONE)
389     CODE:
390     ev->timeout = timeout;
391     ev->abstime = 0;
392     RETVAL = e_start (ev);
393     OUTPUT:
394     RETVAL
395    
396     int event_start (Event ev)
397     CODE:
398     RETVAL = e_start (ev);
399     OUTPUT:
400     RETVAL
401    
402     int event_del (Event ev)
403     ALIAS:
404     stop = 0
405     CODE:
406     RETVAL = e_stop (ev);
407     OUTPUT:
408     RETVAL
409    
410     void DESTROY (Event ev)
411     CODE:
412     e_stop (ev);
413     SvREFCNT_dec (ev->cb);
414     SvREFCNT_dec (ev->fh);
415    
416 root 1.3 SV *cb (Event ev, SV *new_cb = 0)
417 root 1.1 CODE:
418 root 1.3 RETVAL = newSVsv (ev->cb);
419     if (items > 1)
420     sv_setsv (ev->cb, new_cb);
421     OUTPUT:
422     RETVAL
423 root 1.1
424     SV *fh (Event ev, SV *new_fh = 0)
425     ALIAS:
426     signal = 0
427     CODE:
428     RETVAL = newSVsv (ev->fh);
429     if (items > 1)
430     {
431     if (ev->active) event_del (&ev->ev);
432     sv_setsv (ev->fh, new_fh);
433 root 1.2 ev->ev.ev_fd = sv_fileno (ev->fh);
434 root 1.1 if (ev->active) event_add (&ev->ev, e_tv (ev));
435     }
436     OUTPUT:
437     RETVAL
438    
439     short events (Event ev, short new_events = EV_UNDEF)
440     CODE:
441     RETVAL = ev->ev.ev_events;
442     if (items > 1)
443     {
444     if (ev->active) event_del (&ev->ev);
445     ev->ev.ev_events = new_events;
446     if (ev->active) event_add (&ev->ev, e_tv (ev));
447     }
448     OUTPUT:
449     RETVAL
450    
451     double timeout (Event ev, double new_timeout = 0., int repeat = 0)
452     CODE:
453     RETVAL = ev->timeout;
454     if (items > 1)
455     {
456     if (ev->active) event_del (&ev->ev);
457     ev->timeout = new_timeout;
458     ev->interval = repeat;
459     ev->abstime = 0;
460     if (ev->active) event_add (&ev->ev, e_tv (ev));
461     }
462     OUTPUT:
463     RETVAL
464    
465     void timeout_abs (Event ev, double at, double interval = 0.)
466     CODE:
467     if (ev->active) event_del (&ev->ev);
468     ev->timeout = at;
469     ev->interval = interval;
470     ev->abstime = 1;
471     if (ev->active) event_add (&ev->ev, e_tv (ev));
472    
473    
474     MODULE = EV PACKAGE = EV::DNS PREFIX = evdns_
475    
476     BOOT:
477     {
478     HV *stash = gv_stashpv ("EV::DNS", 1);
479    
480     static const struct {
481     const char *name;
482     IV iv;
483     } *civ, const_iv[] = {
484     # define const_iv(pfx, name) { # name, (IV) pfx ## name },
485    
486     const_iv (DNS_, ERR_NONE)
487     const_iv (DNS_, ERR_FORMAT)
488     const_iv (DNS_, ERR_SERVERFAILED)
489     const_iv (DNS_, ERR_NOTEXIST)
490     const_iv (DNS_, ERR_NOTIMPL)
491     const_iv (DNS_, ERR_REFUSED)
492     const_iv (DNS_, ERR_TRUNCATED)
493     const_iv (DNS_, ERR_UNKNOWN)
494     const_iv (DNS_, ERR_TIMEOUT)
495     const_iv (DNS_, ERR_SHUTDOWN)
496     const_iv (DNS_, IPv4_A)
497     const_iv (DNS_, PTR)
498     const_iv (DNS_, IPv6_AAAA)
499     const_iv (DNS_, QUERY_NO_SEARCH)
500     const_iv (DNS_, OPTION_SEARCH)
501     const_iv (DNS_, OPTION_NAMESERVERS)
502     const_iv (DNS_, OPTION_MISC)
503     const_iv (DNS_, OPTIONS_ALL)
504     const_iv (DNS_, NO_SEARCH)
505     };
506    
507     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
508     newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
509     }
510    
511     int evdns_init ()
512    
513     void evdns_shutdown (int fail_requests = 1)
514    
515     const char *evdns_err_to_string (int err)
516    
517     int evdns_nameserver_add (U32 address)
518    
519     int evdns_count_nameservers ()
520    
521     int evdns_clear_nameservers_and_suspend ()
522    
523     int evdns_resume ()
524    
525     int evdns_nameserver_ip_add (char *ip_as_string)
526    
527     int evdns_resolve_ipv4 (const char *name, int flags, SV *cb)
528     C_ARGS: name, flags, dns_cb, (void *)SvREFCNT_inc (cb)
529    
530     int evdns_resolve_ipv6 (const char *name, int flags, SV *cb)
531     C_ARGS: name, flags, dns_cb, (void *)SvREFCNT_inc (cb)
532    
533     int evdns_resolve_reverse (SV *addr, int flags, SV *cb)
534     ALIAS:
535     evdns_resolve_reverse_ipv6 = 1
536     CODE:
537     {
538     STRLEN len;
539     char *data = SvPVbyte (addr, len);
540     if (len != (ix ? 16 : 4))
541     croak ("ipv4/ipv6 address to resolve must be given as 4/16 byte octet string");
542    
543     RETVAL = ix
544     ? evdns_resolve_reverse_ipv6 ((struct in6_addr *)data, flags, dns_cb, (void *)SvREFCNT_inc (cb))
545     : evdns_resolve_reverse ((struct in_addr *)data, flags, dns_cb, (void *)SvREFCNT_inc (cb));
546     }
547     OUTPUT:
548     RETVAL
549    
550     int evdns_set_option (char *option, char *val, int flags)
551    
552     int evdns_resolv_conf_parse (int flags, const char *filename)
553    
554     #ifdef MS_WINDOWS
555    
556     int evdns_config_windows_nameservers ()
557    
558     #endif
559    
560     void evdns_search_clear ()
561    
562     void evdns_search_add (char *domain)
563    
564     void evdns_search_ndots_set (int ndots)
565