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