Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
ipsocket.c
Go to the documentation of this file.
1 /************************************************
2 
3  ipsocket.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 
14 {
16  struct {
18  struct rb_addrinfo *res;
20  int type;
21  int fd;
22 };
23 
24 static VALUE
25 inetsock_cleanup(VALUE v)
26 {
27  struct inetsock_arg *arg = (void *)v;
28  if (arg->remote.res) {
29  rb_freeaddrinfo(arg->remote.res);
30  arg->remote.res = 0;
31  }
32  if (arg->local.res) {
33  rb_freeaddrinfo(arg->local.res);
34  arg->local.res = 0;
35  }
36  if (arg->fd >= 0) {
37  close(arg->fd);
38  }
39  return Qnil;
40 }
41 
42 static VALUE
43 init_inetsock_internal(VALUE v)
44 {
45  struct inetsock_arg *arg = (void *)v;
46  int error = 0;
47  int type = arg->type;
48  struct addrinfo *res, *lres;
49  int fd, status = 0, local = 0;
50  int family = AF_UNSPEC;
51  const char *syscall = 0;
52 
53  arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
54  family, SOCK_STREAM,
55  (type == INET_SERVER) ? AI_PASSIVE : 0);
56  /*
57  * Maybe also accept a local address
58  */
59 
60  if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
61  arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv,
62  family, SOCK_STREAM, 0);
63  }
64 
65  arg->fd = fd = -1;
66  for (res = arg->remote.res->ai; res; res = res->ai_next) {
67 #if !defined(INET6) && defined(AF_INET6)
68  if (res->ai_family == AF_INET6)
69  continue;
70 #endif
71  lres = NULL;
72  if (arg->local.res) {
73  for (lres = arg->local.res->ai; lres; lres = lres->ai_next) {
74  if (lres->ai_family == res->ai_family)
75  break;
76  }
77  if (!lres) {
78  if (res->ai_next || status < 0)
79  continue;
80  /* Use a different family local address if no choice, this
81  * will cause EAFNOSUPPORT. */
82  lres = arg->local.res->ai;
83  }
84  }
85  status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol);
86  syscall = "socket(2)";
87  fd = status;
88  if (fd < 0) {
89  error = errno;
90  continue;
91  }
92  arg->fd = fd;
93  if (type == INET_SERVER) {
94 #if !defined(_WIN32) && !defined(__CYGWIN__)
95  status = 1;
96  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
97  (char*)&status, (socklen_t)sizeof(status));
98 #endif
99  status = bind(fd, res->ai_addr, res->ai_addrlen);
100  syscall = "bind(2)";
101  }
102  else {
103  if (lres) {
104 #if !defined(_WIN32) && !defined(__CYGWIN__)
105  status = 1;
106  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
107  (char*)&status, (socklen_t)sizeof(status));
108 #endif
109  status = bind(fd, lres->ai_addr, lres->ai_addrlen);
110  local = status;
111  syscall = "bind(2)";
112  }
113 
114  if (status >= 0) {
115  status = rsock_connect(fd, res->ai_addr, res->ai_addrlen,
116  (type == INET_SOCKS));
117  syscall = "connect(2)";
118  }
119  }
120 
121  if (status < 0) {
122  error = errno;
123  close(fd);
124  arg->fd = fd = -1;
125  continue;
126  } else
127  break;
128  }
129  if (status < 0) {
130  VALUE host, port;
131 
132  if (local < 0) {
133  host = arg->local.host;
134  port = arg->local.serv;
135  } else {
136  host = arg->remote.host;
137  port = arg->remote.serv;
138  }
139 
140  rsock_syserr_fail_host_port(error, syscall, host, port);
141  }
142 
143  arg->fd = -1;
144 
145  if (type == INET_SERVER) {
146  status = listen(fd, SOMAXCONN);
147  if (status < 0) {
148  error = errno;
149  close(fd);
150  rb_syserr_fail(error, "listen(2)");
151  }
152  }
153 
154  /* create new instance */
155  return rsock_init_sock(arg->sock, fd);
156 }
157 
158 VALUE
159 rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
160  VALUE local_host, VALUE local_serv, int type)
161 {
162  struct inetsock_arg arg;
163  arg.sock = sock;
164  arg.remote.host = remote_host;
165  arg.remote.serv = remote_serv;
166  arg.remote.res = 0;
167  arg.local.host = local_host;
168  arg.local.serv = local_serv;
169  arg.local.res = 0;
170  arg.type = type;
171  arg.fd = -1;
172  return rb_ensure(init_inetsock_internal, (VALUE)&arg,
173  inetsock_cleanup, (VALUE)&arg);
174 }
175 
176 static ID id_numeric, id_hostname;
177 
178 int
179 rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
180 {
181 #define return_norevlookup(x) {*norevlookup = (x); return 1;}
182  ID id;
183 
184  switch (revlookup) {
185  case Qtrue: return_norevlookup(0);
186  case Qfalse: return_norevlookup(1);
187  case Qnil: break;
188  default:
189  Check_Type(revlookup, T_SYMBOL);
190  id = SYM2ID(revlookup);
191  if (id == id_numeric) return_norevlookup(1);
192  if (id == id_hostname) return_norevlookup(0);
193  rb_raise(rb_eArgError, "invalid reverse_lookup flag: :%s", rb_id2name(id));
194  }
195  return 0;
196 #undef return_norevlookup
197 }
198 
199 /*
200  * call-seq:
201  * ipsocket.inspect -> string
202  *
203  * Return a string describing this IPSocket object.
204  */
205 static VALUE
206 ip_inspect(VALUE sock)
207 {
208  VALUE str = rb_call_super(0, 0);
209  rb_io_t *fptr = RFILE(sock)->fptr;
210  union_sockaddr addr;
211  socklen_t len = (socklen_t)sizeof addr;
212  ID id;
213  if (fptr && fptr->fd >= 0 &&
214  getsockname(fptr->fd, &addr.addr, &len) >= 0 &&
215  (id = rsock_intern_family(addr.addr.sa_family)) != 0) {
216  VALUE family = rb_id2str(id);
217  char hbuf[1024], pbuf[1024];
218  long slen = RSTRING_LEN(str);
219  const char last = (slen > 1 && RSTRING_PTR(str)[slen - 1] == '>') ?
220  (--slen, '>') : 0;
221  str = rb_str_subseq(str, 0, slen);
222  rb_str_cat_cstr(str, ", ");
223  rb_str_append(str, family);
224  if (!rb_getnameinfo(&addr.addr, len, hbuf, sizeof(hbuf),
225  pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
226  rb_str_cat_cstr(str, ", ");
227  rb_str_cat_cstr(str, hbuf);
228  rb_str_cat_cstr(str, ", ");
229  rb_str_cat_cstr(str, pbuf);
230  }
231  if (last) rb_str_cat(str, &last, 1);
232  }
233  return str;
234 }
235 
236 /*
237  * call-seq:
238  * ipsocket.addr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
239  *
240  * Returns the local address as an array which contains
241  * address_family, port, hostname and numeric_address.
242  *
243  * If +reverse_lookup+ is +true+ or +:hostname+,
244  * hostname is obtained from numeric_address using reverse lookup.
245  * Or if it is +false+, or +:numeric+,
246  * hostname is same as numeric_address.
247  * Or if it is +nil+ or omitted, obeys to +ipsocket.do_not_reverse_lookup+.
248  * See +Socket.getaddrinfo+ also.
249  *
250  * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
251  * p sock.addr #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
252  * p sock.addr(true) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
253  * p sock.addr(false) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
254  * p sock.addr(:hostname) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
255  * p sock.addr(:numeric) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
256  * }
257  *
258  */
259 static VALUE
260 ip_addr(int argc, VALUE *argv, VALUE sock)
261 {
262  rb_io_t *fptr;
263  union_sockaddr addr;
264  socklen_t len = (socklen_t)sizeof addr;
265  int norevlookup;
266 
267  GetOpenFile(sock, fptr);
268 
269  if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
270  norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
271  if (getsockname(fptr->fd, &addr.addr, &len) < 0)
272  rb_sys_fail("getsockname(2)");
273  return rsock_ipaddr(&addr.addr, len, norevlookup);
274 }
275 
276 /*
277  * call-seq:
278  * ipsocket.peeraddr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
279  *
280  * Returns the remote address as an array which contains
281  * address_family, port, hostname and numeric_address.
282  * It is defined for connection oriented socket such as TCPSocket.
283  *
284  * If +reverse_lookup+ is +true+ or +:hostname+,
285  * hostname is obtained from numeric_address using reverse lookup.
286  * Or if it is +false+, or +:numeric+,
287  * hostname is same as numeric_address.
288  * Or if it is +nil+ or omitted, obeys to +ipsocket.do_not_reverse_lookup+.
289  * See +Socket.getaddrinfo+ also.
290  *
291  * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
292  * p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
293  * p sock.peeraddr(true) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
294  * p sock.peeraddr(false) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
295  * p sock.peeraddr(:hostname) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
296  * p sock.peeraddr(:numeric) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
297  * }
298  *
299  */
300 static VALUE
301 ip_peeraddr(int argc, VALUE *argv, VALUE sock)
302 {
303  rb_io_t *fptr;
304  union_sockaddr addr;
305  socklen_t len = (socklen_t)sizeof addr;
306  int norevlookup;
307 
308  GetOpenFile(sock, fptr);
309 
310  if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
311  norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
312  if (getpeername(fptr->fd, &addr.addr, &len) < 0)
313  rb_sys_fail("getpeername(2)");
314  return rsock_ipaddr(&addr.addr, len, norevlookup);
315 }
316 
317 /*
318  * call-seq:
319  * ipsocket.recvfrom(maxlen) => [mesg, ipaddr]
320  * ipsocket.recvfrom(maxlen, flags) => [mesg, ipaddr]
321  *
322  * Receives a message and return the message as a string and
323  * an address which the message come from.
324  *
325  * _maxlen_ is the maximum number of bytes to receive.
326  *
327  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
328  *
329  * ipaddr is same as IPSocket#{peeraddr,addr}.
330  *
331  * u1 = UDPSocket.new
332  * u1.bind("127.0.0.1", 4913)
333  * u2 = UDPSocket.new
334  * u2.send "uuuu", 0, "127.0.0.1", 4913
335  * p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
336  *
337  */
338 static VALUE
339 ip_recvfrom(int argc, VALUE *argv, VALUE sock)
340 {
342 }
343 
344 /*
345  * call-seq:
346  * IPSocket.getaddress(host) => ipaddress
347  *
348  * Lookups the IP address of _host_.
349  *
350  * require 'socket'
351  *
352  * IPSocket.getaddress("localhost") #=> "127.0.0.1"
353  * IPSocket.getaddress("ip6-localhost") #=> "::1"
354  *
355  */
356 static VALUE
357 ip_s_getaddress(VALUE obj, VALUE host)
358 {
359  union_sockaddr addr;
360  struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0);
361  socklen_t len = res->ai->ai_addrlen;
362 
363  /* just take the first one */
364  memcpy(&addr, res->ai->ai_addr, len);
365  rb_freeaddrinfo(res);
366 
367  return rsock_make_ipaddr(&addr.addr, len);
368 }
369 
370 void
372 {
373  /*
374  * Document-class: IPSocket < BasicSocket
375  *
376  * IPSocket is the super class of TCPSocket and UDPSocket.
377  */
379  rb_define_method(rb_cIPSocket, "inspect", ip_inspect, 0);
380  rb_define_method(rb_cIPSocket, "addr", ip_addr, -1);
381  rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, -1);
382  rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1);
383  rb_define_singleton_method(rb_cIPSocket, "getaddress", ip_s_getaddress, 1);
384  rb_undef_method(rb_cIPSocket, "getpeereid");
385 
386  id_numeric = rb_intern_const("numeric");
387  id_hostname = rb_intern_const("hostname");
388 }
AF_UNSPEC
#define AF_UNSPEC
Definition: sockport.h:101
ID
unsigned long ID
Definition: ruby.h:103
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:649
rb_id2name
const char * rb_id2name(ID)
Definition: symbol.c:801
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:595
AI_PASSIVE
#define AI_PASSIVE
Definition: addrinfo.h:96
error
const rb_iseq_t const char * error
Definition: rb_mjit_min_header-2.7.2.h:13471
RFILE
#define RFILE(obj)
Definition: ruby.h:1276
id
const int id
Definition: nkf.c:209
rsock_init_sock
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:78
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
rb_str_cat_cstr
#define rb_str_cat_cstr(str, ptr)
Definition: rb_mjit_min_header-2.7.2.h:6122
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_eArgError
VALUE rb_eArgError
Definition: error.c:925
addrinfo::ai_addrlen
size_t ai_addrlen
Definition: addrinfo.h:136
rb_intern_const
#define rb_intern_const(str)
Definition: ruby.h:1879
union_sockaddr
Definition: rubysocket.h:192
rb_call_super
VALUE rb_call_super(int, const VALUE *)
Definition: vm_eval.c:306
rb_addrinfo::ai
struct addrinfo * ai
Definition: rubysocket.h:291
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1755
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
INET_SOCKS
#define INET_SOCKS
Definition: rubysocket.h:229
rb_id2str
#define rb_id2str(id)
Definition: vm_backtrace.c:30
rb_addrinfo
Definition: rubysocket.h:290
rb_io_t::fd
int fd
Definition: io.h:68
NULL
#define NULL
Definition: _sdbm.c:101
socklen_t
int socklen_t
Definition: getaddrinfo.c:83
last
unsigned int last
Definition: nkf.c:4324
T_SYMBOL
#define T_SYMBOL
Definition: ruby.h:540
rb_undef_method
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1575
rsock_socket
int rsock_socket(int domain, int type, int proto)
Definition: init.c:491
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
rb_cIPSocket
VALUE rb_cIPSocket
Definition: init.c:18
inetsock_arg::host
VALUE host
Definition: ipsocket.c:17
rsock_revlookup_flag
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
Definition: ipsocket.c:179
rsock_make_ipaddr
VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen)
Definition: raddrinfo.c:470
rsock_syserr_fail_host_port
void rsock_syserr_fail_host_port(int err, const char *mesg, VALUE host, VALUE port)
Definition: socket.c:24
SOMAXCONN
#define SOMAXCONN
Definition: constdefs.h:1849
inetsock_arg::serv
VALUE serv
Definition: ipsocket.c:17
rb_syserr_fail
void rb_syserr_fail(int e, const char *mesg)
Definition: error.c:2783
NI_NUMERICHOST
#define NI_NUMERICHOST
Definition: addrinfo.h:125
RECV_IP
@ RECV_IP
Definition: rubysocket.h:342
inetsock_arg
Definition: ipsocket.c:14
inetsock_arg::res
struct rb_addrinfo * res
Definition: ipsocket.c:18
addrinfo::ai_addr
struct sockaddr * ai_addr
Definition: addrinfo.h:138
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:2795
addrinfo::ai_family
int ai_family
Definition: addrinfo.h:133
rsock_ipaddr
VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
Definition: raddrinfo.c:665
inetsock_arg::type
int type
Definition: ipsocket.c:20
INET_SERVER
#define INET_SERVER
Definition: rubysocket.h:228
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.2.h:5597
addrinfo::ai_protocol
int ai_protocol
Definition: addrinfo.h:135
rb_getnameinfo
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
Definition: raddrinfo.c:437
NI_NUMERICSERV
#define NI_NUMERICSERV
Definition: addrinfo.h:127
rb_freeaddrinfo
void rb_freeaddrinfo(struct rb_addrinfo *ai)
Definition: raddrinfo.c:396
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
rsock_init_ipsocket
void rsock_init_ipsocket(void)
Definition: ipsocket.c:371
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.2.h:5738
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2965
inetsock_arg::sock
VALUE sock
Definition: ipsocket.c:15
FMODE_NOREVLOOKUP
#define FMODE_NOREVLOOKUP
Definition: rubysocket.h:233
argv
char ** argv
Definition: ruby.c:223
rb_io_t::mode
int mode
Definition: io.h:69
rb_str_subseq
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2474
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
rsock_s_recvfrom
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
Definition: init.c:169
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
inetsock_arg::remote
struct inetsock_arg::@0 remote
rsock_intern_family
ID rsock_intern_family(int val)
Definition: constdefs.c:6748
close
int close(int __fildes)
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
addrinfo::ai_socktype
int ai_socktype
Definition: addrinfo.h:134
argc
int argc
Definition: ruby.c:222
GetOpenFile
#define GetOpenFile(obj, fp)
Definition: io.h:127
inetsock_arg::fd
int fd
Definition: ipsocket.c:21
Qtrue
#define Qtrue
Definition: ruby.h:468
errno
int errno
v
int VALUE v
Definition: rb_mjit_min_header-2.7.2.h:12300
len
uint8_t len
Definition: escape.c:17
inetsock_arg::local
struct inetsock_arg::@0 local
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
Qnil
#define Qnil
Definition: ruby.h:469
rb_cBasicSocket
VALUE rb_cBasicSocket
Definition: init.c:17
rb_io_t
Definition: io.h:66
union_sockaddr::addr
struct sockaddr addr
Definition: rubysocket.h:193
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005
return_norevlookup
#define return_norevlookup(x)
addrinfo
Definition: addrinfo.h:131
rsock_init_inetsock
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type)
Definition: ipsocket.c:159
rb_str_cat
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2812
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
SYM2ID
#define SYM2ID(x)
Definition: ruby.h:415