Ruby: ext/socket/udpsocket.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

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 */
28static VALUE
29udp_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;
49 rb_io_t *fptr;
50};
51
52static VALUE
53udp_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 */
86static VALUE
87udp_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
100static VALUE
101udp_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 */
131static VALUE
132udp_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;
147 rb_io_t *fptr;
148 struct rsock_send_arg sarg;
149};
150
151static VALUE
152udp_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);
166 n = (int)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg->sarg);
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 */
199static VALUE
200udp_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,
217 rsock_freeaddrinfo, (VALUE)arg.res);
218 if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
219 return ret;
220}
221
222/* :nodoc: */
223static VALUE
224udp_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
229void
230 rsock_init_udpsocket(void)
231{
232 /*
233 * Document-class: UDPSocket < IPSocket
234 *
235 * UDPSocket represents a UDP/IP socket.
236 *
237 */
238 rb_cUDPSocket = rb_define_class("UDPSocket", rb_cIPSocket);
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: */
245 rb_define_private_method(rb_cUDPSocket,
246 "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
247}
rsock_bsock_send
VALUE rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
Definition: basicsocket.c:540
rsock_family_arg
int rsock_family_arg(VALUE domain)
Definition: constants.c:42
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
rb_define_private_method
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
Definition: cxxanyargs.hpp:660
len
uint8_t len
Definition: escape.c:17
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:748
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
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:1148
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:3041
GetOpenFile
#define GetOpenFile
Definition: io.h:125
rb_io_check_closed
void rb_io_check_closed(rb_io_t *)
Definition: io.c:775
rb_io_wait_writable
int rb_io_wait_writable(int fd)
Definition: io.c:1341
rsock_sendto_blocking
VALUE rsock_sendto_blocking(void *data)
Definition: init.c:100
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
rb_cIPSocket
VALUE rb_cIPSocket
Definition: init.c:18
rsock_socket
int rsock_socket(int domain, int type, int proto)
Definition: init.c:437
rb_cUDPSocket
VALUE rb_cUDPSocket
Definition: init.c:21
rsock_init_sock
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:78
rsock_connect
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout)
Definition: init.c:559
NUM2INT
#define NUM2INT
Definition: int.h:44
int
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
INT2FIX
#define INT2FIX
Definition: long.h:48
rsock_freeaddrinfo
VALUE rsock_freeaddrinfo(VALUE arg)
Definition: raddrinfo.c:698
rsock_addrinfo
struct rb_addrinfo * rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
Definition: raddrinfo.c:543
rsock_fd_family
int rsock_fd_family(int fd)
Definition: raddrinfo.c:530
NULL
#define NULL
Definition: regenc.h:69
StringValue
#define StringValue(v)
Definition: rstring.h:50
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
rubysocket.h
rsock_sys_fail_host_port
void rsock_sys_fail_host_port(const char *, VALUE, VALUE)
Definition: socket.c:18
rsock_maybe_fd_writable
#define rsock_maybe_fd_writable(fd)
Definition: rubysocket.h:450
RECV_IP
@ RECV_IP
Definition: rubysocket.h:365
BLOCKING_REGION_FD
#define BLOCKING_REGION_FD(func, arg)
Definition: rubysocket.h:290
Qtrue
#define Qtrue
Definition: special_consts.h:52
Qfalse
#define Qfalse
Definition: special_consts.h:50
addrinfo
Definition: addrinfo.h:131
addrinfo::ai_addrlen
size_t ai_addrlen
Definition: addrinfo.h:136
addrinfo::ai_addr
struct sockaddr * ai_addr
Definition: addrinfo.h:138
addrinfo::ai_next
struct addrinfo * ai_next
Definition: addrinfo.h:139
rb_addrinfo
Definition: rubysocket.h:312
rb_addrinfo::ai
struct addrinfo * ai
Definition: rubysocket.h:313
rb_io_t
Definition: io.h:61
rb_io_t::fd
int fd
Definition: io.h:65
rsock_send_arg
Definition: rubysocket.h:352
rsock_send_arg::tolen
socklen_t tolen
Definition: rubysocket.h:356
rsock_send_arg::flags
int flags
Definition: rubysocket.h:353
rsock_send_arg::fd
int fd
Definition: rubysocket.h:353
rsock_send_arg::mesg
VALUE mesg
Definition: rubysocket.h:354
rsock_send_arg::to
struct sockaddr * to
Definition: rubysocket.h:355
udp_arg
Definition: udpsocket.c:47
udp_arg::res
struct rb_addrinfo * res
Definition: udpsocket.c:48
udp_arg::fptr
rb_io_t * fptr
Definition: udpsocket.c:49
udp_send_arg
Definition: udpsocket.c:145
udp_send_arg::fptr
rb_io_t * fptr
Definition: udpsocket.c:147
udp_send_arg::sarg
struct rsock_send_arg sarg
Definition: udpsocket.c:148
udp_send_arg::res
struct rb_addrinfo * res
Definition: udpsocket.c:146
rsock_init_udpsocket
void rsock_init_udpsocket(void)
Definition: udpsocket.c:230
VALUE
unsigned long VALUE
Definition: value.h:38