Ruby  2.5.0dev(2017-10-22revision60238)
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  * require 'socket'
23  *
24  * UDPSocket.new #=> #<UDPSocket:fd 3>
25  * UDPSocket.new(Socket::AF_INET6) #=> #<UDPSocket:fd 4>
26  *
27  */
28 static VALUE
29 udp_init(int argc, VALUE *argv, VALUE sock)
30 {
31  VALUE arg;
32  int family = AF_INET;
33  int fd;
34 
35  if (rb_scan_args(argc, argv, "01", &arg) == 1) {
36  family = rsock_family_arg(arg);
37  }
38  fd = rsock_socket(family, SOCK_DGRAM, 0);
39  if (fd < 0) {
40  rb_sys_fail("socket(2) - udp");
41  }
42 
43  return rsock_init_sock(sock, fd);
44 }
45 
46 struct udp_arg
47 {
48  struct rb_addrinfo *res;
50 };
51 
52 static VALUE
53 udp_connect_internal(struct udp_arg *arg)
54 {
55  rb_io_t *fptr;
56  int fd;
57  struct addrinfo *res;
58 
59  rb_io_check_closed(fptr = arg->fptr);
60  fd = fptr->fd;
61  for (res = arg->res->ai; res; res = res->ai_next) {
62  if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
63  return Qtrue;
64  }
65  }
66  return Qfalse;
67 }
68 
69 /*
70  * call-seq:
71  * udpsocket.connect(host, port) => 0
72  *
73  * Connects _udpsocket_ to _host_:_port_.
74  *
75  * This makes possible to send without destination address.
76  *
77  * u1 = UDPSocket.new
78  * u1.bind("127.0.0.1", 4913)
79  * u2 = UDPSocket.new
80  * u2.connect("127.0.0.1", 4913)
81  * u2.send "uuuu", 0
82  * p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
83  *
84  */
85 static VALUE
86 udp_connect(VALUE sock, VALUE host, VALUE port)
87 {
88  struct udp_arg arg;
89  VALUE ret;
90 
91  GetOpenFile(sock, arg.fptr);
92  arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
93  ret = rb_ensure(udp_connect_internal, (VALUE)&arg,
94  rsock_freeaddrinfo, (VALUE)arg.res);
95  if (!ret) rsock_sys_fail_host_port("connect(2)", host, port);
96  return INT2FIX(0);
97 }
98 
99 static VALUE
100 udp_bind_internal(struct udp_arg *arg)
101 {
102  rb_io_t *fptr;
103  int fd;
104  struct addrinfo *res;
105 
106  rb_io_check_closed(fptr = arg->fptr);
107  fd = fptr->fd;
108  for (res = arg->res->ai; res; res = res->ai_next) {
109  if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
110  continue;
111  }
112  return Qtrue;
113  }
114  return Qfalse;
115 }
116 
117 /*
118  * call-seq:
119  * udpsocket.bind(host, port) #=> 0
120  *
121  * Binds _udpsocket_ to _host_:_port_.
122  *
123  * u1 = UDPSocket.new
124  * u1.bind("127.0.0.1", 4913)
125  * u1.send "message-to-self", 0, "127.0.0.1", 4913
126  * p u1.recvfrom(10) #=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]]
127  *
128  */
129 static VALUE
130 udp_bind(VALUE sock, VALUE host, VALUE port)
131 {
132  struct udp_arg arg;
133  VALUE ret;
134 
135  GetOpenFile(sock, arg.fptr);
136  arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
137  ret = rb_ensure(udp_bind_internal, (VALUE)&arg,
138  rsock_freeaddrinfo, (VALUE)arg.res);
139  if (!ret) rsock_sys_fail_host_port("bind(2)", host, port);
140  return INT2FIX(0);
141 }
142 
143 struct udp_send_arg {
144  struct rb_addrinfo *res;
146  struct rsock_send_arg sarg;
147 };
148 
149 static VALUE
150 udp_send_internal(struct udp_send_arg *arg)
151 {
152  rb_io_t *fptr;
153  int n;
154  struct addrinfo *res;
155 
156  rb_io_check_closed(fptr = arg->fptr);
157  for (res = arg->res->ai; res; res = res->ai_next) {
158  retry:
159  arg->sarg.fd = fptr->fd;
160  arg->sarg.to = res->ai_addr;
161  arg->sarg.tolen = res->ai_addrlen;
164  if (n >= 0) {
165  return INT2FIX(n);
166  }
167  if (rb_io_wait_writable(fptr->fd)) {
168  goto retry;
169  }
170  }
171  return Qfalse;
172 }
173 
174 /*
175  * call-seq:
176  * udpsocket.send(mesg, flags, host, port) => numbytes_sent
177  * udpsocket.send(mesg, flags, sockaddr_to) => numbytes_sent
178  * udpsocket.send(mesg, flags) => numbytes_sent
179  *
180  * Sends _mesg_ via _udpsocket_.
181  *
182  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
183  *
184  * u1 = UDPSocket.new
185  * u1.bind("127.0.0.1", 4913)
186  *
187  * u2 = UDPSocket.new
188  * u2.send "hi", 0, "127.0.0.1", 4913
189  *
190  * mesg, addr = u1.recvfrom(10)
191  * u1.send mesg, 0, addr[3], addr[1]
192  *
193  * p u2.recv(100) #=> "hi"
194  *
195  */
196 static VALUE
197 udp_send(int argc, VALUE *argv, VALUE sock)
198 {
199  VALUE flags, host, port;
200  struct udp_send_arg arg;
201  VALUE ret;
202 
203  if (argc == 2 || argc == 3) {
204  return rsock_bsock_send(argc, argv, sock);
205  }
206  rb_scan_args(argc, argv, "4", &arg.sarg.mesg, &flags, &host, &port);
207 
208  StringValue(arg.sarg.mesg);
209  GetOpenFile(sock, arg.fptr);
210  arg.sarg.fd = arg.fptr->fd;
211  arg.sarg.flags = NUM2INT(flags);
212  arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
213  ret = rb_ensure(udp_send_internal, (VALUE)&arg,
214  rsock_freeaddrinfo, (VALUE)arg.res);
215  if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
216  return ret;
217 }
218 
219 /* :nodoc: */
220 static VALUE
221 udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
222 {
223  return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
224 }
225 
226 void
228 {
229  /*
230  * Document-class: UDPSocket < IPSocket
231  *
232  * UDPSocket represents a UDP/IP socket.
233  *
234  */
236  rb_define_method(rb_cUDPSocket, "initialize", udp_init, -1);
237  rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
238  rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
239  rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
240 
241  /* for ext/socket/lib/socket.rb use only: */
243  "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
244 }
struct rsock_send_arg sarg
Definition: udpsocket.c:146
void rsock_init_udpsocket(void)
Definition: udpsocket.c:227
socklen_t tolen
Definition: rubysocket.h:327
VALUE rsock_sendto_blocking(void *data)
Definition: init.c:82
#define NUM2INT(x)
Definition: ruby.h:684
struct rb_addrinfo * res
Definition: udpsocket.c:48
#define Qtrue
Definition: ruby.h:437
Definition: io.h:62
void rb_define_private_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1527
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:60
#define rsock_maybe_fd_writable(fd)
Definition: rubysocket.h:421
VALUE rb_cIPSocket
Definition: init.c:14
struct sockaddr * to
Definition: rubysocket.h:326
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1035
VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex, enum sock_recv_type from)
Definition: init.c:209
#define GetOpenFile(obj, fp)
Definition: io.h:120
rb_io_t * fptr
Definition: udpsocket.c:145
VALUE rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
Definition: basicsocket.c:528
struct rb_addrinfo * rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
Definition: raddrinfo.c:547
int rsock_family_arg(VALUE domain)
Definition: constants.c:43
int rsock_socket(int domain, int type, int proto)
Definition: init.c:357
rb_io_t * fptr
Definition: udpsocket.c:49
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:646
int fd
Definition: io.h:64
int rb_io_wait_writable(int)
Definition: io.c:1132
int argc
Definition: ruby.c:187
#define Qfalse
Definition: ruby.h:436
VALUE rsock_freeaddrinfo(VALUE arg)
Definition: raddrinfo.c:696
void rb_sys_fail(const char *mesg)
Definition: error.c:2403
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1908
struct rb_addrinfo * res
Definition: udpsocket.c:144
void rsock_sys_fail_host_port(const char *mesg, VALUE host, VALUE port)
Definition: socket.c:18
unsigned long VALUE
Definition: ruby.h:85
register unsigned int len
Definition: zonetab.h:51
int rsock_fd_family(int fd)
Definition: raddrinfo.c:534
#define INT2FIX(i)
Definition: ruby.h:232
struct addrinfo * ai
Definition: rubysocket.h:285
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
Definition: init.c:454
struct addrinfo * ai_next
Definition: addrinfo.h:139
size_t ai_addrlen
Definition: addrinfo.h:136
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
void rb_io_check_closed(rb_io_t *)
Definition: io.c:641
struct sockaddr * ai_addr
Definition: addrinfo.h:138
#define BLOCKING_REGION_FD(func, arg)
Definition: rubysocket.h:262
char ** argv
Definition: ruby.c:188
#define StringValue(v)
Definition: ruby.h:569
VALUE rb_cUDPSocket
Definition: init.c:17