Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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