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

# 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 (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 int event_loopexit (double after = 0)
295 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 RETVAL = e_new (NEWSV (0, 0), 0, cb);
305 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 RETVAL = e_new (NEWSV (0, 0), 0, cb);
322 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 RETVAL = e_new (NEWSV (0, 0), 0, cb);
333 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 SV *cb (Event ev, SV *new_cb = 0)
417 CODE:
418 RETVAL = newSVsv (ev->cb);
419 if (items > 1)
420 sv_setsv (ev->cb, new_cb);
421 OUTPUT:
422 RETVAL
423
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 ev->ev.ev_fd = sv_fileno (ev->fh);
434 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