Ruby
1.9.3p551(2014-11-13revision48407)
Main Page
Modules
Data Structures
Files
File List
Globals
ext
socket
udpsocket.c
Go to the documentation of this file.
1
/************************************************
2
3
udpsocket.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
/*
14
* call-seq:
15
* UDPSocket.new([address_family]) => socket
16
*
17
* Creates a new UDPSocket object.
18
*
19
* _address_family_ should be an integer, a string or a symbol:
20
* Socket::AF_INET, "AF_INET", :INET, etc.
21
*
22
* UDPSocket.new #=> #<UDPSocket:fd 3>
23
* UDPSocket.new(Socket::AF_INET6) #=> #<UDPSocket:fd 4>
24
*
25
*/
26
static
VALUE
27
udp_init
(
int
argc
,
VALUE
*
argv
,
VALUE
sock)
28
{
29
VALUE
arg
;
30
int
family = AF_INET;
31
int
fd;
32
33
rb_secure
(3);
34
if
(
rb_scan_args
(argc, argv,
"01"
, &arg) == 1) {
35
family =
rsock_family_arg
(arg);
36
}
37
fd =
rsock_socket
(family, SOCK_DGRAM, 0);
38
if
(fd < 0) {
39
rb_sys_fail
(
"socket(2) - udp"
);
40
}
41
42
return
rsock_init_sock
(sock, fd);
43
}
44
45
struct
udp_arg
46
{
47
struct
addrinfo
*
res
;
48
int
fd
;
49
};
50
51
static
VALUE
52
udp_connect_internal
(
struct
udp_arg
*
arg
)
53
{
54
int
fd = arg->
fd
;
55
struct
addrinfo
*res;
56
57
for
(res = arg->
res
; res; res = res->
ai_next
) {
58
if
(
rsock_connect
(fd, res->
ai_addr
, res->
ai_addrlen
, 0) >= 0) {
59
return
Qtrue
;
60
}
61
}
62
return
Qfalse
;
63
}
64
65
VALUE
rsock_freeaddrinfo
(
struct
addrinfo
*addr);
66
67
/*
68
* call-seq:
69
* udpsocket.connect(host, port) => 0
70
*
71
* Connects _udpsocket_ to _host_:_port_.
72
*
73
* This makes possible to send without destination address.
74
*
75
* u1 = UDPSocket.new
76
* u1.bind("127.0.0.1", 4913)
77
* u2 = UDPSocket.new
78
* u2.connect("127.0.0.1", 4913)
79
* u2.send "uuuu", 0
80
* p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
81
*
82
*/
83
static
VALUE
84
udp_connect
(
VALUE
sock,
VALUE
host,
VALUE
port)
85
{
86
rb_io_t
*fptr;
87
struct
udp_arg
arg;
88
VALUE
ret;
89
90
rb_secure
(3);
91
arg.
res
=
rsock_addrinfo
(host, port, SOCK_DGRAM, 0);
92
GetOpenFile
(sock, fptr);
93
arg.
fd
= fptr->
fd
;
94
ret =
rb_ensure
(
udp_connect_internal
, (
VALUE
)&arg,
95
rsock_freeaddrinfo
, (
VALUE
)arg.res);
96
if
(!ret)
rb_sys_fail
(
"connect(2)"
);
97
return
INT2FIX
(0);
98
}
99
100
/*
101
* call-seq:
102
* udpsocket.bind(host, port) #=> 0
103
*
104
* Binds _udpsocket_ to _host_:_port_.
105
*
106
* u1 = UDPSocket.new
107
* u1.bind("127.0.0.1", 4913)
108
* u1.send "message-to-self", 0, "127.0.0.1", 4913
109
* p u1.recvfrom(10) #=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]]
110
*
111
*/
112
static
VALUE
113
udp_bind
(
VALUE
sock,
VALUE
host,
VALUE
port)
114
{
115
rb_io_t
*fptr;
116
struct
addrinfo
*res0, *res;
117
118
rb_secure
(3);
119
res0 =
rsock_addrinfo
(host, port, SOCK_DGRAM, 0);
120
GetOpenFile
(sock, fptr);
121
for
(res = res0; res; res = res->
ai_next
) {
122
if
(bind(fptr->
fd
, res->
ai_addr
, res->
ai_addrlen
) < 0) {
123
continue
;
124
}
125
freeaddrinfo
(res0);
126
return
INT2FIX
(0);
127
}
128
freeaddrinfo
(res0);
129
rb_sys_fail
(
"bind(2)"
);
130
return
INT2FIX
(0);
131
}
132
133
/*
134
* call-seq:
135
* udpsocket.send(mesg, flags, host, port) => numbytes_sent
136
* udpsocket.send(mesg, flags, sockaddr_to) => numbytes_sent
137
* udpsocket.send(mesg, flags) => numbytes_sent
138
*
139
* Sends _mesg_ via _udpsocket_.
140
*
141
* _flags_ should be a bitwise OR of Socket::MSG_* constants.
142
*
143
* u1 = UDPSocket.new
144
* u1.bind("127.0.0.1", 4913)
145
*
146
* u2 = UDPSocket.new
147
* u2.send "hi", 0, "127.0.0.1", 4913
148
*
149
* mesg, addr = u1.recvfrom(10)
150
* u1.send mesg, 0, addr[3], addr[1]
151
*
152
* p u2.recv(100) #=> "hi"
153
*
154
*/
155
static
VALUE
156
udp_send
(
int
argc
,
VALUE
*
argv
,
VALUE
sock)
157
{
158
VALUE
flags, host, port;
159
rb_io_t
*fptr;
160
int
n;
161
struct
addrinfo
*res0, *res;
162
struct
rsock_send_arg
arg;
163
164
if
(argc == 2 || argc == 3) {
165
return
rsock_bsock_send
(argc, argv, sock);
166
}
167
rb_secure
(4);
168
rb_scan_args
(argc, argv,
"4"
, &arg.
mesg
, &flags, &host, &port);
169
170
StringValue
(arg.
mesg
);
171
res0 =
rsock_addrinfo
(host, port, SOCK_DGRAM, 0);
172
GetOpenFile
(sock, fptr);
173
arg.
fd
= fptr->
fd
;
174
arg.
flags
=
NUM2INT
(flags);
175
for
(res = res0; res; res = res->
ai_next
) {
176
retry:
177
arg.
to
= res->
ai_addr
;
178
arg.
tolen
= res->
ai_addrlen
;
179
rb_thread_fd_writable
(arg.
fd
);
180
n = (int)
BLOCKING_REGION_FD
(
rsock_sendto_blocking
, &arg);
181
if
(n >= 0) {
182
freeaddrinfo
(res0);
183
return
INT2FIX
(n);
184
}
185
if
(
rb_io_wait_writable
(fptr->
fd
)) {
186
goto
retry;
187
}
188
}
189
freeaddrinfo
(res0);
190
rb_sys_fail
(
"sendto(2)"
);
191
return
INT2FIX
(n);
192
}
193
194
/*
195
* call-seq:
196
* udpsocket.recvfrom_nonblock(maxlen) => [mesg, sender_inet_addr]
197
* udpsocket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_inet_addr]
198
*
199
* Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
200
* O_NONBLOCK is set for the underlying file descriptor.
201
* If _maxlen_ is omitted, its default value is 65536.
202
* _flags_ is zero or more of the +MSG_+ options.
203
* The first element of the results, _mesg_, is the data received.
204
* The second element, _sender_inet_addr_, is an array to represent the sender address.
205
*
206
* When recvfrom(2) returns 0,
207
* Socket#recvfrom_nonblock returns an empty string as data.
208
* It means an empty packet.
209
*
210
* === Parameters
211
* * +maxlen+ - the number of bytes to receive from the socket
212
* * +flags+ - zero or more of the +MSG_+ options
213
*
214
* === Example
215
* require 'socket'
216
* s1 = UDPSocket.new
217
* s1.bind("127.0.0.1", 0)
218
* s2 = UDPSocket.new
219
* s2.bind("127.0.0.1", 0)
220
* s2.connect(*s1.addr.values_at(3,1))
221
* s1.connect(*s2.addr.values_at(3,1))
222
* s1.send "aaa", 0
223
* begin # emulate blocking recvfrom
224
* p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
225
* rescue IO::WaitReadable
226
* IO.select([s2])
227
* retry
228
* end
229
*
230
* Refer to Socket#recvfrom for the exceptions that may be thrown if the call
231
* to _recvfrom_nonblock_ fails.
232
*
233
* UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
234
* including Errno::EWOULDBLOCK.
235
*
236
* If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
237
* it is extended by IO::WaitReadable.
238
* So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
239
*
240
* === See
241
* * Socket#recvfrom
242
*/
243
static
VALUE
244
udp_recvfrom_nonblock
(
int
argc
,
VALUE
*
argv
,
VALUE
sock)
245
{
246
return
rsock_s_recvfrom_nonblock
(sock, argc, argv,
RECV_IP
);
247
}
248
249
void
250
rsock_init_udpsocket
(
void
)
251
{
252
/*
253
* Document-class: UDPSocket < IPSocket
254
*
255
* UDPSocket represents a UDP/IP socket.
256
*
257
*/
258
rb_cUDPSocket
=
rb_define_class
(
"UDPSocket"
,
rb_cIPSocket
);
259
rb_define_method
(
rb_cUDPSocket
,
"initialize"
,
udp_init
, -1);
260
rb_define_method
(
rb_cUDPSocket
,
"connect"
,
udp_connect
, 2);
261
rb_define_method
(
rb_cUDPSocket
,
"bind"
,
udp_bind
, 2);
262
rb_define_method
(
rb_cUDPSocket
,
"send"
,
udp_send
, -1);
263
rb_define_method
(
rb_cUDPSocket
,
"recvfrom_nonblock"
,
udp_recvfrom_nonblock
, -1);
264
}
265
266
Generated on Fri Nov 14 2014 16:04:03 for Ruby by
1.8.3