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

# Content
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
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
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 SvGETMAGIC (fh);
71
72 if (SvROK (fh))
73 fh = SvRV (fh);
74
75 if (SvTYPE (fh) == SVt_PVGV)
76 return PerlIO_fileno (IoIFP (sv_2io (fh)));
77
78 if (SvIOK (fh))
79 return SvIV (fh);
80
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 (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) || (events & EV_TIMEOUT))
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
184 if (ev->interval && !ev->active)
185 e_start (ev);
186
187 FREETMPS;
188
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 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
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 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 int event_loopexit (double after = 0)
310 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 RETVAL = e_new (NEWSV (0, 0), 0, cb);
320 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 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 Event timer (double after, int repeat, SV *cb)
353 ALIAS:
354 timer_ns = 1
355 CODE:
356 RETVAL = e_new (NEWSV (0, 0), 0, cb);
357 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 RETVAL = e_new (NEWSV (0, 0), 0, cb);
368 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 SV *cb (Event ev, SV *new_cb = 0)
452 CODE:
453 RETVAL = newSVsv (ev->cb);
454 if (items > 1)
455 sv_setsv (ev->cb, new_cb);
456 OUTPUT:
457 RETVAL
458
459 SV *fh (Event ev, SV *new_fh = 0)
460 ALIAS:
461 signal = 1
462 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 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 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 croak ("ipv4/ipv6 address to be resolved must be given as 4/16 byte octet string");
577
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
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