em-udns 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: []