Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

ipsocket.c
Go to the documentation of this file.
1 /************************************************
2
3 ipsocket.c -
4
5 created at: Thu Mar 31 12:21:29 JST 1994
6
7 Copyright (C) 1993-2007 Yukihiro Matsumoto
8
9 ************************************************/
10
11 #include "rubysocket.h"
12
13 struct inetsock_arg
14 {
15 VALUE sock;
16 struct {
17 VALUE host, serv;
18 struct rb_addrinfo *res;
19 } remote, local;
20 int type;
21 int fd;
22 };
23
24 static VALUE
25 inetsock_cleanup(struct inetsock_arg *arg)
26 {
27 if (arg->remote.res) {
28 rb_freeaddrinfo(arg->remote.res);
29 arg->remote.res = 0;
30 }
31 if (arg->local.res) {
32 rb_freeaddrinfo(arg->local.res);
33 arg->local.res = 0;
34 }
35 if (arg->fd >= 0) {
36 close(arg->fd);
37 }
38 return Qnil;
39 }
40
41 static VALUE
42 init_inetsock_internal(struct inetsock_arg *arg)
43 {
44 int type = arg->type;
45 struct addrinfo *res, *lres;
46 int fd, status = 0, local = 0;
47 const char *syscall = 0;
48
49 arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM,
50 (type == INET_SERVER) ? AI_PASSIVE : 0);
51 /*
52 * Maybe also accept a local address
53 */
54
55 if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
56 arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0);
57 }
58
59 arg->fd = fd = -1;
60 for (res = arg->remote.res->ai; res; res = res->ai_next) {
61 #if !defined(INET6) && defined(AF_INET6)
62 if (res->ai_family == AF_INET6)
63 continue;
64 #endif
65 lres = NULL;
66 if (arg->local.res) {
67 for (lres = arg->local.res->ai; lres; lres = lres->ai_next) {
68 if (lres->ai_family == res->ai_family)
69 break;
70 }
71 if (!lres) {
72 if (res->ai_next || status < 0)
73 continue;
74 /* Use a different family local address if no choice, this
75 * will cause EAFNOSUPPORT. */
76 lres = arg->local.res->ai;
77 }
78 }
79 status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol);
80 syscall = "socket(2)";
81 fd = status;
82 if (fd < 0) {
83 continue;
84 }
85 arg->fd = fd;
86 if (type == INET_SERVER) {
87 #if !defined(_WIN32) && !defined(__CYGWIN__)
88 status = 1;
89 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
90 (char*)&status, (socklen_t)sizeof(status));
91 #endif
92 status = bind(fd, res->ai_addr, res->ai_addrlen);
93 syscall = "bind(2)";
94 }
95 else {
96 if (lres) {
97 status = bind(fd, lres->ai_addr, lres->ai_addrlen);
98 local = status;
99 syscall = "bind(2)";
100 }
101
102 if (status >= 0) {
103 status = rsock_connect(fd, res->ai_addr, res->ai_addrlen,
104 (type == INET_SOCKS));
105 syscall = "connect(2)";
106 }
107 }
108
109 if (status < 0) {
110 close(fd);
111 arg->fd = fd = -1;
112 continue;
113 } else
114 break;
115 }
116 if (status < 0) {
117 VALUE host, port;
118
119 if (local < 0) {
120 host = arg->local.host;
121 port = arg->local.serv;
122 } else {
123 host = arg->remote.host;
124 port = arg->remote.serv;
125 }
126
127 rsock_sys_fail_host_port(syscall, host, port);
128 }
129
130 arg->fd = -1;
131
132 if (type == INET_SERVER) {
133 status = listen(fd, SOMAXCONN);
134 if (status < 0) {
135 close(fd);
136 rb_sys_fail("listen(2)");
137 }
138 }
139
140 /* create new instance */
141 return rsock_init_sock(arg->sock, fd);
142 }
143
144 VALUE
145 rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
146 VALUE local_host, VALUE local_serv, int type)
147 {
148 struct inetsock_arg arg;
149 arg.sock = sock;
150 arg.remote.host = remote_host;
151 arg.remote.serv = remote_serv;
152 arg.remote.res = 0;
153 arg.local.host = local_host;
154 arg.local.serv = local_serv;
155 arg.local.res = 0;
156 arg.type = type;
157 arg.fd = -1;
158 return rb_ensure(init_inetsock_internal, (VALUE)&arg,
159 inetsock_cleanup, (VALUE)&arg);
160 }
161
162 static ID id_numeric, id_hostname;
163
164 int
165 rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
166 {
167 #define return_norevlookup(x) {*norevlookup = (x); return 1;}
168 ID id;
169
170 switch (revlookup) {
171 case Qtrue: return_norevlookup(0);
172 case Qfalse: return_norevlookup(1);
173 case Qnil: break;
174 default:
175 Check_Type(revlookup, T_SYMBOL);
176 id = SYM2ID(revlookup);
177 if (id == id_numeric) return_norevlookup(1);
178 if (id == id_hostname) return_norevlookup(0);
179 rb_raise(rb_eArgError, "invalid reverse_lookup flag: :%s", rb_id2name(id));
180 }
181 return 0;
182 #undef return_norevlookup
183 }
184
185 /*
186 * call-seq:
187 * ipsocket.addr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
188 *
189 * Returns the local address as an array which contains
190 * address_family, port, hostname and numeric_address.
191 *
192 * If +reverse_lookup+ is +true+ or +:hostname+,
193 * hostname is obtained from numeric_address using reverse lookup.
194 * Or if it is +false+, or +:numeric+,
195 * hostname is same as numeric_address.
196 * Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
197 * See +Socket.getaddrinfo+ also.
198 *
199 * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
200 * p sock.addr #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
201 * p sock.addr(true) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
202 * p sock.addr(false) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
203 * p sock.addr(:hostname) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
204 * p sock.addr(:numeric) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
205 * }
206 *
207 */
208 static VALUE
209 ip_addr(int argc, VALUE *argv, VALUE sock)
210 {
211 rb_io_t *fptr;
212 union_sockaddr addr;
213 socklen_t len = (socklen_t)sizeof addr;
214 int norevlookup;
215
216 GetOpenFile(sock, fptr);
217
218 if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
219 norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
220 if (getsockname(fptr->fd, &addr.addr, &len) < 0)
221 rb_sys_fail("getsockname(2)");
222 return rsock_ipaddr(&addr.addr, len, norevlookup);
223 }
224
225 /*
226 * call-seq:
227 * ipsocket.peeraddr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
228 *
229 * Returns the remote address as an array which contains
230 * address_family, port, hostname and numeric_address.
231 * It is defined for connection oriented socket such as TCPSocket.
232 *
233 * If +reverse_lookup+ is +true+ or +:hostname+,
234 * hostname is obtained from numeric_address using reverse lookup.
235 * Or if it is +false+, or +:numeric+,
236 * hostname is same as numeric_address.
237 * Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
238 * See +Socket.getaddrinfo+ also.
239 *
240 * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
241 * p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
242 * p sock.peeraddr(true) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
243 * p sock.peeraddr(false) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
244 * p sock.peeraddr(:hostname) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
245 * p sock.peeraddr(:numeric) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
246 * }
247 *
248 */
249 static VALUE
250 ip_peeraddr(int argc, VALUE *argv, VALUE sock)
251 {
252 rb_io_t *fptr;
253 union_sockaddr addr;
254 socklen_t len = (socklen_t)sizeof addr;
255 int norevlookup;
256
257 GetOpenFile(sock, fptr);
258
259 if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
260 norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
261 if (getpeername(fptr->fd, &addr.addr, &len) < 0)
262 rb_sys_fail("getpeername(2)");
263 return rsock_ipaddr(&addr.addr, len, norevlookup);
264 }
265
266 /*
267 * call-seq:
268 * ipsocket.recvfrom(maxlen) => [mesg, ipaddr]
269 * ipsocket.recvfrom(maxlen, flags) => [mesg, ipaddr]
270 *
271 * Receives a message and return the message as a string and
272 * an address which the message come from.
273 *
274 * _maxlen_ is the maximum number of bytes to receive.
275 *
276 * _flags_ should be a bitwise OR of Socket::MSG_* constants.
277 *
278 * ipaddr is same as IPSocket#{peeraddr,addr}.
279 *
280 * u1 = UDPSocket.new
281 * u1.bind("127.0.0.1", 4913)
282 * u2 = UDPSocket.new
283 * u2.send "uuuu", 0, "127.0.0.1", 4913
284 * p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
285 *
286 */
287 static VALUE
288 ip_recvfrom(int argc, VALUE *argv, VALUE sock)
289 {
290 return rsock_s_recvfrom(sock, argc, argv, RECV_IP);
291 }
292
293 /*
294 * call-seq:
295 * IPSocket.getaddress(host) => ipaddress
296 *
297 * Lookups the IP address of _host_.
298 *
299 * IPSocket.getaddress("localhost") #=> "127.0.0.1"
300 * IPSocket.getaddress("ip6-localhost") #=> "::1"
301 *
302 */
303 static VALUE
304 ip_s_getaddress(VALUE obj, VALUE host)
305 {
306 union_sockaddr addr;
307 struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0);
308 socklen_t len = res->ai->ai_addrlen;
309
310 /* just take the first one */
311 memcpy(&addr, res->ai->ai_addr, len);
312 rb_freeaddrinfo(res);
313
314 return rsock_make_ipaddr(&addr.addr, len);
315 }
316
317 void
318 rsock_init_ipsocket(void)
319 {
320 /*
321 * Document-class: IPSocket < BasicSocket
322 *
323 * IPSocket is the super class of TCPSocket and UDPSocket.
324 */
325 rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket);
326 rb_define_method(rb_cIPSocket, "addr", ip_addr, -1);
327 rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, -1);
328 rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1);
329 rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1);
330 rb_undef_method(rb_cIPSocket, "getpeereid");
331
332 id_numeric = rb_intern_const("numeric");
333 id_hostname = rb_intern_const("hostname");
334 }
T_SYMBOL
#define T_SYMBOL
Definition: ruby.h:494
inetsock_arg
Definition: ipsocket.c:13
SOMAXCONN
#define SOMAXCONN
Definition: constdefs.h:1704
rb_cBasicSocket
VALUE rb_cBasicSocket
Definition: init.c:13
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1655
Qtrue
#define Qtrue
Definition: ruby.h:426
rsock_make_ipaddr
VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen)
Definition: raddrinfo.c:367
rb_io_t
Definition: io.h:61
id
const int id
Definition: nkf.c:209
inetsock_arg::serv
VALUE serv
Definition: ipsocket.c:17
rsock_init_sock
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:43
SYM2ID
#define SYM2ID(x)
Definition: ruby.h:356
INET_SOCKS
#define INET_SOCKS
Definition: rubysocket.h:226
rb_cIPSocket
VALUE rb_cIPSocket
Definition: init.c:14
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:532
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
AI_PASSIVE
#define AI_PASSIVE
Definition: addrinfo.h:96
FMODE_NOREVLOOKUP
#define FMODE_NOREVLOOKUP
Definition: rubysocket.h:229
ip_peeraddr
static VALUE ip_peeraddr(int argc, VALUE *argv, VALUE sock)
Definition: ipsocket.c:250
rsock_ipaddr
VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
Definition: raddrinfo.c:505
rb_undef_method
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1506
GetOpenFile
#define GetOpenFile(obj, fp)
Definition: io.h:118
rb_io_t::mode
int mode
Definition: io.h:64
rb_freeaddrinfo
void rb_freeaddrinfo(struct rb_addrinfo *ai)
Definition: raddrinfo.c:293
rsock_addrinfo
struct rb_addrinfo * rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
Definition: raddrinfo.c:493
rb_addrinfo
Definition: rubysocket.h:281
inetsock_arg::remote
struct inetsock_arg::@93 remote
id_hostname
static ID id_hostname
Definition: ipsocket.c:162
union_sockaddr
Definition: rubysocket.h:184
rsock_socket
int rsock_socket(int domain, int type, int proto)
Definition: init.c:285
inetsock_arg::host
VALUE host
Definition: ipsocket.c:17
inetsock_arg::local
struct inetsock_arg::@93 local
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:630
rb_io_t::fd
int fd
Definition: io.h:62
inetsock_cleanup
static VALUE inetsock_cleanup(struct inetsock_arg *arg)
Definition: ipsocket.c:25
argc
int argc
Definition: ruby.c:131
Qfalse
#define Qfalse
Definition: ruby.h:425
init_inetsock_internal
static VALUE init_inetsock_internal(struct inetsock_arg *arg)
Definition: ipsocket.c:42
inetsock_arg::type
int type
Definition: ipsocket.c:20
socklen_t
int socklen_t
Definition: getaddrinfo.c:84
rsock_s_recvfrom
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
Definition: init.c:111
INET_SERVER
#define INET_SERVER
Definition: rubysocket.h:225
ID
unsigned long ID
Definition: ruby.h:89
Qnil
#define Qnil
Definition: ruby.h:427
type
int type
Definition: tcltklib.c:112
ip_s_getaddress
static VALUE ip_s_getaddress(VALUE obj, VALUE host)
Definition: ipsocket.c:304
rsock_sys_fail_host_port
void rsock_sys_fail_host_port(const char *mesg, VALUE host, VALUE port)
Definition: socket.c:16
VALUE
unsigned long VALUE
Definition: ruby.h:88
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
inetsock_arg::fd
int fd
Definition: ipsocket.c:21
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
id_numeric
static ID id_numeric
Definition: ipsocket.c:162
addrinfo::ai_protocol
int ai_protocol
Definition: addrinfo.h:135
ip_addr
static VALUE ip_addr(int argc, VALUE *argv, VALUE sock)
Definition: ipsocket.c:209
rubysocket.h
addrinfo::ai_socktype
int ai_socktype
Definition: addrinfo.h:134
rsock_revlookup_flag
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
Definition: ipsocket.c:165
return_norevlookup
#define return_norevlookup(x)
RECV_IP
Definition: rubysocket.h:331
rb_addrinfo::ai
struct addrinfo * ai
Definition: rubysocket.h:282
rsock_connect
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
Definition: init.c:386
ip_recvfrom
static VALUE ip_recvfrom(int argc, VALUE *argv, VALUE sock)
Definition: ipsocket.c:288
addrinfo::ai_next
struct addrinfo * ai_next
Definition: addrinfo.h:139
rsock_init_inetsock
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type)
Definition: ipsocket.c:145
rsock_init_ipsocket
void rsock_init_ipsocket(void)
Definition: ipsocket.c:318
rb_id2name
const char * rb_id2name(ID id)
Definition: ripper.c:17230
addrinfo::ai_addrlen
size_t ai_addrlen
Definition: addrinfo.h:136
rb_intern_const
#define rb_intern_const(str)
Definition: ruby.h:1442
addrinfo
Definition: addrinfo.h:131
NULL
#define NULL
Definition: _sdbm.c:103
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
addrinfo::ai_addr
struct sockaddr * ai_addr
Definition: addrinfo.h:138
inetsock_arg::res
struct rb_addrinfo * res
Definition: ipsocket.c:18
rb_eArgError
VALUE rb_eArgError
Definition: error.c:549
inetsock_arg::sock
VALUE sock
Definition: ipsocket.c:15
argv
char ** argv
Definition: ruby.c:132
union_sockaddr::addr
struct sockaddr addr
Definition: rubysocket.h:185
addrinfo::ai_family
int ai_family
Definition: addrinfo.h:133