ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/EV/EV.xs
Revision: 1.2
Committed: Fri Oct 26 16:51:27 2007 UTC (16 years, 6 months ago) by root
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
looks better

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