Ruby
1.9.3p551(2014-11-13revision48407)
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
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
freeaddrinfo
(arg->
remote
.
res
);
29
arg->
remote
.
res
= 0;
30
}
31
if
(arg->
local
.
res
) {
32
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;
46
int
fd, status = 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
; res; res = res->
ai_next
) {
61
#if !defined(INET6) && defined(AF_INET6)
62
if
(res->
ai_family
== AF_INET6)
63
continue
;
64
#endif
65
status =
rsock_socket
(res->
ai_family
,res->
ai_socktype
,res->
ai_protocol
);
66
syscall =
"socket(2)"
;
67
fd = status;
68
if
(fd < 0) {
69
continue
;
70
}
71
arg->
fd
= fd;
72
if
(type ==
INET_SERVER
) {
73
#if !defined(_WIN32) && !defined(__CYGWIN__)
74
status = 1;
75
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
76
(
char
*)&status, (socklen_t)
sizeof
(status));
77
#endif
78
status = bind(fd, res->
ai_addr
, res->
ai_addrlen
);
79
syscall =
"bind(2)"
;
80
}
81
else
{
82
if
(arg->
local
.
res
) {
83
status = bind(fd, arg->
local
.
res
->
ai_addr
, arg->
local
.
res
->
ai_addrlen
);
84
syscall =
"bind(2)"
;
85
}
86
87
if
(status >= 0) {
88
status =
rsock_connect
(fd, res->
ai_addr
, res->
ai_addrlen
,
89
(type ==
INET_SOCKS
));
90
syscall =
"connect(2)"
;
91
}
92
}
93
94
if
(status < 0) {
95
close(fd);
96
arg->
fd
= fd = -1;
97
continue
;
98
}
else
99
break
;
100
}
101
if
(status < 0) {
102
rb_sys_fail
(syscall);
103
}
104
105
arg->
fd
= -1;
106
107
if
(type ==
INET_SERVER
) {
108
status = listen(fd, 5);
109
if
(status < 0) {
110
close(fd);
111
rb_sys_fail
(
"listen(2)"
);
112
}
113
}
114
115
/* create new instance */
116
return
rsock_init_sock
(arg->
sock
, fd);
117
}
118
119
VALUE
120
rsock_init_inetsock
(
VALUE
sock,
VALUE
remote_host,
VALUE
remote_serv,
121
VALUE
local_host,
VALUE
local_serv,
int
type
)
122
{
123
struct
inetsock_arg
arg;
124
arg.
sock
=
sock
;
125
arg.
remote
.
host
= remote_host;
126
arg.
remote
.
serv
= remote_serv;
127
arg.
remote
.
res
= 0;
128
arg.
local
.
host
= local_host;
129
arg.
local
.
serv
= local_serv;
130
arg.
local
.
res
= 0;
131
arg.
type
=
type
;
132
arg.
fd
= -1;
133
return
rb_ensure
(
init_inetsock_internal
, (
VALUE
)&arg,
134
inetsock_cleanup
, (
VALUE
)&arg);
135
}
136
137
static
ID
id_numeric
,
id_hostname
;
138
139
int
140
rsock_revlookup_flag
(
VALUE
revlookup,
int
*norevlookup)
141
{
142
#define return_norevlookup(x) {*norevlookup = (x); return 1;}
143
ID
id
;
144
145
switch
(revlookup) {
146
case
Qtrue
:
return_norevlookup
(0);
147
case
Qfalse
:
return_norevlookup
(1);
148
case
Qnil
:
break
;
149
default
:
150
Check_Type
(revlookup,
T_SYMBOL
);
151
id
=
SYM2ID
(revlookup);
152
if
(
id
==
id_numeric
)
return_norevlookup
(1);
153
if
(
id
==
id_hostname
)
return_norevlookup
(0);
154
rb_raise
(
rb_eArgError
,
"invalid reverse_lookup flag: :%s"
,
rb_id2name
(
id
));
155
}
156
return
0;
157
#undef return_norevlookup
158
}
159
160
/*
161
* call-seq:
162
* ipsocket.addr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
163
*
164
* Returns the local address as an array which contains
165
* address_family, port, hostname and numeric_address.
166
*
167
* If +reverse_lookup+ is +true+ or +:hostname+,
168
* hostname is obtained from numeric_address using reverse lookup.
169
* Or if it is +false+, or +:numeric+,
170
* hostname is same as numeric_address.
171
* Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
172
* See +Socket.getaddrinfo+ also.
173
*
174
* TCPSocket.open("www.ruby-lang.org", 80) {|sock|
175
* p sock.addr #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
176
* p sock.addr(true) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
177
* p sock.addr(false) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
178
* p sock.addr(:hostname) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
179
* p sock.addr(:numeric) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
180
* }
181
*
182
*/
183
static
VALUE
184
ip_addr
(
int
argc
,
VALUE
*
argv
,
VALUE
sock
)
185
{
186
rb_io_t
*fptr;
187
struct
sockaddr_storage
addr;
188
socklen_t
len
= (socklen_t)
sizeof
addr;
189
int
norevlookup;
190
191
GetOpenFile
(sock, fptr);
192
193
if
(argc < 1 || !
rsock_revlookup_flag
(argv[0], &norevlookup))
194
norevlookup = fptr->
mode
&
FMODE_NOREVLOOKUP
;
195
if
(getsockname(fptr->
fd
, (
struct
sockaddr*)&addr, &len) < 0)
196
rb_sys_fail
(
"getsockname(2)"
);
197
return
rsock_ipaddr
((
struct
sockaddr*)&addr, norevlookup);
198
}
199
200
/*
201
* call-seq:
202
* ipsocket.peeraddr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
203
*
204
* Returns the remote address as an array which contains
205
* address_family, port, hostname and numeric_address.
206
* It is defined for connection oriented socket such as TCPSocket.
207
*
208
* If +reverse_lookup+ is +true+ or +:hostname+,
209
* hostname is obtained from numeric_address using reverse lookup.
210
* Or if it is +false+, or +:numeric+,
211
* hostname is same as numeric_address.
212
* Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
213
* See +Socket.getaddrinfo+ also.
214
*
215
* TCPSocket.open("www.ruby-lang.org", 80) {|sock|
216
* p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
217
* p sock.peeraddr(true) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
218
* p sock.peeraddr(false) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
219
* p sock.peeraddr(:hostname) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
220
* p sock.peeraddr(:numeric) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
221
* }
222
*
223
*/
224
static
VALUE
225
ip_peeraddr
(
int
argc
,
VALUE
*
argv
,
VALUE
sock)
226
{
227
rb_io_t
*fptr;
228
struct
sockaddr_storage
addr;
229
socklen_t
len
= (socklen_t)
sizeof
addr;
230
int
norevlookup;
231
232
GetOpenFile
(sock, fptr);
233
234
if
(argc < 1 || !
rsock_revlookup_flag
(argv[0], &norevlookup))
235
norevlookup = fptr->
mode
&
FMODE_NOREVLOOKUP
;
236
if
(getpeername(fptr->
fd
, (
struct
sockaddr*)&addr, &len) < 0)
237
rb_sys_fail
(
"getpeername(2)"
);
238
return
rsock_ipaddr
((
struct
sockaddr*)&addr, norevlookup);
239
}
240
241
/*
242
* call-seq:
243
* ipsocket.recvfrom(maxlen) => [mesg, ipaddr]
244
* ipsocket.recvfrom(maxlen, flags) => [mesg, ipaddr]
245
*
246
* Receives a message and return the message as a string and
247
* an address which the message come from.
248
*
249
* _maxlen_ is the maximum number of bytes to receive.
250
*
251
* _flags_ should be a bitwise OR of Socket::MSG_* constants.
252
*
253
* ipaddr is same as IPSocket#{peeraddr,addr}.
254
*
255
* u1 = UDPSocket.new
256
* u1.bind("127.0.0.1", 4913)
257
* u2 = UDPSocket.new
258
* u2.send "uuuu", 0, "127.0.0.1", 4913
259
* p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
260
*
261
*/
262
static
VALUE
263
ip_recvfrom
(
int
argc
,
VALUE
*
argv
,
VALUE
sock)
264
{
265
return
rsock_s_recvfrom
(sock, argc, argv,
RECV_IP
);
266
}
267
268
/*
269
* call-seq:
270
* IPSocket.getaddress(host) => ipaddress
271
*
272
* Lookups the IP address of _host_.
273
*
274
* IPSocket.getaddress("localhost") #=> "127.0.0.1"
275
* IPSocket.getaddress("ip6-localhost") #=> "::1"
276
*
277
*/
278
static
VALUE
279
ip_s_getaddress
(
VALUE
obj,
VALUE
host)
280
{
281
struct
sockaddr_storage
addr;
282
struct
addrinfo
*res =
rsock_addrinfo
(host,
Qnil
, SOCK_STREAM, 0);
283
284
/* just take the first one */
285
memcpy(&addr, res->
ai_addr
, res->
ai_addrlen
);
286
freeaddrinfo
(res);
287
288
return
rsock_make_ipaddr
((
struct
sockaddr*)&addr);
289
}
290
291
void
292
rsock_init_ipsocket
(
void
)
293
{
294
/*
295
* Document-class: IPSocket < BasicSocket
296
*
297
* IPSocket is the super class of TCPSocket and UDPSocket.
298
*/
299
rb_cIPSocket
=
rb_define_class
(
"IPSocket"
,
rb_cBasicSocket
);
300
rb_define_method
(
rb_cIPSocket
,
"addr"
,
ip_addr
, -1);
301
rb_define_method
(
rb_cIPSocket
,
"peeraddr"
,
ip_peeraddr
, -1);
302
rb_define_method
(
rb_cIPSocket
,
"recvfrom"
,
ip_recvfrom
, -1);
303
rb_define_singleton_method
(
rb_cIPSocket
,
"getaddress"
,
ip_s_getaddress
, 1);
304
rb_undef_method
(
rb_cIPSocket
,
"getpeereid"
);
305
306
id_numeric
=
rb_intern_const
(
"numeric"
);
307
id_hostname
=
rb_intern_const
(
"hostname"
);
308
}
309
Generated on Fri Nov 14 2014 16:04:03 for Ruby by
1.8.3