Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
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(VALUE v)
54 {
55  struct udp_arg *arg = (void *)v;
56  rb_io_t *fptr;
57  int fd;
58  struct addrinfo *res;
59 
60  rb_io_check_closed(fptr = arg->fptr);
61  fd = fptr->fd;
62  for (res = arg->res->ai; res; res = res->ai_next) {
63  if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
64  return Qtrue;
65  }
66  }
67  return Qfalse;
68 }
69 
70 /*
71  * call-seq:
72  * udpsocket.connect(host, port) => 0
73  *
74  * Connects _udpsocket_ to _host_:_port_.
75  *
76  * This makes possible to send without destination address.
77  *
78  * u1 = UDPSocket.new
79  * u1.bind("127.0.0.1", 4913)
80  * u2 = UDPSocket.new
81  * u2.connect("127.0.0.1", 4913)
82  * u2.send "uuuu", 0
83  * p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
84  *
85  */
86 static VALUE
87 udp_connect(VALUE sock, VALUE host, VALUE port)
88 {
89  struct udp_arg arg;
90  VALUE ret;
91 
92  GetOpenFile(sock, arg.fptr);
93  arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
94  ret = rb_ensure(udp_connect_internal, (VALUE)&arg,
96  if (!ret) rsock_sys_fail_host_port("connect(2)", host, port);
97  return INT2FIX(0);
98 }
99 
100 static VALUE
101 udp_bind_internal(VALUE v)
102 {
103  struct udp_arg *arg = (void *)v;
104  rb_io_t *fptr;
105  int fd;
106  struct addrinfo *res;
107 
108  rb_io_check_closed(fptr = arg->fptr);
109  fd = fptr->fd;
110  for (res = arg->res->ai; res; res = res->ai_next) {
111  if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
112  continue;
113  }
114  return Qtrue;
115  }
116  return Qfalse;
117 }
118 
119 /*
120  * call-seq:
121  * udpsocket.bind(host, port) #=> 0
122  *
123  * Binds _udpsocket_ to _host_:_port_.
124  *
125  * u1 = UDPSocket.new
126  * u1.bind("127.0.0.1", 4913)
127  * u1.send "message-to-self", 0, "127.0.0.1", 4913
128  * p u1.recvfrom(10) #=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]]
129  *
130  */
131 static VALUE
132 udp_bind(VALUE sock, VALUE host, VALUE port)
133 {
134  struct udp_arg arg;
135  VALUE ret;
136 
137  GetOpenFile(sock, arg.fptr);
138  arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
139  ret = rb_ensure(udp_bind_internal, (VALUE)&arg,
141  if (!ret) rsock_sys_fail_host_port("bind(2)", host, port);
142  return INT2FIX(0);
143 }
144 
145 struct udp_send_arg {
146  struct rb_addrinfo *res;
149 };
150 
151 static VALUE
152 udp_send_internal(VALUE v)
153 {
154  struct udp_send_arg *arg = (void *)v;
155  rb_io_t *fptr;
156  int n;
157  struct addrinfo *res;
158 
159  rb_io_check_closed(fptr = arg->fptr);
160  for (res = arg->res->ai; res; res = res->ai_next) {
161  retry:
162  arg->sarg.fd = fptr->fd;
163  arg->sarg.to = res->ai_addr;
164  arg->sarg.tolen = res->ai_addrlen;
165  rsock_maybe_fd_writable(arg->sarg.fd);
167  if (n >= 0) {
168  return INT2FIX(n);
169  }
170  if (rb_io_wait_writable(fptr->fd)) {
171  goto retry;
172  }
173  }
174  return Qfalse;
175 }
176 
177 /*
178  * call-seq:
179  * udpsocket.send(mesg, flags, host, port) => numbytes_sent
180  * udpsocket.send(mesg, flags, sockaddr_to) => numbytes_sent
181  * udpsocket.send(mesg, flags) => numbytes_sent
182  *
183  * Sends _mesg_ via _udpsocket_.
184  *
185  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
186  *
187  * u1 = UDPSocket.new
188  * u1.bind("127.0.0.1", 4913)
189  *
190  * u2 = UDPSocket.new
191  * u2.send "hi", 0, "127.0.0.1", 4913
192  *
193  * mesg, addr = u1.recvfrom(10)
194  * u1.send mesg, 0, addr[3], addr[1]
195  *
196  * p u2.recv(100) #=> "hi"
197  *
198  */
199 static VALUE
200 udp_send(int argc, VALUE *argv, VALUE sock)
201 {
202  VALUE flags, host, port;
203  struct udp_send_arg arg;
204  VALUE ret;
205 
206  if (argc == 2 || argc == 3) {
207  return rsock_bsock_send(argc, argv, sock);
208  }
209  rb_scan_args(argc, argv, "4", &arg.sarg.mesg, &flags, &host, &port);
210 
211  StringValue(arg.sarg.mesg);
212  GetOpenFile(sock, arg.fptr);
213  arg.sarg.fd = arg.fptr->fd;
214  arg.sarg.flags = NUM2INT(flags);
215  arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
216  ret = rb_ensure(udp_send_internal, (VALUE)&arg,
218  if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
219  return ret;
220 }
221 
222 /* :nodoc: */
223 static VALUE
224 udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
225 {
226  return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
227 }
228 
229 void
231 {
232  /*
233  * Document-class: UDPSocket < IPSocket
234  *
235  * UDPSocket represents a UDP/IP socket.
236  *
237  */
239  rb_define_method(rb_cUDPSocket, "initialize", udp_init, -1);
240  rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
241  rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
242  rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
243 
244  /* for ext/socket/lib/socket.rb use only: */
246  "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
247 }
rsock_maybe_fd_writable
#define rsock_maybe_fd_writable(fd)
Definition: rubysocket.h:427
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:649
udp_send_arg::fptr
rb_io_t * fptr
Definition: udpsocket.c:147
udp_send_arg::res
struct rb_addrinfo * res
Definition: udpsocket.c:146
udp_send_arg
Definition: udpsocket.c:145
rsock_init_sock
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:78
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:263
n
const char size_t n
Definition: rb_mjit_min_header-2.7.1.h:5456
rsock_s_recvfrom_nonblock
VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex, enum sock_recv_type from)
Definition: init.c:231
VALUE
unsigned long VALUE
Definition: ruby.h:102
addrinfo::ai_addrlen
size_t ai_addrlen
Definition: addrinfo.h:136
udp_arg::res
struct rb_addrinfo * res
Definition: udpsocket.c:48
rb_io_check_closed
void rb_io_check_closed(rb_io_t *)
Definition: io.c:718
rsock_sendto_blocking
VALUE rsock_sendto_blocking(void *data)
Definition: init.c:100
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.1.h:5601
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
Qfalse
#define Qfalse
Definition: ruby.h:467
rb_addrinfo
Definition: rubysocket.h:290
rb_io_t::fd
int fd
Definition: io.h:68
rsock_init_udpsocket
void rsock_init_udpsocket(void)
Definition: udpsocket.c:230
rsock_socket
int rsock_socket(int domain, int type, int proto)
Definition: init.c:491
rb_cIPSocket
VALUE rb_cIPSocket
Definition: init.c:18
udp_arg
Definition: udpsocket.c:46
RECV_IP
@ RECV_IP
Definition: rubysocket.h:342
rsock_freeaddrinfo
VALUE rsock_freeaddrinfo(VALUE arg)
Definition: raddrinfo.c:808
BLOCKING_REGION_FD
#define BLOCKING_REGION_FD(func, arg)
Definition: rubysocket.h:268
addrinfo::ai_addr
struct sockaddr * ai_addr
Definition: addrinfo.h:138
rsock_send_arg
Definition: rubysocket.h:329
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:2793
udp_send_arg::sarg
struct rsock_send_arg sarg
Definition: udpsocket.c:148
rsock_sys_fail_host_port
void rsock_sys_fail_host_port(const char *mesg, VALUE host, VALUE port)
Definition: socket.c:18
udp_arg::fptr
rb_io_t * fptr
Definition: udpsocket.c:49
rsock_connect
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
Definition: init.c:607
addrinfo::ai_next
struct addrinfo * ai_next
Definition: addrinfo.h:139
rb_scan_args
#define rb_scan_args(argc, argvp, fmt,...)
Definition: rb_mjit_min_header-2.7.1.h:6372
StringValue
use StringValue() instead")))
argv
char ** argv
Definition: ruby.c:223
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
int
__inline__ int
Definition: rb_mjit_min_header-2.7.1.h:2839
argc
int argc
Definition: ruby.c:222
rsock_fd_family
int rsock_fd_family(int fd)
Definition: raddrinfo.c:640
GetOpenFile
#define GetOpenFile(obj, fp)
Definition: io.h:127
v
int VALUE v
Definition: rb_mjit_min_header-2.7.1.h:12337
rb_cUDPSocket
VALUE rb_cUDPSocket
Definition: init.c:21
rsock_bsock_send
VALUE rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
Definition: basicsocket.c:540
Qtrue
#define Qtrue
Definition: ruby.h:468
len
uint8_t len
Definition: escape.c:17
rsock_addrinfo
struct rb_addrinfo * rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
Definition: raddrinfo.c:653
rubysocket.h
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1115
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
rsock_family_arg
int rsock_family_arg(VALUE domain)
Definition: constants.c:42
rb_io_t
Definition: io.h:66
addrinfo
Definition: addrinfo.h:131
rb_define_private_method
void rb_define_private_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1569
rb_io_wait_writable
int rb_io_wait_writable(int)
Definition: io.c:1228