em-udns 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/em-udns.c ADDED
@@ -0,0 +1,635 @@
1
+ #include <ruby.h>
2
+ #include <ctype.h>
3
+ #include <netinet/in.h>
4
+ #include "udns.h"
5
+ #include "em-udns.h"
6
+
7
+
8
+ static VALUE mEm;
9
+ static VALUE mEmDeferrable;
10
+ static VALUE mUdns;
11
+
12
+ static VALUE cResolver;
13
+ static VALUE cQuery;
14
+
15
+ static VALUE cRR_MX;
16
+ static VALUE cRR_SRV;
17
+ static VALUE cRR_NAPTR;
18
+
19
+ static VALUE eUdnsError;
20
+ static VALUE eUdnsTempFail;
21
+ static VALUE eUdnsNoMem;
22
+ static VALUE eUdnsBadQuery;
23
+
24
+
25
+ void Resolver_free(struct dns_ctx *dns_context)
26
+ {
27
+ if(dns_context)
28
+ dns_free(dns_context);
29
+ }
30
+
31
+
32
+ VALUE Resolver_alloc(VALUE klass)
33
+ {
34
+ struct dns_ctx *dns_context;
35
+ VALUE alloc_error = Qnil;
36
+ VALUE obj;
37
+
38
+ /* First initialize the library (so the default context). */
39
+ if (dns_init(NULL, 0) < 0)
40
+ alloc_error = rb_str_new2("udns `dns_init' failed");
41
+
42
+ /* Copy the context to a new one. */
43
+ if (!(dns_context = dns_new(NULL)))
44
+ alloc_error = rb_str_new2("udns `dns_new' failed");
45
+
46
+ obj = Data_Wrap_Struct(klass, NULL, Resolver_free, dns_context);
47
+ if (TYPE(alloc_error) == T_STRING)
48
+ rb_ivar_set(obj, rb_intern("@alloc_error"), alloc_error);
49
+
50
+ return obj;
51
+ }
52
+
53
+
54
+ void timer_cb(struct dns_ctx *dns_context, int timeout, void *data)
55
+ {
56
+ VALUE resolver;
57
+ VALUE timer;
58
+
59
+ resolver = (VALUE)data;
60
+ timer = rb_ivar_get(resolver, rb_intern("@timer"));
61
+
62
+ /* Cancel the EM::Timer. */
63
+ if (TYPE(timer) != T_NIL)
64
+ rb_funcall(timer, rb_intern("cancel"), 0);
65
+
66
+ if (timeout >= 0)
67
+ rb_funcall(resolver, rb_intern("set_timer"), 1, INT2FIX(timeout));
68
+ }
69
+
70
+
71
+ VALUE Resolver_dns_open(VALUE self)
72
+ {
73
+ struct dns_ctx *dns_context = NULL;
74
+
75
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
76
+
77
+ dns_set_tmcbck(dns_context, timer_cb, (void*)self);
78
+
79
+ /* Open the new context. */
80
+ if (dns_open(dns_context) < 0)
81
+ rb_raise(eUdnsError, "udns `dns_open' failed");
82
+
83
+ return Qtrue;
84
+ }
85
+
86
+
87
+ VALUE Resolver_fd(VALUE self)
88
+ {
89
+ struct dns_ctx *dns_context = NULL;
90
+
91
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
92
+ return INT2FIX(dns_sock(dns_context));
93
+ }
94
+
95
+
96
+ VALUE Resolver_ioevent(VALUE self)
97
+ {
98
+ struct dns_ctx *dns_context = NULL;
99
+
100
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
101
+ dns_ioevent(dns_context, 0);
102
+ return Qfalse;
103
+ }
104
+
105
+
106
+ VALUE Resolver_timeouts(VALUE self)
107
+ {
108
+ struct dns_ctx *dns_context = NULL;
109
+
110
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
111
+ dns_timeouts(dns_context, -1, 0);
112
+
113
+ return Qnil;
114
+ }
115
+
116
+
117
+ VALUE Resolver_cancel(VALUE self, VALUE query)
118
+ {
119
+ VALUE queries;
120
+ VALUE value;
121
+
122
+ queries = rb_ivar_get(self, rb_intern("@queries"));
123
+ if (TYPE(rb_hash_aref(queries, query)) == T_TRUE) {
124
+ rb_hash_aset(queries, query, Qfalse);
125
+ return Qtrue;
126
+ }
127
+ else
128
+ return Qfalse;
129
+ }
130
+
131
+
132
+ VALUE Resolver_active(VALUE self)
133
+ {
134
+ struct dns_ctx *dns_context = NULL;
135
+
136
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
137
+ return INT2FIX(dns_active(dns_context));
138
+ }
139
+
140
+
141
+ static void* check_query(struct dns_ctx *dns_context, void *rr, void *data)
142
+ {
143
+ VALUE resolver;
144
+ VALUE query;
145
+ VALUE query_value_in_hash;
146
+ VALUE error;
147
+ int status;
148
+
149
+ resolver = ((struct resolver_query*)data)->resolver;
150
+ query = ((struct resolver_query*)data)->query;
151
+ xfree(data);
152
+
153
+ query_value_in_hash = rb_hash_delete(rb_ivar_get(resolver, rb_intern("@queries")), query);
154
+ /* Got response belongs to a query already removed (shouldn't occur). Ignore. */
155
+ if (query_value_in_hash == Qnil) {
156
+ if (rr) free(rr);
157
+ return NULL;
158
+ }
159
+ /* Got response belongs to a cancelled query. Ignore. */
160
+ else if (query_value_in_hash == Qfalse) {
161
+ if (rr) free(rr);
162
+ return NULL;
163
+ }
164
+
165
+ if ((status = dns_status(dns_context)) < 0) {
166
+ if (rr) free(rr);
167
+ switch(status) {
168
+ case DNS_E_TEMPFAIL:
169
+ error = ID2SYM(rb_intern("dns_error_tempfail"));
170
+ break;
171
+ case DNS_E_PROTOCOL:
172
+ error = ID2SYM(rb_intern("dns_error_protocol"));
173
+ break;
174
+ case DNS_E_NXDOMAIN:
175
+ error = ID2SYM(rb_intern("dns_error_nxdomain"));
176
+ break;
177
+ case DNS_E_NODATA:
178
+ error = ID2SYM(rb_intern("dns_error_nodata"));
179
+ break;
180
+ default:
181
+ error = ID2SYM(rb_intern("dns_error_unknown"));
182
+ break;
183
+ }
184
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("failed")), error);
185
+ return NULL;
186
+ }
187
+
188
+ return (void*)query;
189
+ }
190
+
191
+
192
+ static void dns_result_A_cb(struct dns_ctx *dns_context, struct dns_rr_a4 *rr, void *data)
193
+ {
194
+ VALUE query;
195
+ VALUE array;
196
+ int i;
197
+ char ip[INET_ADDRSTRLEN];
198
+
199
+ if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
200
+
201
+ array = rb_ary_new2(rr->dnsa4_nrr);
202
+ for(i = 0; i < rr->dnsa4_nrr; i++)
203
+ rb_ary_push(array, rb_str_new2((char *)dns_ntop(AF_INET, &(rr->dnsa4_addr[i].s_addr), ip, INET_ADDRSTRLEN)));
204
+ free(rr);
205
+
206
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
207
+ }
208
+
209
+
210
+ static void dns_result_AAAA_cb(struct dns_ctx *dns_context, struct dns_rr_a6 *rr, void *data)
211
+ {
212
+ VALUE query;
213
+ VALUE array;
214
+ int i;
215
+ char ip[INET6_ADDRSTRLEN];
216
+
217
+ if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
218
+
219
+ array = rb_ary_new2(rr->dnsa6_nrr);
220
+ for(i = 0; i < rr->dnsa6_nrr; i++)
221
+ rb_ary_push(array, rb_str_new2((char *)dns_ntop(AF_INET6, &(rr->dnsa6_addr[i].s6_addr), ip, INET6_ADDRSTRLEN)));
222
+ free(rr);
223
+
224
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
225
+ }
226
+
227
+
228
+ static void dns_result_PTR_cb(struct dns_ctx *dns_context, struct dns_rr_ptr *rr, void *data)
229
+ {
230
+ VALUE query;
231
+ VALUE array;
232
+ int i;
233
+
234
+ if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
235
+
236
+ array = rb_ary_new2(rr->dnsptr_nrr);
237
+ for(i = 0; i < rr->dnsptr_nrr; i++)
238
+ rb_ary_push(array, rb_str_new2(rr->dnsptr_ptr[i]));
239
+ free(rr);
240
+
241
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
242
+ }
243
+
244
+
245
+ static void dns_result_MX_cb(struct dns_ctx *dns_context, struct dns_rr_mx *rr, void *data)
246
+ {
247
+ VALUE query;
248
+ VALUE array;
249
+ int i;
250
+ VALUE rr_mx;
251
+
252
+ if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
253
+
254
+ array = rb_ary_new2(rr->dnsmx_nrr);
255
+ for(i = 0; i < rr->dnsmx_nrr; i++) {
256
+ rr_mx = rb_obj_alloc(cRR_MX);
257
+ rb_ivar_set(rr_mx, rb_intern("@domain"), rb_str_new2(rr->dnsmx_mx[i].name));
258
+ rb_ivar_set(rr_mx, rb_intern("@priority"), INT2FIX(rr->dnsmx_mx[i].priority));
259
+ rb_ary_push(array, rr_mx);
260
+ }
261
+ free(rr);
262
+
263
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
264
+ }
265
+
266
+
267
+ static void dns_result_TXT_cb(struct dns_ctx *dns_context, struct dns_rr_txt *rr, void *data)
268
+ {
269
+ VALUE query;
270
+ VALUE array;
271
+ int i;
272
+
273
+ if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
274
+
275
+ array = rb_ary_new2(rr->dnstxt_nrr);
276
+ for(i = 0; i < rr->dnstxt_nrr; i++)
277
+ rb_ary_push(array, rb_str_new(rr->dnstxt_txt[i].txt, rr->dnstxt_txt[i].len));
278
+ free(rr);
279
+
280
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
281
+ }
282
+
283
+
284
+ static void dns_result_SRV_cb(struct dns_ctx *dns_context, struct dns_rr_srv *rr, void *data)
285
+ {
286
+ VALUE query;
287
+ VALUE array;
288
+ int i;
289
+ VALUE rr_srv;
290
+
291
+ if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
292
+
293
+ array = rb_ary_new2(rr->dnssrv_nrr);
294
+ for(i = 0; i < rr->dnssrv_nrr; i++) {
295
+ rr_srv = rb_obj_alloc(cRR_SRV);
296
+ rb_ivar_set(rr_srv, rb_intern("@domain"), rb_str_new2(rr->dnssrv_srv[i].name));
297
+ rb_ivar_set(rr_srv, rb_intern("@priority"), INT2FIX(rr->dnssrv_srv[i].priority));
298
+ rb_ivar_set(rr_srv, rb_intern("@weight"), INT2FIX(rr->dnssrv_srv[i].weight));
299
+ rb_ivar_set(rr_srv, rb_intern("@port"), INT2FIX(rr->dnssrv_srv[i].port));
300
+ rb_ary_push(array, rr_srv);
301
+ }
302
+ free(rr);
303
+
304
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
305
+ }
306
+
307
+
308
+ static void dns_result_NAPTR_cb(struct dns_ctx *dns_context, struct dns_rr_naptr *rr, void *data)
309
+ {
310
+ VALUE query;
311
+ VALUE array;
312
+ int i;
313
+ VALUE rr_naptr;
314
+
315
+ if (!(query = (VALUE)check_query(dns_context, rr, data))) return;
316
+
317
+ array = rb_ary_new2(rr->dnsnaptr_nrr);
318
+ for(i = 0; i < rr->dnsnaptr_nrr; i++) {
319
+ rr_naptr = rb_obj_alloc(cRR_NAPTR);
320
+ rb_ivar_set(rr_naptr, rb_intern("@order"), INT2FIX(rr->dnsnaptr_naptr[i].order));
321
+ rb_ivar_set(rr_naptr, rb_intern("@preference"), INT2FIX(rr->dnsnaptr_naptr[i].preference));
322
+ rb_ivar_set(rr_naptr, rb_intern("@flags"), rb_str_new2(rr->dnsnaptr_naptr[i].flags));
323
+ rb_ivar_set(rr_naptr, rb_intern("@service"), rb_str_new2(rr->dnsnaptr_naptr[i].service));
324
+ if (strlen(rr->dnsnaptr_naptr[i].regexp) > 0)
325
+ rb_ivar_set(rr_naptr, rb_intern("@regexp"), rb_str_new2(rr->dnsnaptr_naptr[i].regexp));
326
+ else
327
+ rb_ivar_set(rr_naptr, rb_intern("@regexp"), Qnil);
328
+ if (strlen(rr->dnsnaptr_naptr[i].replacement) > 0)
329
+ rb_ivar_set(rr_naptr, rb_intern("@replacement"), rb_str_new2(rr->dnsnaptr_naptr[i].replacement));
330
+ else
331
+ rb_ivar_set(rr_naptr, rb_intern("@replacement"), Qnil);
332
+ rb_ary_push(array, rr_naptr);
333
+ }
334
+ free(rr);
335
+
336
+ rb_funcall(query, rb_intern("set_deferred_status"), 2, ID2SYM(rb_intern("succeeded")), array);
337
+ }
338
+
339
+
340
+ void raise_dns_error(struct dns_ctx *dns_context)
341
+ {
342
+ switch(dns_status(dns_context)) {
343
+ case DNS_E_TEMPFAIL:
344
+ rb_raise(eUdnsTempFail, "internal error occured");
345
+ break;
346
+ case DNS_E_NOMEM:
347
+ rb_raise(eUdnsNoMem, "no memory available to allocate query structure");
348
+ break;
349
+ case DNS_E_BADQUERY:
350
+ rb_raise(eUdnsBadQuery, "name of dn is invalid");
351
+ break;
352
+ default:
353
+ rb_raise(eUdnsError, "udns `dns_status' returns unexpected error %i", dns_status(dns_context));
354
+ break;
355
+ }
356
+ }
357
+
358
+
359
+ VALUE Resolver_submit_A(VALUE self, VALUE rb_domain)
360
+ {
361
+ struct dns_ctx *dns_context;
362
+ char *domain;
363
+ VALUE query;
364
+ struct resolver_query *data;
365
+
366
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
367
+ domain = StringValueCStr(rb_domain);
368
+ query = rb_obj_alloc(cQuery);
369
+
370
+ data = ALLOC(struct resolver_query);
371
+ data->resolver = self;
372
+ data->query = query;
373
+
374
+ if (!dns_submit_a4(dns_context, domain, 0, dns_result_A_cb, (void *)data)) {
375
+ xfree(data);
376
+ raise_dns_error(dns_context);
377
+ }
378
+
379
+ rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
380
+ return query;
381
+ }
382
+
383
+
384
+ VALUE Resolver_submit_AAAA(VALUE self, VALUE rb_domain)
385
+ {
386
+ struct dns_ctx *dns_context;
387
+ char *domain;
388
+ VALUE query;
389
+ struct resolver_query *data;
390
+
391
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
392
+ domain = StringValueCStr(rb_domain);
393
+ query = rb_obj_alloc(cQuery);
394
+
395
+ data = ALLOC(struct resolver_query);
396
+ data->resolver = self;
397
+ data->query = query;
398
+
399
+ if (!dns_submit_a6(dns_context, domain, 0, dns_result_AAAA_cb, (void *)data)) {
400
+ xfree(data);
401
+ raise_dns_error(dns_context);
402
+ }
403
+
404
+ rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
405
+ return query;
406
+ }
407
+
408
+
409
+ VALUE Resolver_submit_PTR(VALUE self, VALUE rb_ip)
410
+ {
411
+ struct dns_ctx *dns_context;
412
+ char *ip;
413
+ VALUE query;
414
+ struct resolver_query *data;
415
+ struct in_addr addr;
416
+ struct in6_addr addr6;
417
+
418
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
419
+ ip = StringValueCStr(rb_ip);
420
+ query = rb_obj_alloc(cQuery);
421
+
422
+ data = ALLOC(struct resolver_query);
423
+ data->resolver = self;
424
+ data->query = query;
425
+
426
+ switch(dns_pton(AF_INET, ip, &addr)) {
427
+ /* It's valid IPv4. */
428
+ case 1:
429
+ if (!dns_submit_a4ptr(dns_context, &addr, dns_result_PTR_cb, (void *)data)) {
430
+ xfree(data);
431
+ raise_dns_error(dns_context);
432
+ }
433
+ break;
434
+ /* Invalid IPv4, let's try with IPv6. */
435
+ case 0:
436
+ switch(dns_pton(AF_INET6, ip, &addr6)) {
437
+ /* It's valid IPv6. */
438
+ case 1:
439
+ if (!dns_submit_a6ptr(dns_context, &addr6, dns_result_PTR_cb, (void *)data)) {
440
+ xfree(data);
441
+ raise_dns_error(dns_context);
442
+ }
443
+ break;
444
+ /* Also an invalid IPv6 so raise an exception. */
445
+ case 0:
446
+ xfree(data);
447
+ rb_raise(rb_eArgError, "invalid IP '%s' (neither IPv4 or IPv6)", ip);
448
+ break;
449
+ }
450
+ break;
451
+ }
452
+
453
+ rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
454
+ return query;
455
+ }
456
+
457
+
458
+ VALUE Resolver_submit_MX(VALUE self, VALUE rb_domain)
459
+ {
460
+ struct dns_ctx *dns_context;
461
+ char *domain;
462
+ VALUE query;
463
+ struct resolver_query *data;
464
+
465
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
466
+ domain = StringValueCStr(rb_domain);
467
+ query = rb_obj_alloc(cQuery);
468
+
469
+ data = ALLOC(struct resolver_query);
470
+ data->resolver = self;
471
+ data->query = query;
472
+
473
+ if (!dns_submit_mx(dns_context, domain, 0, dns_result_MX_cb, (void *)data)) {
474
+ xfree(data);
475
+ raise_dns_error(dns_context);
476
+ }
477
+
478
+ rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
479
+ return query;
480
+ }
481
+
482
+
483
+ VALUE Resolver_submit_TXT(VALUE self, VALUE rb_domain)
484
+ {
485
+ struct dns_ctx *dns_context;
486
+ char *domain;
487
+ VALUE query;
488
+ struct resolver_query *data;
489
+
490
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
491
+ domain = StringValueCStr(rb_domain);
492
+ query = rb_obj_alloc(cQuery);
493
+
494
+ data = ALLOC(struct resolver_query);
495
+ data->resolver = self;
496
+ data->query = query;
497
+
498
+ if (!dns_submit_txt(dns_context, domain, DNS_C_IN, 0, dns_result_TXT_cb, (void *)data)) {
499
+ xfree(data);
500
+ raise_dns_error(dns_context);
501
+ }
502
+
503
+ rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
504
+ return query;
505
+ }
506
+
507
+
508
+ VALUE Resolver_submit_SRV(int argc, VALUE *argv, VALUE self)
509
+ {
510
+ struct dns_ctx *dns_context;
511
+ char *domain;
512
+ char *service = NULL;
513
+ char *protocol = NULL;
514
+ VALUE query;
515
+ struct resolver_query *data;
516
+
517
+ if (argc == 1 && TYPE(argv[0]) == T_STRING);
518
+ else if (argc == 3 && TYPE(argv[0]) == T_STRING &&
519
+ TYPE(argv[1]) == T_STRING && TYPE(argv[2]) == T_STRING) {
520
+ service = StringValueCStr(argv[1]);
521
+ protocol = StringValueCStr(argv[2]);
522
+ }
523
+ else if (argc == 3 && TYPE(argv[0]) == T_STRING &&
524
+ TYPE(argv[1]) == T_NIL && TYPE(argv[2]) == T_NIL);
525
+ else
526
+ rb_raise(rb_eArgError, "arguments must be `domain' or `domain',`service',`protocol'");
527
+
528
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
529
+ domain = StringValueCStr(argv[0]);
530
+ query = rb_obj_alloc(cQuery);
531
+
532
+ data = ALLOC(struct resolver_query);
533
+ data->resolver = self;
534
+ data->query = query;
535
+
536
+ if (!dns_submit_srv(dns_context, domain, service, protocol, 0, dns_result_SRV_cb, (void *)data)) {
537
+ xfree(data);
538
+ raise_dns_error(dns_context);
539
+ }
540
+
541
+ rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
542
+ return query;
543
+ }
544
+
545
+
546
+ VALUE Resolver_submit_NAPTR(VALUE self, VALUE rb_domain)
547
+ {
548
+ struct dns_ctx *dns_context;
549
+ char *domain;
550
+ VALUE query;
551
+ struct resolver_query *data;
552
+
553
+ Data_Get_Struct(self, struct dns_ctx, dns_context);
554
+ domain = StringValueCStr(rb_domain);
555
+ query = rb_obj_alloc(cQuery);
556
+
557
+ data = ALLOC(struct resolver_query);
558
+ data->resolver = self;
559
+ data->query = query;
560
+
561
+ if (!dns_submit_naptr(dns_context, domain, 0, dns_result_NAPTR_cb, (void *)data)) {
562
+ xfree(data);
563
+ raise_dns_error(dns_context);
564
+ }
565
+
566
+ rb_hash_aset(rb_ivar_get(self, rb_intern("@queries")), query, Qtrue);
567
+ return query;
568
+ }
569
+
570
+
571
+ /* Attribute readers. */
572
+ VALUE RR_MX_domain(VALUE self) { return rv_ivar_get(self, rb_intern("@domain")); }
573
+ VALUE RR_MX_priority(VALUE self) { return rv_ivar_get(self, rb_intern("@priority")); }
574
+
575
+ VALUE RR_SRV_priority(VALUE self) { return rv_ivar_get(self, rb_intern("@priority")); }
576
+ VALUE RR_SRV_weight(VALUE self) { return rv_ivar_get(self, rb_intern("@weight")); }
577
+ VALUE RR_SRV_port(VALUE self) { return rv_ivar_get(self, rb_intern("@port")); }
578
+ VALUE RR_SRV_domain(VALUE self) { return rv_ivar_get(self, rb_intern("@domain")); }
579
+
580
+ VALUE RR_NAPTR_order(VALUE self) { return rv_ivar_get(self, rb_intern("@order")); }
581
+ VALUE RR_NAPTR_preference(VALUE self) { return rv_ivar_get(self, rb_intern("@preference")); }
582
+ VALUE RR_NAPTR_flags(VALUE self) { return rv_ivar_get(self, rb_intern("@flags")); }
583
+ VALUE RR_NAPTR_service(VALUE self) { return rv_ivar_get(self, rb_intern("@service")); }
584
+ VALUE RR_NAPTR_regexp(VALUE self) { return rv_ivar_get(self, rb_intern("@regexp")); }
585
+ VALUE RR_NAPTR_replacement(VALUE self) { return rv_ivar_get(self, rb_intern("@replacement")); }
586
+
587
+
588
+ void Init_em_udns_ext()
589
+ {
590
+ mEm = rb_define_module("EventMachine");
591
+ mEmDeferrable = rb_define_module_under(mEm, "Deferrable");
592
+ mUdns = rb_define_module_under(mEm, "Udns");
593
+
594
+ eUdnsError = rb_define_class_under(mUdns, "UdnsError", rb_eStandardError);
595
+ eUdnsTempFail = rb_define_class_under(mUdns, "UdnsTempFail", eUdnsError);
596
+ eUdnsNoMem = rb_define_class_under(mUdns, "UdnsNoMem", eUdnsError);
597
+ eUdnsBadQuery = rb_define_class_under(mUdns, "UdnsBadQuery", eUdnsError);
598
+
599
+ cResolver = rb_define_class_under(mUdns, "Resolver", rb_cObject);
600
+ rb_define_alloc_func(cResolver, Resolver_alloc);
601
+ rb_define_private_method(cResolver, "dns_open", Resolver_dns_open, 0);
602
+ rb_define_method(cResolver, "fd", Resolver_fd, 0);
603
+ rb_define_method(cResolver, "ioevent", Resolver_ioevent, 0);
604
+ rb_define_private_method(cResolver, "timeouts", Resolver_timeouts, 0);
605
+ rb_define_method(cResolver, "active", Resolver_active, 0);
606
+ rb_define_method(cResolver, "cancel", Resolver_cancel, 1);
607
+ rb_define_method(cResolver, "submit_A", Resolver_submit_A, 1);
608
+ rb_define_method(cResolver, "submit_AAAA", Resolver_submit_AAAA, 1);
609
+ rb_define_method(cResolver, "submit_PTR", Resolver_submit_PTR, 1);
610
+ rb_define_method(cResolver, "submit_MX", Resolver_submit_MX, 1);
611
+ rb_define_method(cResolver, "submit_TXT", Resolver_submit_TXT, 1);
612
+ rb_define_method(cResolver, "submit_SRV", Resolver_submit_SRV, -1);
613
+ rb_define_method(cResolver, "submit_NAPTR", Resolver_submit_NAPTR, 1);
614
+
615
+ cQuery = rb_define_class_under(mUdns, "Query", rb_cObject);
616
+ rb_include_module(cQuery, mEmDeferrable);
617
+
618
+ cRR_MX = rb_define_class_under(mUdns, "RR_MX", rb_cObject);
619
+ rb_define_method(cRR_MX, "domain", RR_MX_domain, 0);
620
+ rb_define_method(cRR_MX, "priority", RR_MX_priority, 0);
621
+
622
+ cRR_SRV = rb_define_class_under(mUdns, "RR_SRV", rb_cObject);
623
+ rb_define_method(cRR_SRV, "priority", RR_SRV_priority, 0);
624
+ rb_define_method(cRR_SRV, "weight", RR_SRV_weight, 0);
625
+ rb_define_method(cRR_SRV, "port", RR_SRV_port, 0);
626
+ rb_define_method(cRR_SRV, "domain", RR_SRV_domain, 0);
627
+
628
+ cRR_NAPTR = rb_define_class_under(mUdns, "RR_NAPTR", rb_cObject);
629
+ rb_define_method(cRR_NAPTR, "order", RR_NAPTR_order, 0);
630
+ rb_define_method(cRR_NAPTR, "preference", RR_NAPTR_preference, 0);
631
+ rb_define_method(cRR_NAPTR, "flags", RR_NAPTR_flags, 0);
632
+ rb_define_method(cRR_NAPTR, "service", RR_NAPTR_service, 0);
633
+ rb_define_method(cRR_NAPTR, "regexp", RR_NAPTR_regexp, 0);
634
+ rb_define_method(cRR_NAPTR, "replacement", RR_NAPTR_replacement, 0);
635
+ }
data/ext/em-udns.h ADDED
@@ -0,0 +1,11 @@
1
+ #ifndef em_udns_h
2
+ #define em_udns_h
3
+
4
+
5
+ struct resolver_query {
6
+ VALUE resolver;
7
+ VALUE query;
8
+ };
9
+
10
+
11
+ #endif
data/ext/extconf.rb ADDED
@@ -0,0 +1,32 @@
1
+ require "mkmf"
2
+ require "fileutils"
3
+
4
+
5
+ here = File.expand_path(File.dirname(__FILE__))
6
+ udns_tarball = Dir.glob("#{here}/udns-*.tar.gz").first
7
+ udns_path = udns_tarball.gsub(".tar.gz", "")
8
+
9
+ Dir.chdir(here) do
10
+ puts(cmd = "tar xzf #{udns_tarball} 2>&1")
11
+ raise "'#{cmd}' failed" unless system(cmd)
12
+
13
+ Dir.chdir(udns_path) do
14
+ puts(cmd = "./configure 2>&1")
15
+ raise "'#{cmd}' failed" unless system(cmd)
16
+
17
+ puts(cmd = "make sharedlib 2>&1")
18
+ raise "'#{cmd}' failed" unless system(cmd)
19
+
20
+ puts(cmd = "ar r libudns.a *.lo 2>&1")
21
+ raise "'#{cmd}' failed" unless system(cmd)
22
+
23
+ FileUtils.mv "libudns.a", "../"
24
+ FileUtils.mv "udns.h", "../"
25
+ end
26
+
27
+ FileUtils.remove_dir(udns_path, force = true)
28
+ end
29
+
30
+
31
+ have_library("udns") # == -ludns
32
+ create_makefile("em_udns_ext")
Binary file
@@ -0,0 +1,36 @@
1
+ module EventMachine::Udns
2
+
3
+ class Resolver
4
+
5
+ def initialize(nameserver = nil)
6
+ raise UdnsError, @alloc_error if @alloc_error
7
+
8
+ @queries = {}
9
+
10
+ if nameserver
11
+ ENV.delete("NAMESERVERS")
12
+ ENV["NAMESERVERS"] = case nameserver
13
+ # A single nameserver.
14
+ when String
15
+ nameserver
16
+ # Multiple nameservers.
17
+ when Array
18
+ nameserver.join(" ")
19
+ else
20
+ raise Error, "`nameserver' argument must be a String or Array of addresses"
21
+ end
22
+ end
23
+
24
+ dns_open
25
+ end
26
+
27
+ def set_timer(timeout)
28
+ @timer = EM::Timer.new(timeout) do
29
+ timeouts
30
+ end
31
+ end
32
+ private :set_timer
33
+
34
+ end
35
+
36
+ end
data/lib/em-udns.rb ADDED
@@ -0,0 +1,32 @@
1
+ require "eventmachine"
2
+
3
+ require "em_udns_ext"
4
+ require "em-udns/resolver"
5
+
6
+
7
+ module EventMachine::Udns
8
+
9
+ module Watcher
10
+ def initialize(resolver)
11
+ @resolver = resolver
12
+ end
13
+
14
+ def notify_readable
15
+ @resolver.ioevent
16
+ end
17
+ end
18
+
19
+ def self.run(resolver)
20
+ raise Error, "EventMachine is not running" unless EM.reactor_running?
21
+
22
+ raise Error, "`resolver' argument must be a EM::Udns::Resolver instance" unless
23
+ resolver.is_a? EM::Udns::Resolver
24
+
25
+ EM.watch resolver.fd, Watcher, resolver do |dns_client|
26
+ dns_client.notify_readable = true
27
+ end
28
+
29
+ self
30
+ end
31
+
32
+ end
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require "rubygems"
4
+ require "em-udns"
5
+
6
+
7
+ def show_usage
8
+ puts <<-END_USAGE
9
+ USAGE:
10
+
11
+ #{$0} A domain [times]
12
+ #{$0} AAAA domain [times]
13
+ #{$0} PTR ip [times]
14
+ #{$0} MX domain [times]
15
+ #{$0} TXT domain [times]
16
+ #{$0} SRV _service._protocol.domain [times]
17
+ #{$0} SRV domain [service] [protocol] [times]
18
+ #{$0} NAPTR domain [times]
19
+ END_USAGE
20
+ end
21
+
22
+
23
+ if ARGV.size < 2
24
+ show_usage
25
+ exit false
26
+ end
27
+
28
+ type = ARGV[0].upcase
29
+ name = ARGV[1]
30
+ case type
31
+ when "A", "AAAA", "MX", "TXT", "PTR", "NAPTR"
32
+ times = (ARGV[2].to_i > 0) ? ARGV[2].to_i : 1
33
+ when "SRV"
34
+ if ARGV[3]
35
+ service = ARGV[2]
36
+ protocol = ARGV[3]
37
+ times = (ARGV[4].to_i > 0) ? ARGV[4].to_i : 1
38
+ else
39
+ service = nil
40
+ protocol = nil
41
+ times = (ARGV[2].to_i > 0) ? ARGV[2].to_i : 1
42
+ end
43
+ else
44
+ show_usage
45
+ exit false
46
+ end
47
+
48
+
49
+ def print_info(times, time_start)
50
+ puts "\n\nINFO: all the #{times} queries terminated"
51
+ printf "INFO: time elapsed: %.4f seconds (%.4f queries/second)\n", (time_elapsed = Time.now - time_start), (times / time_elapsed)
52
+ end
53
+
54
+
55
+ EM.set_max_timers 100000
56
+ EM.run do
57
+
58
+ resolver = EM::Udns::Resolver.new "127.0.0.1"
59
+ EM::Udns.run resolver
60
+
61
+ second = 0
62
+ EM.add_periodic_timer(1) { puts "[#{second += 1}] - active queries: #{resolver.active}" }
63
+
64
+ time_start = Time.now
65
+ sent = 0
66
+ recv = 0
67
+
68
+ timer = EM::PeriodicTimer.new(0) do
69
+ if sent == times
70
+ timer.cancel
71
+ else
72
+ sent += 1
73
+ end
74
+
75
+ query = case type
76
+ when "A"
77
+ resolver.submit_A name
78
+ when "AAAA"
79
+ resolver.submit_AAAA name
80
+ when "PTR"
81
+ resolver.submit_PTR name
82
+ when "MX"
83
+ resolver.submit_MX name
84
+ when "TXT"
85
+ resolver.submit_TXT name
86
+ when "SRV"
87
+ resolver.submit_SRV name, service, protocol
88
+ when "NAPTR"
89
+ resolver.submit_NAPTR name
90
+ end
91
+
92
+ query.callback do |result|
93
+ recv += 1
94
+ puts "#{Time.now} INFO: callback: result => #{result.inspect} (sent: #{sent} / recv: #{recv})"
95
+ if recv == times
96
+ print_info(times, time_start)
97
+ exit
98
+ end
99
+ end
100
+
101
+ query.errback do |error|
102
+ recv += 1
103
+ puts "#{Time.now} INFO: errback: error => #{error.inspect} (sent: #{sent} / recv: #{recv})"
104
+ if recv == times
105
+ print_info(times, time_start)
106
+ exit
107
+ end
108
+ end
109
+
110
+ # Uncomment to cancel the query (so no callback/errback will be called).
111
+ #resolver.cancel(query)
112
+ end
113
+
114
+ end
115
+
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-udns
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Iñaki Baz Castillo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-02-14 00:00:00.000000000 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: eventmachine
17
+ requirement: &21069240 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *21069240
26
+ description: em-udns is an async DNS resolver for EventMachine based on udns C library.
27
+ Having most of the core written in C, em-udns becomes very fast. It can resolve
28
+ DNS A, AAAA, PTR, MX, TXT, SRV and NAPTR records, and can handle every kind of errors
29
+ (domain/record not found, request timeout, malformed response...).
30
+ email: ibc@aliax.net
31
+ executables: []
32
+ extensions:
33
+ - ext/extconf.rb
34
+ extra_rdoc_files: []
35
+ files:
36
+ - lib/em-udns.rb
37
+ - lib/em-udns/resolver.rb
38
+ - ext/em-udns.c
39
+ - ext/em-udns.h
40
+ - ext/extconf.rb
41
+ - ext/udns-0.1.tar.gz
42
+ - test/test-em-udns.rb
43
+ has_rdoc: true
44
+ homepage: https://github.com/ibc/em-udns
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: 1.8.7
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 1.5.2
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Async DNS resolver for EventMachine based on udns C library
68
+ test_files: []