Ruby
2.1.3p242(2014-09-19revision47630)
Main Page
Modules
Data Structures
Files
File List
Globals
ext
socket
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
}
335
Generated on Mon Sep 22 2014 11:05:29 for Ruby by
1.8.2