ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV/EV.xs
Revision: 1.8
Committed: Sat Oct 27 19:11:27 2007 UTC (16 years, 6 months ago) by root
Branch: MAIN
CVS Tags: rel-0_02
Changes since 1.7: +17 -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 timer (double after, int repeat, SV *cb)
333 ALIAS:
334 timer_ns = 1
335 CODE:
336 RETVAL = e_new (NEWSV (0, 0), 0, cb);
337 RETVAL->timeout = after;
338 RETVAL->interval = repeat;
339 if (!ix) e_start (RETVAL);
340 OUTPUT:
341 RETVAL
342
343 Event timer_abs (double at, double interval, SV *cb)
344 ALIAS:
345 timer_abs_ns = 1
346 CODE:
347 RETVAL = e_new (NEWSV (0, 0), 0, cb);
348 RETVAL->timeout = at;
349 RETVAL->interval = interval;
350 RETVAL->abstime = 1;
351 if (!ix) e_start (RETVAL);
352 OUTPUT:
353 RETVAL
354
355 Event signal (SV *signal, SV *cb)
356 ALIAS:
357 signal_ns = 1
358 CODE:
359 RETVAL = e_new (signal, EV_SIGNAL | EV_PERSIST, cb);
360 if (!ix) e_start (RETVAL);
361 OUTPUT:
362 RETVAL
363
364 PROTOTYPES: DISABLE
365
366
367 MODULE = EV PACKAGE = EV::Base PREFIX = event_base_
368
369 Base new ()
370 CODE:
371 RETVAL = event_init ();
372 OUTPUT:
373 RETVAL
374
375 int event_base_dispatch (Base base)
376
377 int event_base_loop (Base base, int flags = 0)
378
379 int event_base_loopexit (Base base, double after)
380 CODE:
381 {
382 struct timeval tv;
383 tv.tv_sec = (long)after;
384 tv.tv_usec = (long)(after - tv.tv_sec) * 1e6;
385 event_base_loopexit (base, &tv);
386 }
387
388 int event_base_priority_init (Base base, int npri)
389
390 void event_base_set (Base base, Event ev)
391 C_ARGS: base, &ev->ev
392
393 void DESTROY (Base base)
394 CODE:
395 /*event_base_free (base);*/ /* causes too many problems */
396
397
398 MODULE = EV PACKAGE = EV::Event PREFIX = event_
399
400 int event_priority_set (Event ev, int pri)
401 C_ARGS: &ev->ev, pri
402
403 int event_add (Event ev, double timeout = TIMEOUT_NONE)
404 CODE:
405 ev->timeout = timeout;
406 ev->abstime = 0;
407 RETVAL = e_start (ev);
408 OUTPUT:
409 RETVAL
410
411 int event_start (Event ev)
412 CODE:
413 RETVAL = e_start (ev);
414 OUTPUT:
415 RETVAL
416
417 int event_del (Event ev)
418 ALIAS:
419 stop = 0
420 CODE:
421 RETVAL = e_stop (ev);
422 OUTPUT:
423 RETVAL
424
425 void DESTROY (Event ev)
426 CODE:
427 e_stop (ev);
428 SvREFCNT_dec (ev->cb);
429 SvREFCNT_dec (ev->fh);
430
431 SV *cb (Event ev, SV *new_cb = 0)
432 CODE:
433 RETVAL = newSVsv (ev->cb);
434 if (items > 1)
435 sv_setsv (ev->cb, new_cb);
436 OUTPUT:
437 RETVAL
438
439 SV *fh (Event ev, SV *new_fh = 0)
440 ALIAS:
441 signal = 0
442 CODE:
443 RETVAL = newSVsv (ev->fh);
444 if (items > 1)
445 {
446 if (ev->active) event_del (&ev->ev);
447 sv_setsv (ev->fh, new_fh);
448 ev->ev.ev_fd = sv_fileno (ev->fh);
449 if (ev->active) event_add (&ev->ev, e_tv (ev));
450 }
451 OUTPUT:
452 RETVAL
453
454 short events (Event ev, short new_events = EV_UNDEF)
455 CODE:
456 RETVAL = ev->ev.ev_events;
457 if (items > 1)
458 {
459 if (ev->active) event_del (&ev->ev);
460 ev->ev.ev_events = new_events;
461 if (ev->active) event_add (&ev->ev, e_tv (ev));
462 }
463 OUTPUT:
464 RETVAL
465
466 double timeout (Event ev, double new_timeout = 0., int repeat = 0)
467 CODE:
468 RETVAL = ev->timeout;
469 if (items > 1)
470 {
471 if (ev->active) event_del (&ev->ev);
472 ev->timeout = new_timeout;
473 ev->interval = repeat;
474 ev->abstime = 0;
475 if (ev->active) event_add (&ev->ev, e_tv (ev));
476 }
477 OUTPUT:
478 RETVAL
479
480 void timeout_abs (Event ev, double at, double interval = 0.)
481 CODE:
482 if (ev->active) event_del (&ev->ev);
483 ev->timeout = at;
484 ev->interval = interval;
485 ev->abstime = 1;
486 if (ev->active) event_add (&ev->ev, e_tv (ev));
487
488
489 MODULE = EV PACKAGE = EV::DNS PREFIX = evdns_
490
491 BOOT:
492 {
493 HV *stash = gv_stashpv ("EV::DNS", 1);
494
495 static const struct {
496 const char *name;
497 IV iv;
498 } *civ, const_iv[] = {
499 # define const_iv(pfx, name) { # name, (IV) pfx ## name },
500 const_iv (DNS_, ERR_NONE)
501 const_iv (DNS_, ERR_FORMAT)
502 const_iv (DNS_, ERR_SERVERFAILED)
503 const_iv (DNS_, ERR_NOTEXIST)
504 const_iv (DNS_, ERR_NOTIMPL)
505 const_iv (DNS_, ERR_REFUSED)
506 const_iv (DNS_, ERR_TRUNCATED)
507 const_iv (DNS_, ERR_UNKNOWN)
508 const_iv (DNS_, ERR_TIMEOUT)
509 const_iv (DNS_, ERR_SHUTDOWN)
510 const_iv (DNS_, IPv4_A)
511 const_iv (DNS_, PTR)
512 const_iv (DNS_, IPv6_AAAA)
513 const_iv (DNS_, QUERY_NO_SEARCH)
514 const_iv (DNS_, OPTION_SEARCH)
515 const_iv (DNS_, OPTION_NAMESERVERS)
516 const_iv (DNS_, OPTION_MISC)
517 const_iv (DNS_, OPTIONS_ALL)
518 const_iv (DNS_, NO_SEARCH)
519 };
520
521 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
522 newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
523 }
524
525 int evdns_init ()
526
527 void evdns_shutdown (int fail_requests = 1)
528
529 const char *evdns_err_to_string (int err)
530
531 int evdns_nameserver_add (U32 address)
532
533 int evdns_count_nameservers ()
534
535 int evdns_clear_nameservers_and_suspend ()
536
537 int evdns_resume ()
538
539 int evdns_nameserver_ip_add (char *ip_as_string)
540
541 int evdns_resolve_ipv4 (const char *name, int flags, SV *cb)
542 C_ARGS: name, flags, dns_cb, (void *)SvREFCNT_inc (cb)
543
544 int evdns_resolve_ipv6 (const char *name, int flags, SV *cb)
545 C_ARGS: name, flags, dns_cb, (void *)SvREFCNT_inc (cb)
546
547 int evdns_resolve_reverse (SV *addr, int flags, SV *cb)
548 ALIAS:
549 evdns_resolve_reverse_ipv6 = 1
550 CODE:
551 {
552 STRLEN len;
553 char *data = SvPVbyte (addr, len);
554 if (len != (ix ? 16 : 4))
555 croak ("ipv4/ipv6 address to be resolved must be given as 4/16 byte octet string");
556
557 RETVAL = ix
558 ? evdns_resolve_reverse_ipv6 ((struct in6_addr *)data, flags, dns_cb, (void *)SvREFCNT_inc (cb))
559 : evdns_resolve_reverse ((struct in_addr *)data, flags, dns_cb, (void *)SvREFCNT_inc (cb));
560 }
561 OUTPUT:
562 RETVAL
563
564 int evdns_set_option (char *option, char *val, int flags)
565
566 int evdns_resolv_conf_parse (int flags, const char *filename)
567
568 #ifdef MS_WINDOWS
569
570 int evdns_config_windows_nameservers ()
571
572 #endif
573
574 void evdns_search_clear ()
575
576 void evdns_search_add (char *domain)
577
578 void evdns_search_ndots_set (int ndots)
579
580
581 MODULE = EV PACKAGE = EV::HTTP PREFIX = evhttp_
582
583 BOOT:
584 {
585 HV *stash = gv_stashpv ("EV::HTTP", 1);
586
587 static const struct {
588 const char *name;
589 IV iv;
590 } *civ, const_iv[] = {
591 # define const_iv(pfx, name) { # name, (IV) pfx ## name },
592 const_iv (HTTP_, OK)
593 const_iv (HTTP_, NOCONTENT)
594 const_iv (HTTP_, MOVEPERM)
595 const_iv (HTTP_, MOVETEMP)
596 const_iv (HTTP_, NOTMODIFIED)
597 const_iv (HTTP_, BADREQUEST)
598 const_iv (HTTP_, NOTFOUND)
599 const_iv (HTTP_, SERVUNAVAIL)
600 const_iv (EVHTTP_, REQ_OWN_CONNECTION)
601 const_iv (EVHTTP_, PROXY_REQUEST)
602 const_iv (EVHTTP_, REQ_GET)
603 const_iv (EVHTTP_, REQ_POST)
604 const_iv (EVHTTP_, REQ_HEAD)
605 const_iv (EVHTTP_, REQUEST)
606 const_iv (EVHTTP_, RESPONSE)
607 };
608
609 for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; )
610 newCONSTSUB (stash, (char *)civ->name, newSViv (civ->iv));
611 }
612
613 MODULE = EV PACKAGE = EV::HTTP::Request PREFIX = evhttp_request_
614
615 #HttpRequest new (SV *klass, SV *cb)
616
617 #void DESTROY (struct evhttp_request *req);
618
619
620
621
622
623
624
625