Ruby  3.1.0dev(2021-09-10revisionb76ad15ed0da636161de0243c547ee1e6fc95681)
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, NULL) >= 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,
95  rsock_freeaddrinfo, (VALUE)arg.res);
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,
140  rsock_freeaddrinfo, (VALUE)arg.res);
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  struct addrinfo *res;
157 
158  rb_io_check_closed(fptr = arg->fptr);
159  for (res = arg->res->ai; res; res = res->ai_next) {
160  retry:
161  arg->sarg.fd = fptr->fd;
162  arg->sarg.to = res->ai_addr;
163  arg->sarg.tolen = res->ai_addrlen;
164 
165 #ifdef RSOCK_WAIT_BEFORE_BLOCKING
167 #endif
168 
169  ssize_t n = (ssize_t)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg->sarg);
170 
171  if (n >= 0) return RB_SSIZE2NUM(n);
172 
173  if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
174  goto retry;
175  }
176  }
177  return Qfalse;
178 }
179 
180 /*
181  * call-seq:
182  * udpsocket.send(mesg, flags, host, port) => numbytes_sent
183  * udpsocket.send(mesg, flags, sockaddr_to) => numbytes_sent
184  * udpsocket.send(mesg, flags) => numbytes_sent
185  *
186  * Sends _mesg_ via _udpsocket_.
187  *
188  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
189  *
190  * u1 = UDPSocket.new
191  * u1.bind("127.0.0.1", 4913)
192  *
193  * u2 = UDPSocket.new
194  * u2.send "hi", 0, "127.0.0.1", 4913
195  *
196  * mesg, addr = u1.recvfrom(10)
197  * u1.send mesg, 0, addr[3], addr[1]
198  *
199  * p u2.recv(100) #=> "hi"
200  *
201  */
202 static VALUE
203 udp_send(int argc, VALUE *argv, VALUE sock)
204 {
205  VALUE flags, host, port;
206  struct udp_send_arg arg;
207  VALUE ret;
208 
209  if (argc == 2 || argc == 3) {
210  return rsock_bsock_send(argc, argv, sock);
211  }
212  rb_scan_args(argc, argv, "4", &arg.sarg.mesg, &flags, &host, &port);
213 
214  StringValue(arg.sarg.mesg);
215  GetOpenFile(sock, arg.fptr);
216  arg.sarg.fd = arg.fptr->fd;
217  arg.sarg.flags = NUM2INT(flags);
218  arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
219  ret = rb_ensure(udp_send_internal, (VALUE)&arg,
220  rsock_freeaddrinfo, (VALUE)arg.res);
221  if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
222  return ret;
223 }
224 
225 /* :nodoc: */
226 static VALUE
227 udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
228 {
229  return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
230 }
231 
232 void
234 {
235  /*
236  * Document-class: UDPSocket < IPSocket
237  *
238  * UDPSocket represents a UDP/IP socket.
239  *
240  */
242  rb_define_method(rb_cUDPSocket, "initialize", udp_init, -1);
243  rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
244  rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
245  rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
246 
247  /* for ext/socket/lib/socket.rb use only: */
249  "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
250 }
rsock_send_arg::tolen
socklen_t tolen
Definition: rubysocket.h:356
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:759
rsock_bsock_send
VALUE rsock_bsock_send(int argc, VALUE *argv, VALUE socket)
Definition: basicsocket.c:566
udp_send_arg::fptr
rb_io_t * fptr
Definition: udpsocket.c:147
udp_send_arg::res
struct rb_addrinfo * res
Definition: udpsocket.c:146
StringValue
#define StringValue(v)
Definition: rstring.h:50
rsock_send_arg::mesg
VALUE mesg
Definition: rubysocket.h:354
udp_send_arg
Definition: udpsocket.c:145
rsock_connect
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout)
Definition: init.c:552
rsock_send_arg::fd
int fd
Definition: rubysocket.h:353
rb_cUDPSocket
VALUE rb_cUDPSocket
Definition: init.c:21
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:224
rsock_send_arg::to
struct sockaddr * to
Definition: rubysocket.h:355
addrinfo::ai_addrlen
size_t ai_addrlen
Definition: addrinfo.h:136
rsock_socket
int rsock_socket(int domain, int type, int proto)
Definition: init.c:430
INT2FIX
#define INT2FIX
Definition: long.h:48
GetOpenFile
#define GetOpenFile
Definition: io.h:125
udp_arg::res
struct rb_addrinfo * res
Definition: udpsocket.c:48
RB_SSIZE2NUM
#define RB_SSIZE2NUM
Definition: size_t.h:31
argv
char ** argv
Definition: ruby.c:243
rb_addrinfo::ai
struct addrinfo * ai
Definition: rubysocket.h:314
NUM2INT
#define NUM2INT
Definition: int.h:44
rb_addrinfo
Definition: rubysocket.h:313
rb_io_t::fd
int fd
Definition: io.h:65
rsock_init_udpsocket
void rsock_init_udpsocket(void)
Definition: udpsocket.c:233
udp_arg
Definition: udpsocket.c:46
rsock_init_sock
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:64
RECV_IP
@ RECV_IP
Definition: rubysocket.h:365
rsock_freeaddrinfo
VALUE rsock_freeaddrinfo(VALUE arg)
Definition: raddrinfo.c:751
Qfalse
#define Qfalse
Definition: special_consts.h:50
len
uint8_t len
Definition: escape.c:17
BLOCKING_REGION_FD
#define BLOCKING_REGION_FD(func, arg)
Definition: rubysocket.h:291
addrinfo::ai_addr
struct sockaddr * ai_addr
Definition: addrinfo.h:138
rsock_send_arg
Definition: rubysocket.h:352
Qnil
#define Qnil
Definition: special_consts.h:51
RUBY_IO_WRITABLE
@ RUBY_IO_WRITABLE
Definition: io.h:46
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:3146
rb_define_private_method
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
Definition: cxxanyargs.hpp:662
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
NULL
#define NULL
Definition: regenc.h:69
udp_arg::fptr
rb_io_t * fptr
Definition: udpsocket.c:49
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2347
rb_io_maybe_wait_writable
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Definition: io.c:1468
rb_io_check_closed
void rb_io_check_closed(rb_io_t *)
Definition: io.c:778
Qtrue
#define Qtrue
Definition: special_consts.h:52
addrinfo::ai_next
struct addrinfo * ai_next
Definition: addrinfo.h:139
VALUE
unsigned long VALUE
Definition: value.h:38
rsock_send_arg::flags
int flags
Definition: rubysocket.h:353
rb_cIPSocket
VALUE rb_cIPSocket
Definition: init.c:18
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
ret
return ret
Definition: memory.h:232
RB_INT2NUM
#define RB_INT2NUM
Definition: int.h:37
rsock_sendto_blocking
VALUE rsock_sendto_blocking(void *data)
Definition: init.c:82
argc
int argc
Definition: ruby.c:242
rsock_fd_family
int rsock_fd_family(int fd)
Definition: raddrinfo.c:583
rsock_addrinfo
struct rb_addrinfo * rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
Definition: raddrinfo.c:596
rubysocket.h
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:655
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:1144
rsock_family_arg
int rsock_family_arg(VALUE domain)
Definition: constants.c:42
rb_io_t
Definition: io.h:61
addrinfo
Definition: addrinfo.h:131
rb_io_wait
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Definition: io.c:1272
rb_io_t::self
VALUE self
Definition: io.h:62