ruby-cares 0.1.0
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/examples/example.rb +32 -0
- data/ext/cares.c +653 -0
- data/ext/extconf.rb +5 -0
- metadata +48 -0
data/examples/example.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'cares'
|
|
3
|
+
|
|
4
|
+
domain = 'www.rubyforge.org'
|
|
5
|
+
addr = '205.234.109.18'
|
|
6
|
+
port = 25
|
|
7
|
+
|
|
8
|
+
cares = Cares.new
|
|
9
|
+
|
|
10
|
+
cares.gethostbyname(domain, Socket::AF_INET) do |name, aliases, family, *addrs|
|
|
11
|
+
puts "[-] Cares#gethostbyname:"
|
|
12
|
+
puts " #{domain}:"
|
|
13
|
+
puts " canonical name: #{name}"
|
|
14
|
+
puts " aliases: #{aliases.join(', ')}"
|
|
15
|
+
puts " addresses: #{addrs.join(', ')}"
|
|
16
|
+
puts
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
cares.gethostbyaddr(addr, Socket::AF_INET) do |name, *rest|
|
|
20
|
+
puts "[-] Cares#gethostbyaddr:"
|
|
21
|
+
puts " #{addr}:"
|
|
22
|
+
puts " name: #{name}"
|
|
23
|
+
puts
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
cares.getnameinfo(:addr => addr, :port => port) do |name, service|
|
|
27
|
+
puts "[-] Cares#getnameinfo:"
|
|
28
|
+
puts " IP #{addr} is #{name}"
|
|
29
|
+
puts " Port #{port} is #{service}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
cares.select_loop
|
data/ext/cares.c
ADDED
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
/*
|
|
2
|
+
*--
|
|
3
|
+
* Copyright (c) 2006 Andre Nathan <andre@digirati.com.br>
|
|
4
|
+
*
|
|
5
|
+
* Permission to use, copy, modify, and distribute this software for any
|
|
6
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
* copyright notice and this permission notice appear in all copies.
|
|
8
|
+
*
|
|
9
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
*
|
|
17
|
+
* $Id$
|
|
18
|
+
*++
|
|
19
|
+
*/
|
|
20
|
+
/*
|
|
21
|
+
* Document-class: Cares
|
|
22
|
+
*
|
|
23
|
+
* == Overview
|
|
24
|
+
*
|
|
25
|
+
* Ruby/Cares is a C extension to the
|
|
26
|
+
* c-ares[http://daniel.haxx.se/projects/c-ares/] library. It performs DNS
|
|
27
|
+
* requests and name resolving asynchronously.
|
|
28
|
+
*
|
|
29
|
+
* = Example
|
|
30
|
+
*
|
|
31
|
+
* Below follows a simple example. See Cares' methods documentations for
|
|
32
|
+
* details valid parameters.
|
|
33
|
+
*
|
|
34
|
+
* require 'cares'
|
|
35
|
+
* require 'socket'
|
|
36
|
+
*
|
|
37
|
+
* # Create new Cares instance
|
|
38
|
+
* cares = Cares.new(:timeout => 3)
|
|
39
|
+
*
|
|
40
|
+
* #
|
|
41
|
+
* # Set up three DNS requests.
|
|
42
|
+
* #
|
|
43
|
+
*
|
|
44
|
+
* cares.gethostbyname('www.rubyforge.org', Socket::AF_INET) do |name, aliases, family, *addrs|
|
|
45
|
+
* puts "[-] Cares#gethostbyname:"
|
|
46
|
+
* puts " #{domain}:"
|
|
47
|
+
* puts " canonical name: #{name}"
|
|
48
|
+
* puts " aliases: #{aliases.join(', ')}"
|
|
49
|
+
* puts " addresses: #{addrs.join(', ')}"
|
|
50
|
+
* puts
|
|
51
|
+
* end
|
|
52
|
+
*
|
|
53
|
+
* cares.gethostbyaddr('205.234.109.18', Socket::AF_INET) do |name, *rest|
|
|
54
|
+
* puts "[-] Cares#gethostbyaddr:"
|
|
55
|
+
* puts " #{addr}:"
|
|
56
|
+
* puts " name: #{name}"
|
|
57
|
+
* puts
|
|
58
|
+
* end
|
|
59
|
+
*
|
|
60
|
+
* cares.getnameinfo(:addr => '205.234.109.18') do |name, service|
|
|
61
|
+
* puts "[-] Cares#getnameinfo:"
|
|
62
|
+
* puts " #{addr}:"
|
|
63
|
+
* puts " name: #{name}"
|
|
64
|
+
* puts
|
|
65
|
+
* end
|
|
66
|
+
*
|
|
67
|
+
* # Wait for responses and yield the blocks passed to each of the
|
|
68
|
+
* # methods calls above.
|
|
69
|
+
* cares.select_loop
|
|
70
|
+
*/
|
|
71
|
+
#include <ruby.h>
|
|
72
|
+
#include <ares.h>
|
|
73
|
+
|
|
74
|
+
#include <sys/types.h>
|
|
75
|
+
#include <sys/socket.h>
|
|
76
|
+
|
|
77
|
+
#include <arpa/inet.h>
|
|
78
|
+
#include <netdb.h>
|
|
79
|
+
|
|
80
|
+
#define BUFLEN 46
|
|
81
|
+
|
|
82
|
+
static VALUE cInit;
|
|
83
|
+
static VALUE cNameInfo;
|
|
84
|
+
static VALUE cNotImpError;
|
|
85
|
+
static VALUE cBadNameError;
|
|
86
|
+
static VALUE cNotFoundError;
|
|
87
|
+
static VALUE cNoMemError;
|
|
88
|
+
static VALUE cDestrError;
|
|
89
|
+
static VALUE cFlagsError;
|
|
90
|
+
|
|
91
|
+
static void
|
|
92
|
+
define_cares_exceptions(VALUE cares)
|
|
93
|
+
{
|
|
94
|
+
cNotImpError =
|
|
95
|
+
rb_define_class_under(cares, "NotImplementedError", rb_eException);
|
|
96
|
+
cBadNameError =
|
|
97
|
+
rb_define_class_under(cares, "BadNameError", rb_eException);
|
|
98
|
+
cNotFoundError =
|
|
99
|
+
rb_define_class_under(cares, "AddressNotFoundError", rb_eException);
|
|
100
|
+
cNoMemError =
|
|
101
|
+
rb_define_class_under(cares, "NoMemoryError", rb_eException);
|
|
102
|
+
cDestrError =
|
|
103
|
+
rb_define_class_under(cares, "DestructionError", rb_eException);
|
|
104
|
+
cFlagsError =
|
|
105
|
+
rb_define_class_under(cares, "BadFlagsError", rb_eException);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static void
|
|
109
|
+
define_init_flags(VALUE init)
|
|
110
|
+
{
|
|
111
|
+
rb_define_const(init, "USEVC", INT2NUM(ARES_FLAG_USEVC));
|
|
112
|
+
rb_define_const(init, "PRIMARY", INT2NUM(ARES_FLAG_PRIMARY));
|
|
113
|
+
rb_define_const(init, "IGNTC", INT2NUM(ARES_FLAG_IGNTC));
|
|
114
|
+
rb_define_const(init, "NORECURSE", INT2NUM(ARES_FLAG_NORECURSE));
|
|
115
|
+
rb_define_const(init, "STAYOPEN", INT2NUM(ARES_FLAG_STAYOPEN));
|
|
116
|
+
rb_define_const(init, "NOSEARCH", INT2NUM(ARES_FLAG_NOSEARCH));
|
|
117
|
+
rb_define_const(init, "NOALIASES", INT2NUM(ARES_FLAG_NOALIASES));
|
|
118
|
+
rb_define_const(init, "NOCHECKRESP", INT2NUM(ARES_FLAG_NOCHECKRESP));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static void
|
|
122
|
+
define_nameinfo_flags(VALUE ni)
|
|
123
|
+
{
|
|
124
|
+
rb_define_const(ni, "NOFQDN", INT2NUM(ARES_NI_NOFQDN));
|
|
125
|
+
rb_define_const(ni, "NUMERICHOST", INT2NUM(ARES_NI_NUMERICHOST));
|
|
126
|
+
rb_define_const(ni, "NAMEREQD", INT2NUM(ARES_NI_NAMEREQD));
|
|
127
|
+
rb_define_const(ni, "NUMERICSERV", INT2NUM(ARES_NI_NUMERICSERV));
|
|
128
|
+
rb_define_const(ni, "TCP", INT2NUM(ARES_NI_TCP));
|
|
129
|
+
rb_define_const(ni, "UDP", INT2NUM(ARES_NI_UDP));
|
|
130
|
+
rb_define_const(ni, "SCTP", INT2NUM(ARES_NI_SCTP));
|
|
131
|
+
rb_define_const(ni, "DCCP", INT2NUM(ARES_NI_DCCP));
|
|
132
|
+
rb_define_const(ni, "NUMERICSCOPE", INT2NUM(ARES_NI_NUMERICSCOPE));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static void
|
|
136
|
+
raise_error(int error)
|
|
137
|
+
{
|
|
138
|
+
switch (error) {
|
|
139
|
+
case ARES_ENOTIMP:
|
|
140
|
+
rb_raise(cNotImpError, "%s", ares_strerror(error));
|
|
141
|
+
break;
|
|
142
|
+
case ARES_ENOTFOUND:
|
|
143
|
+
rb_raise(cNotFoundError, "%s", ares_strerror(error));
|
|
144
|
+
break;
|
|
145
|
+
case ARES_ENOMEM:
|
|
146
|
+
rb_raise(cNoMemError, "%s", ares_strerror(error));
|
|
147
|
+
break;
|
|
148
|
+
case ARES_EDESTRUCTION:
|
|
149
|
+
rb_raise(cDestrError, "%s", ares_strerror(error));
|
|
150
|
+
break;
|
|
151
|
+
case ARES_EBADFLAGS:
|
|
152
|
+
rb_raise(cFlagsError, "%s", ares_strerror(error));
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static VALUE
|
|
158
|
+
rb_cares_destroy(void *chp)
|
|
159
|
+
{
|
|
160
|
+
ares_destroy(*(ares_channel *)chp);
|
|
161
|
+
return(Qnil);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static VALUE
|
|
165
|
+
rb_cares_alloc(VALUE klass)
|
|
166
|
+
{
|
|
167
|
+
ares_channel *chp;
|
|
168
|
+
return(Data_Make_Struct(klass, ares_channel, 0, rb_cares_destroy, chp));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static void
|
|
172
|
+
init_callback(void *arg, int s, int read, int write)
|
|
173
|
+
{
|
|
174
|
+
VALUE socket, rb_cSock;
|
|
175
|
+
VALUE block = (VALUE)arg;
|
|
176
|
+
|
|
177
|
+
rb_cSock = rb_const_get(rb_cObject, rb_intern("Socket"));
|
|
178
|
+
socket = rb_funcall(rb_cSock, rb_intern("for_fd"), 1, INT2NUM(s));
|
|
179
|
+
|
|
180
|
+
rb_funcall(block, rb_intern("call"), 3, socket,
|
|
181
|
+
read ? Qtrue : Qfalse, write ? Qtrue : Qfalse);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static int
|
|
185
|
+
set_init_opts(VALUE opts, struct ares_options *aop)
|
|
186
|
+
{
|
|
187
|
+
int optmask = 0;
|
|
188
|
+
VALUE vflags, vtimeout, vtries, vndots, vudp_port, vtcp_port;
|
|
189
|
+
VALUE vservers, vdomains, vlookups;
|
|
190
|
+
|
|
191
|
+
if (!NIL_P(opts)) {
|
|
192
|
+
vflags = rb_hash_aref(opts, ID2SYM(rb_intern("flags")));
|
|
193
|
+
if (!NIL_P(vflags)) {
|
|
194
|
+
aop->flags = NUM2INT(vflags);
|
|
195
|
+
optmask |= ARES_OPT_FLAGS;
|
|
196
|
+
}
|
|
197
|
+
vtimeout = rb_hash_aref(opts, ID2SYM(rb_intern("timeout")));
|
|
198
|
+
if (!NIL_P(vtimeout)) {
|
|
199
|
+
aop->timeout = NUM2INT(vtimeout);
|
|
200
|
+
optmask |= ARES_OPT_TIMEOUT;
|
|
201
|
+
}
|
|
202
|
+
vtries = rb_hash_aref(opts, ID2SYM(rb_intern("tries")));
|
|
203
|
+
if (!NIL_P(vtries)) {
|
|
204
|
+
aop->timeout = NUM2INT(vtries);
|
|
205
|
+
optmask |= ARES_OPT_TRIES;
|
|
206
|
+
}
|
|
207
|
+
vndots = rb_hash_aref(opts, ID2SYM(rb_intern("ndots")));
|
|
208
|
+
if (!NIL_P(vndots)) {
|
|
209
|
+
aop->timeout = NUM2INT(vtries);
|
|
210
|
+
optmask |= ARES_OPT_NDOTS;
|
|
211
|
+
}
|
|
212
|
+
vudp_port = rb_hash_aref(opts, ID2SYM(rb_intern("udp_port")));
|
|
213
|
+
if (!NIL_P(vudp_port)) {
|
|
214
|
+
aop->udp_port = NUM2UINT(vudp_port);
|
|
215
|
+
optmask |= ARES_OPT_UDP_PORT;
|
|
216
|
+
}
|
|
217
|
+
vtcp_port = rb_hash_aref(opts, ID2SYM(rb_intern("tcp_port")));
|
|
218
|
+
if (!NIL_P(vtcp_port)) {
|
|
219
|
+
aop->tcp_port = NUM2UINT(vtcp_port);
|
|
220
|
+
optmask |= ARES_OPT_TCP_PORT;
|
|
221
|
+
}
|
|
222
|
+
vservers = rb_hash_aref(opts, ID2SYM(rb_intern("servers")));
|
|
223
|
+
if (!NIL_P(vservers)) {
|
|
224
|
+
long i, n;
|
|
225
|
+
struct in_addr in, *servers;
|
|
226
|
+
|
|
227
|
+
n = RARRAY(vservers)->len;
|
|
228
|
+
servers = ALLOCA_N(struct in_addr, n);
|
|
229
|
+
for (i = 0; i < n; i++) {
|
|
230
|
+
char *caddr;
|
|
231
|
+
VALUE vaddr;
|
|
232
|
+
vaddr = rb_ary_entry(vservers, i);
|
|
233
|
+
caddr = StringValuePtr(vaddr);
|
|
234
|
+
if (inet_pton(AF_INET, caddr, &in) != 1)
|
|
235
|
+
rb_sys_fail("initialize");
|
|
236
|
+
MEMCPY(servers+i, &in, struct in_addr, 1);
|
|
237
|
+
}
|
|
238
|
+
aop->servers = servers;
|
|
239
|
+
aop->nservers = n;
|
|
240
|
+
optmask |= ARES_OPT_SERVERS;
|
|
241
|
+
}
|
|
242
|
+
vdomains = rb_hash_aref(opts, ID2SYM(rb_intern("domains")));
|
|
243
|
+
if (!NIL_P(vdomains)) {
|
|
244
|
+
char *domains;
|
|
245
|
+
long i, n;
|
|
246
|
+
|
|
247
|
+
n = RARRAY(vdomains)->len;
|
|
248
|
+
domains = ALLOC_N(char, n);
|
|
249
|
+
for (i = 0; i < n; i++) {
|
|
250
|
+
char *cdomain;
|
|
251
|
+
VALUE vdomain;
|
|
252
|
+
vdomain = rb_ary_entry(vdomains, i);
|
|
253
|
+
cdomain = StringValuePtr(vdomain);
|
|
254
|
+
MEMCPY(domains+i, cdomain, strlen(cdomain), 1);
|
|
255
|
+
}
|
|
256
|
+
aop->domains = &domains;
|
|
257
|
+
aop->ndomains = n;
|
|
258
|
+
optmask |= ARES_OPT_DOMAINS;
|
|
259
|
+
}
|
|
260
|
+
vlookups = rb_hash_aref(opts, ID2SYM(rb_intern("lookups")));
|
|
261
|
+
if (!NIL_P(vlookups)) {
|
|
262
|
+
ID id = rb_to_id(vlookups);
|
|
263
|
+
if (id == rb_intern("dns"))
|
|
264
|
+
aop->lookups = "b";
|
|
265
|
+
else if (id == rb_intern("hosts"))
|
|
266
|
+
aop->lookups = "f";
|
|
267
|
+
else {
|
|
268
|
+
/*
|
|
269
|
+
* XXX Let c-ares handle it (why does rb_raise
|
|
270
|
+
* segfault here?)
|
|
271
|
+
* rb_raise(rb_eArgError, "initialize: "
|
|
272
|
+
* "invalid value for :lookups");
|
|
273
|
+
*/
|
|
274
|
+
aop->lookups = "";
|
|
275
|
+
}
|
|
276
|
+
optmask |= ARES_OPT_LOOKUPS;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (rb_block_given_p()) {
|
|
280
|
+
aop->sock_state_cb = init_callback;
|
|
281
|
+
aop->sock_state_cb_data = (void *)rb_block_proc();
|
|
282
|
+
optmask |= ARES_OPT_SOCK_STATE_CB;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return(optmask);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/*
|
|
289
|
+
* call-seq:
|
|
290
|
+
* Cares.new([options]) => cares_obj
|
|
291
|
+
* Cares.new([options]) { |socket, read, write| block } => cares_obj
|
|
292
|
+
*
|
|
293
|
+
* Creates a new <code>Cares</code> object. The <code>options</code> hash
|
|
294
|
+
* accepts the following keys:
|
|
295
|
+
*
|
|
296
|
+
* * <code>:flags</code> Flags controlling the behaviour of the resolver.
|
|
297
|
+
* See below for a description os the possible flags.
|
|
298
|
+
* * <code>:timeout</code> The number of seconds each name server is given
|
|
299
|
+
* to respond to a query on the first try. For further queries, the timeout
|
|
300
|
+
* scales nearly with the provided value. The default is 5 seconds.
|
|
301
|
+
* * <code>:tries</code> The number of times the resolver will try to
|
|
302
|
+
* contact each name server before giving up. The default is 4 tries.
|
|
303
|
+
* * <code>:ndots</code> The number of dots that must be present in a
|
|
304
|
+
* domain name for it to be queried "as is", prior to querying with the
|
|
305
|
+
* default domain extensions appended. The default is 1, unless set
|
|
306
|
+
* otherwise in resolv.conf or the <code>RES_OPTIONS</code> environment
|
|
307
|
+
* variable.
|
|
308
|
+
* * <code>:udp_port</code> The port to use for UDP queries. The default is 53.
|
|
309
|
+
* * <code>:tcp_port</code> The port to use for TCP queries. The default is 53.
|
|
310
|
+
* * <code>:servers</code> An array of IP addresses to be used as the servers
|
|
311
|
+
* to be contacted, instead of the ones found in resolv.conf or the local
|
|
312
|
+
* name daemon.
|
|
313
|
+
* * <code>:domains</code> An array of domains to be searched, instead of
|
|
314
|
+
* the ones specified in resolv.conf or the machine hostname.
|
|
315
|
+
* * <code>:lookups</code> The lookups to perform for host queries. It
|
|
316
|
+
* should be a string of the characters <i>b</i> or <i>f</i>, where <i>b</i>
|
|
317
|
+
* indicates a DNS lookup, and <i>f</i> indicates a hosts file lookup.
|
|
318
|
+
*
|
|
319
|
+
* The <code>:flags</code> option is a bitwise-or of values from the list
|
|
320
|
+
* below:
|
|
321
|
+
*
|
|
322
|
+
* * <code>Cares::Init::USEVC</code> Always use TCP queries. Normally, TCP
|
|
323
|
+
* is only used if a UDP query returns a truncated result.
|
|
324
|
+
* * <code>Cares::Init::PRIMARY</code> Only query the first server in the
|
|
325
|
+
* server list.
|
|
326
|
+
* * <code>Cares::Init::IGNTC</code> If a truncated response to an UDP query
|
|
327
|
+
* is received, do not fall back to TCP; simply continue with the truncated
|
|
328
|
+
* response.
|
|
329
|
+
* * <code>Cares::Init::NORECURSE</code> Do not set the "recursion desired"
|
|
330
|
+
* bit on outgoing queries.
|
|
331
|
+
* * <code>Cares::Init::STAYOPEN</code> Do not close the communication
|
|
332
|
+
* sockets when the number of active queries drops to zero.
|
|
333
|
+
* * <code>Cares::Init::NOSEARCH</code> Do not use the default search
|
|
334
|
+
* domains; only query hostnames as-is or as aliases.
|
|
335
|
+
* * <code>Cares::Init::NOALIASES</code> Do not honor the
|
|
336
|
+
* <code>HOSTALIASES</code> environment variable, which specifies a
|
|
337
|
+
* file of hostname translations.
|
|
338
|
+
* * <code>Cares::Init::NOCHECKRESP</code> Do not discard responses with the
|
|
339
|
+
* <code>SERVFAIL</code>, <code>NOTIMP</code>, or <code>REFUSED</code>
|
|
340
|
+
* response codes or responses whose questions don't match the
|
|
341
|
+
* questions in the request.
|
|
342
|
+
*
|
|
343
|
+
* If a block is given, it'll be called when a socket used in name resolving
|
|
344
|
+
* has its state changed. The block takes three arguments. The first one is
|
|
345
|
+
* the <code>Socket</code> object, the the other two are boolean values
|
|
346
|
+
* indicating if the socket should listen for read and/or write events,
|
|
347
|
+
* respectively.
|
|
348
|
+
*/
|
|
349
|
+
static VALUE
|
|
350
|
+
rb_cares_init(int argc, VALUE *argv, VALUE self)
|
|
351
|
+
{
|
|
352
|
+
int status, optmask;
|
|
353
|
+
ares_channel *chp;
|
|
354
|
+
struct ares_options ao;
|
|
355
|
+
VALUE opts;
|
|
356
|
+
|
|
357
|
+
Data_Get_Struct(self, ares_channel, chp);
|
|
358
|
+
|
|
359
|
+
rb_scan_args(argc, argv, "01", &opts);
|
|
360
|
+
if (NIL_P(opts) && !rb_block_given_p()) {
|
|
361
|
+
status = ares_init(chp);
|
|
362
|
+
if (status != ARES_SUCCESS)
|
|
363
|
+
raise_error(status);
|
|
364
|
+
return(self);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
optmask = set_init_opts(opts, &ao);
|
|
368
|
+
|
|
369
|
+
status = ares_init_options(chp, &ao, optmask);
|
|
370
|
+
if (status != ARES_SUCCESS)
|
|
371
|
+
raise_error(status);
|
|
372
|
+
|
|
373
|
+
return(self);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
static void
|
|
377
|
+
host_callback(void *arg, int status, struct hostent *hp)
|
|
378
|
+
{
|
|
379
|
+
char buf[BUFLEN], **p;
|
|
380
|
+
VALUE block, info, aliases;
|
|
381
|
+
|
|
382
|
+
if (status != ARES_SUCCESS)
|
|
383
|
+
raise_error(status);
|
|
384
|
+
|
|
385
|
+
block = (VALUE)arg;
|
|
386
|
+
|
|
387
|
+
info = rb_ary_new();
|
|
388
|
+
rb_ary_push(info, rb_str_new2(hp->h_name));
|
|
389
|
+
|
|
390
|
+
aliases = rb_ary_new();
|
|
391
|
+
rb_ary_push(info, aliases);
|
|
392
|
+
if (hp->h_aliases != NULL) {
|
|
393
|
+
for (p = hp->h_aliases; *p; p++)
|
|
394
|
+
rb_ary_push(aliases, rb_str_new2(*p));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
rb_ary_push(info, INT2NUM(hp->h_addrtype));
|
|
398
|
+
|
|
399
|
+
for (p = hp->h_addr_list; *p != NULL; p++) {
|
|
400
|
+
inet_ntop(hp->h_addrtype, *p, buf, BUFLEN);
|
|
401
|
+
rb_ary_push(info, rb_str_new2(buf));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
rb_funcall(block, rb_intern("call"), 1, info);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/*
|
|
408
|
+
* call-seq:
|
|
409
|
+
* cares.gethostbyname(name, family) { |cname, aliases, family, *addrs| block } => cares
|
|
410
|
+
*
|
|
411
|
+
* Performs a DNS lookup on <code>name</code>, for addresses of family
|
|
412
|
+
* <code>family</code>. The <code>family</code> argument is either
|
|
413
|
+
* <code>Socket::AF_INET</code> or <code>Socket::AF_INET6</code>. The results
|
|
414
|
+
* are passed as arguments to the block:
|
|
415
|
+
*
|
|
416
|
+
* * <code>cname</code>: <code>name</code>'s canonical name.
|
|
417
|
+
* * <code>aliases</code>: array of aliases.
|
|
418
|
+
* * <code>family</code>: address family.
|
|
419
|
+
* * <code>*addrs</code>: array containing <code>name</code>'s addresses.
|
|
420
|
+
*/
|
|
421
|
+
static VALUE
|
|
422
|
+
rb_cares_gethostbyname(VALUE self, VALUE host, VALUE family)
|
|
423
|
+
{
|
|
424
|
+
ares_channel *chp;
|
|
425
|
+
|
|
426
|
+
if (!rb_block_given_p())
|
|
427
|
+
rb_raise(rb_eArgError, "gethostbyname: block needed");
|
|
428
|
+
|
|
429
|
+
Data_Get_Struct(self, ares_channel, chp);
|
|
430
|
+
ares_gethostbyname(*chp, StringValuePtr(host), NUM2INT(family),
|
|
431
|
+
host_callback, (void *)rb_block_proc());
|
|
432
|
+
return(self);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/*
|
|
436
|
+
* call-seq:
|
|
437
|
+
* cares.gethostbyaddr(addr, family) { |name, aliases, family, *addrs| block } => cares
|
|
438
|
+
*
|
|
439
|
+
* Performs a reverse DNS query on <code>addr</code>. for addresses of family
|
|
440
|
+
* <code>family</code>. The <code>family</code> argument is either
|
|
441
|
+
* <code>Socket::AF_INET</code> or <code>Socket::AF_INET6</code>. The results
|
|
442
|
+
* are passed as arguments to the block:
|
|
443
|
+
*
|
|
444
|
+
* * <code>name</code>: <code>addr</code>'s name.
|
|
445
|
+
* * <code>aliases</code>: array of aliases.
|
|
446
|
+
* * <code>family</code>: address family.
|
|
447
|
+
* * <code>*addrs</code>: array containing <code>name</code>'s addresses.
|
|
448
|
+
*/
|
|
449
|
+
static VALUE
|
|
450
|
+
rb_cares_gethostbyaddr(VALUE self, VALUE addr, VALUE family)
|
|
451
|
+
{
|
|
452
|
+
char *caddr;
|
|
453
|
+
int cfamily;
|
|
454
|
+
ares_channel *chp;
|
|
455
|
+
|
|
456
|
+
if (!rb_block_given_p())
|
|
457
|
+
rb_raise(rb_eArgError, "gethostbyaddr: block needed");
|
|
458
|
+
|
|
459
|
+
Data_Get_Struct(self, ares_channel, chp);
|
|
460
|
+
cfamily = NUM2INT(family);
|
|
461
|
+
caddr = StringValuePtr(addr);
|
|
462
|
+
|
|
463
|
+
switch (cfamily) {
|
|
464
|
+
case AF_INET: {
|
|
465
|
+
struct in_addr in;
|
|
466
|
+
if (inet_pton(cfamily, caddr, &in) != 1)
|
|
467
|
+
rb_sys_fail("gethostbyaddr");
|
|
468
|
+
ares_gethostbyaddr(*chp, &in, sizeof(in), cfamily,
|
|
469
|
+
host_callback, (void *)rb_block_proc());
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
case AF_INET6: {
|
|
473
|
+
struct in6_addr in6;
|
|
474
|
+
if (inet_pton(cfamily, caddr, &in6) != 1)
|
|
475
|
+
rb_sys_fail("gethostbyaddr");
|
|
476
|
+
ares_gethostbyaddr(*chp, &in6, sizeof(in6), cfamily,
|
|
477
|
+
host_callback, (void *)rb_block_proc());
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
default:
|
|
481
|
+
rb_raise(cNotImpError, "gethostbyaddr: invalid address family");
|
|
482
|
+
}
|
|
483
|
+
return(self);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
static void
|
|
487
|
+
nameinfo_callback(void *arg, int status, char *node, char *service)
|
|
488
|
+
{
|
|
489
|
+
VALUE block, info;
|
|
490
|
+
|
|
491
|
+
if (status != ARES_SUCCESS)
|
|
492
|
+
raise_error(status);
|
|
493
|
+
|
|
494
|
+
block = (VALUE)arg;
|
|
495
|
+
info = rb_ary_new();
|
|
496
|
+
|
|
497
|
+
if (node != NULL)
|
|
498
|
+
rb_ary_push(info, rb_str_new2(node));
|
|
499
|
+
if (service != NULL)
|
|
500
|
+
rb_ary_push(info, rb_str_new2(service));
|
|
501
|
+
|
|
502
|
+
rb_funcall(block, rb_intern("call"), 1, info);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/*
|
|
506
|
+
* call-seq:
|
|
507
|
+
* cares.getnameinfo(nameservice) { |name, service| block } => cares
|
|
508
|
+
*
|
|
509
|
+
* Performs a protocol-independent reverse lookup on the host and/or service
|
|
510
|
+
* names specified on the <code>nameservice</code> hash. The valid keys are:
|
|
511
|
+
*
|
|
512
|
+
* * <code>:addr</code>: IPv4 or IPv6 address.
|
|
513
|
+
* * <code>:service</code>: Service name.
|
|
514
|
+
*
|
|
515
|
+
* The lookup results are passed as parameters to the block.
|
|
516
|
+
*/
|
|
517
|
+
static VALUE
|
|
518
|
+
rb_cares_getnameinfo(VALUE self, VALUE info)
|
|
519
|
+
{
|
|
520
|
+
int cflags;
|
|
521
|
+
socklen_t sslen;
|
|
522
|
+
struct sockaddr_storage ss;
|
|
523
|
+
ares_channel *chp;
|
|
524
|
+
VALUE vaddr, vport, vflags;
|
|
525
|
+
|
|
526
|
+
Data_Get_Struct(self, ares_channel, chp);
|
|
527
|
+
|
|
528
|
+
vflags = rb_hash_aref(info, ID2SYM(rb_intern("flags")));
|
|
529
|
+
if (!NIL_P(vflags))
|
|
530
|
+
cflags = NUM2INT(vflags);
|
|
531
|
+
else
|
|
532
|
+
cflags = 0;
|
|
533
|
+
|
|
534
|
+
sslen = 0;
|
|
535
|
+
ss.ss_family = AF_INET;
|
|
536
|
+
|
|
537
|
+
vaddr = rb_hash_aref(info, ID2SYM(rb_intern("addr")));
|
|
538
|
+
if (!NIL_P(vaddr)) {
|
|
539
|
+
char *caddr = StringValuePtr(vaddr);
|
|
540
|
+
struct sockaddr_in *sinp;
|
|
541
|
+
struct sockaddr_in6 *sin6p;
|
|
542
|
+
|
|
543
|
+
sinp = (struct sockaddr_in *)&ss;
|
|
544
|
+
sin6p = (struct sockaddr_in6 *)&ss;
|
|
545
|
+
|
|
546
|
+
cflags |= ARES_NI_LOOKUPHOST;
|
|
547
|
+
|
|
548
|
+
if (inet_pton(AF_INET, caddr, &sinp->sin_addr) == 1) {
|
|
549
|
+
sslen = sizeof(struct sockaddr_in);
|
|
550
|
+
} else if (inet_pton(AF_INET6, caddr, &sin6p->sin6_addr) == 1) {
|
|
551
|
+
ss.ss_family = AF_INET6;
|
|
552
|
+
sslen = sizeof(struct sockaddr_in6);
|
|
553
|
+
} else {
|
|
554
|
+
rb_raise(cNotImpError,
|
|
555
|
+
"getnameinfo: invalid address family");
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
vport = rb_hash_aref(info, ID2SYM(rb_intern("port")));
|
|
560
|
+
if (!NIL_P(vport)) {
|
|
561
|
+
u_short cport = htons(NUM2UINT(vport));
|
|
562
|
+
cflags |= ARES_NI_LOOKUPSERVICE;
|
|
563
|
+
switch (ss.ss_family) {
|
|
564
|
+
case AF_INET:
|
|
565
|
+
((struct sockaddr_in *)&ss)->sin_port = cport;
|
|
566
|
+
sslen = sizeof(struct sockaddr_in);
|
|
567
|
+
break;
|
|
568
|
+
case AF_INET6:
|
|
569
|
+
((struct sockaddr_in6 *)&ss)->sin6_port = cport;
|
|
570
|
+
sslen = sizeof(struct sockaddr_in6);
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
ares_getnameinfo(*chp, (struct sockaddr *)&ss, sslen, cflags,
|
|
576
|
+
nameinfo_callback, (void *)rb_block_proc());
|
|
577
|
+
return(self);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/*
|
|
581
|
+
* call-seq:
|
|
582
|
+
* cares.select_loop(timeout=nil) => nil
|
|
583
|
+
*
|
|
584
|
+
* Handles the input/output and timeout associated witht the queries made
|
|
585
|
+
* from the name and address lookup methods. The block passed to each of
|
|
586
|
+
* those methods is yielded when the event is processed.
|
|
587
|
+
*
|
|
588
|
+
* The <code>timeout</code> hash accepts the following keys:
|
|
589
|
+
*
|
|
590
|
+
* * <code>:seconds</code>: Timeout in seconds.
|
|
591
|
+
* * <code>:useconds</code>: Timeout in microseconds.
|
|
592
|
+
*/
|
|
593
|
+
static VALUE
|
|
594
|
+
rb_cares_select_loop(int argc, VALUE *argv, VALUE self)
|
|
595
|
+
{
|
|
596
|
+
int nfds;
|
|
597
|
+
fd_set read, write;
|
|
598
|
+
struct timeval *tvp, tv;
|
|
599
|
+
struct timeval *maxtvp, maxtv;
|
|
600
|
+
ares_channel *chp;
|
|
601
|
+
VALUE timeout;
|
|
602
|
+
|
|
603
|
+
rb_scan_args(argc, argv, "01", &timeout);
|
|
604
|
+
|
|
605
|
+
maxtvp = NULL;
|
|
606
|
+
if (!NIL_P(timeout)) {
|
|
607
|
+
VALUE secs, usecs;
|
|
608
|
+
|
|
609
|
+
secs = rb_hash_aref(timeout, ID2SYM(rb_intern("seconds")));
|
|
610
|
+
if (!NIL_P(secs))
|
|
611
|
+
maxtv.tv_sec = NUM2LONG(secs);
|
|
612
|
+
usecs = rb_hash_aref(timeout, ID2SYM(rb_intern("useconds")));
|
|
613
|
+
if (!NIL_P(usecs))
|
|
614
|
+
maxtv.tv_usec = NUM2LONG(usecs);
|
|
615
|
+
|
|
616
|
+
if (!NIL_P(secs) || !NIL_P(usecs))
|
|
617
|
+
maxtvp = &maxtv;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
Data_Get_Struct(self, ares_channel, chp);
|
|
621
|
+
|
|
622
|
+
for (;;) {
|
|
623
|
+
FD_ZERO(&read);
|
|
624
|
+
FD_ZERO(&write);
|
|
625
|
+
nfds = ares_fds(*chp, &read, &write);
|
|
626
|
+
if (nfds == 0)
|
|
627
|
+
break;
|
|
628
|
+
tvp = ares_timeout(*chp, maxtvp, &tv);
|
|
629
|
+
rb_thread_select(nfds, &read, &write, NULL, tvp);
|
|
630
|
+
ares_process(*chp, &read, &write);
|
|
631
|
+
}
|
|
632
|
+
return(Qnil);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
void
|
|
636
|
+
Init_cares(void)
|
|
637
|
+
{
|
|
638
|
+
VALUE cCares = rb_define_class("Cares", rb_cObject);
|
|
639
|
+
define_cares_exceptions(cCares);
|
|
640
|
+
|
|
641
|
+
cInit = rb_define_class_under(cCares, "Init", rb_cObject);
|
|
642
|
+
define_init_flags(cInit);
|
|
643
|
+
|
|
644
|
+
cNameInfo = rb_define_class_under(cCares, "NameInfo", rb_cObject);
|
|
645
|
+
define_nameinfo_flags(cNameInfo);
|
|
646
|
+
|
|
647
|
+
rb_define_alloc_func(cCares, rb_cares_alloc);
|
|
648
|
+
rb_define_method(cCares, "initialize", rb_cares_init, -1);
|
|
649
|
+
rb_define_method(cCares, "gethostbyname", rb_cares_gethostbyname, 2);
|
|
650
|
+
rb_define_method(cCares, "gethostbyaddr", rb_cares_gethostbyaddr, 2);
|
|
651
|
+
rb_define_method(cCares, "getnameinfo", rb_cares_getnameinfo, 1);
|
|
652
|
+
rb_define_method(cCares, "select_loop", rb_cares_select_loop, -1);
|
|
653
|
+
}
|
data/ext/extconf.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
rubygems_version: 0.9.0
|
|
3
|
+
specification_version: 1
|
|
4
|
+
name: ruby-cares
|
|
5
|
+
version: !ruby/object:Gem::Version
|
|
6
|
+
version: 0.1.0
|
|
7
|
+
date: 2006-09-06 00:00:00 -03:00
|
|
8
|
+
summary: A Ruby extension for c-ares
|
|
9
|
+
require_paths:
|
|
10
|
+
- lib
|
|
11
|
+
email: andre@digirati.com.br
|
|
12
|
+
homepage: http://cares.rubyforge.org
|
|
13
|
+
rubyforge_project: cares
|
|
14
|
+
description: Ruby/Cares is a C extension for the c-ares library, Providing an asynchronous DNS resolver to be used with ruby scripts.
|
|
15
|
+
autorequire: cares
|
|
16
|
+
default_executable:
|
|
17
|
+
bindir: bin
|
|
18
|
+
has_rdoc: false
|
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">"
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 0.0.0
|
|
24
|
+
version:
|
|
25
|
+
platform: ruby
|
|
26
|
+
signing_key:
|
|
27
|
+
cert_chain:
|
|
28
|
+
post_install_message:
|
|
29
|
+
authors:
|
|
30
|
+
- Andre Nathan
|
|
31
|
+
files:
|
|
32
|
+
- ext/extconf.rb
|
|
33
|
+
- ext/cares.c
|
|
34
|
+
- examples/example.rb
|
|
35
|
+
test_files: []
|
|
36
|
+
|
|
37
|
+
rdoc_options: []
|
|
38
|
+
|
|
39
|
+
extra_rdoc_files: []
|
|
40
|
+
|
|
41
|
+
executables: []
|
|
42
|
+
|
|
43
|
+
extensions:
|
|
44
|
+
- ext/extconf.rb
|
|
45
|
+
requirements:
|
|
46
|
+
- c-ares
|
|
47
|
+
dependencies: []
|
|
48
|
+
|