Ruby  2.1.10p492(2016-04-01revision54464)
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;
19  } remote, local;
20  int type;
21  int fd;
22 };
23 
24 static VALUE
26 {
27  if (arg->remote.res) {
29  arg->remote.res = 0;
30  }
31  if (arg->local.res) {
33  arg->local.res = 0;
34  }
35  if (arg->fd >= 0) {
36  close(arg->fd);
37  }
38  return Qnil;
39 }
40 
41 static VALUE
43 {
44  int error = 0;
45  int type = arg->type;
46  struct addrinfo *res, *lres;
47  int fd, status = 0, local = 0;
48  const char *syscall = 0;
49 
50  arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM,
51  (type == INET_SERVER) ? AI_PASSIVE : 0);
52  /*
53  * Maybe also accept a local address
54  */
55 
56  if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
57  arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0);
58  }
59 
60  arg->fd = fd = -1;
61  for (res = arg->remote.res->ai; res; res = res->ai_next) {
62 #if !defined(INET6) && defined(AF_INET6)
63  if (res->ai_family == AF_INET6)
64  continue;
65 #endif
66  lres = NULL;
67  if (arg->local.res) {
68  for (lres = arg->local.res->ai; lres; lres = lres->ai_next) {
69  if (lres->ai_family == res->ai_family)
70  break;
71  }
72  if (!lres) {
73  if (res->ai_next || status < 0)
74  continue;
75  /* Use a different family local address if no choice, this
76  * will cause EAFNOSUPPORT. */
77  lres = arg->local.res->ai;
78  }
79  }
80  status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol);
81  syscall = "socket(2)";
82  fd = status;
83  if (fd < 0) {
84  error = errno;
85  continue;
86  }
87  arg->fd = fd;
88  if (type == INET_SERVER) {
89 #if !defined(_WIN32) && !defined(__CYGWIN__)
90  status = 1;
91  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
92  (char*)&status, (socklen_t)sizeof(status));
93 #endif
94  status = bind(fd, res->ai_addr, res->ai_addrlen);
95  syscall = "bind(2)";
96  }
97  else {
98  if (lres) {
99  status = bind(fd, lres->ai_addr, lres->ai_addrlen);
100  local = status;
101  syscall = "bind(2)";
102  }
103 
104  if (status >= 0) {
105  status = rsock_connect(fd, res->ai_addr, res->ai_addrlen,
106  (type == INET_SOCKS));
107  syscall = "connect(2)";
108  }
109  }
110 
111  if (status < 0) {
112  error = errno;
113  close(fd);
114  arg->fd = fd = -1;
115  continue;
116  } else
117  break;
118  }
119  if (status < 0) {
120  VALUE host, port;
121 
122  if (local < 0) {
123  host = arg->local.host;
124  port = arg->local.serv;
125  } else {
126  host = arg->remote.host;
127  port = arg->remote.serv;
128  }
129 
130  rsock_syserr_fail_host_port(error, syscall, host, port);
131  }
132 
133  arg->fd = -1;
134 
135  if (type == INET_SERVER) {
136  status = listen(fd, SOMAXCONN);
137  if (status < 0) {
138  error = errno;
139  close(fd);
140  rb_syserr_fail(error, "listen(2)");
141  }
142  }
143 
144  /* create new instance */
145  return rsock_init_sock(arg->sock, fd);
146 }
147 
148 VALUE
149 rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
150  VALUE local_host, VALUE local_serv, int type)
151 {
152  struct inetsock_arg arg;
153  arg.sock = sock;
154  arg.remote.host = remote_host;
155  arg.remote.serv = remote_serv;
156  arg.remote.res = 0;
157  arg.local.host = local_host;
158  arg.local.serv = local_serv;
159  arg.local.res = 0;
160  arg.type = type;
161  arg.fd = -1;
162  return rb_ensure(init_inetsock_internal, (VALUE)&arg,
163  inetsock_cleanup, (VALUE)&arg);
164 }
165 
167 
168 int
169 rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
170 {
171 #define return_norevlookup(x) {*norevlookup = (x); return 1;}
172  ID id;
173 
174  switch (revlookup) {
175  case Qtrue: return_norevlookup(0);
176  case Qfalse: return_norevlookup(1);
177  case Qnil: break;
178  default:
179  Check_Type(revlookup, T_SYMBOL);
180  id = SYM2ID(revlookup);
181  if (id == id_numeric) return_norevlookup(1);
182  if (id == id_hostname) return_norevlookup(0);
183  rb_raise(rb_eArgError, "invalid reverse_lookup flag: :%s", rb_id2name(id));
184  }
185  return 0;
186 #undef return_norevlookup
187 }
188 
189 /*
190  * call-seq:
191  * ipsocket.addr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
192  *
193  * Returns the local address as an array which contains
194  * address_family, port, hostname and numeric_address.
195  *
196  * If +reverse_lookup+ is +true+ or +:hostname+,
197  * hostname is obtained from numeric_address using reverse lookup.
198  * Or if it is +false+, or +:numeric+,
199  * hostname is same as numeric_address.
200  * Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
201  * See +Socket.getaddrinfo+ also.
202  *
203  * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
204  * p sock.addr #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
205  * p sock.addr(true) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
206  * p sock.addr(false) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
207  * p sock.addr(:hostname) #=> ["AF_INET", 49429, "hal", "192.168.0.128"]
208  * p sock.addr(:numeric) #=> ["AF_INET", 49429, "192.168.0.128", "192.168.0.128"]
209  * }
210  *
211  */
212 static VALUE
214 {
215  rb_io_t *fptr;
216  union_sockaddr addr;
217  socklen_t len = (socklen_t)sizeof addr;
218  int norevlookup;
219 
220  GetOpenFile(sock, fptr);
221 
222  if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
223  norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
224  if (getsockname(fptr->fd, &addr.addr, &len) < 0)
225  rb_sys_fail("getsockname(2)");
226  return rsock_ipaddr(&addr.addr, len, norevlookup);
227 }
228 
229 /*
230  * call-seq:
231  * ipsocket.peeraddr([reverse_lookup]) => [address_family, port, hostname, numeric_address]
232  *
233  * Returns the remote address as an array which contains
234  * address_family, port, hostname and numeric_address.
235  * It is defined for connection oriented socket such as TCPSocket.
236  *
237  * If +reverse_lookup+ is +true+ or +:hostname+,
238  * hostname is obtained from numeric_address using reverse lookup.
239  * Or if it is +false+, or +:numeric+,
240  * hostname is same as numeric_address.
241  * Or if it is +nil+ or ommitted, obeys to +ipsocket.do_not_reverse_lookup+.
242  * See +Socket.getaddrinfo+ also.
243  *
244  * TCPSocket.open("www.ruby-lang.org", 80) {|sock|
245  * p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
246  * p sock.peeraddr(true) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
247  * p sock.peeraddr(false) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
248  * p sock.peeraddr(:hostname) #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
249  * p sock.peeraddr(:numeric) #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
250  * }
251  *
252  */
253 static VALUE
255 {
256  rb_io_t *fptr;
257  union_sockaddr addr;
258  socklen_t len = (socklen_t)sizeof addr;
259  int norevlookup;
260 
261  GetOpenFile(sock, fptr);
262 
263  if (argc < 1 || !rsock_revlookup_flag(argv[0], &norevlookup))
264  norevlookup = fptr->mode & FMODE_NOREVLOOKUP;
265  if (getpeername(fptr->fd, &addr.addr, &len) < 0)
266  rb_sys_fail("getpeername(2)");
267  return rsock_ipaddr(&addr.addr, len, norevlookup);
268 }
269 
270 /*
271  * call-seq:
272  * ipsocket.recvfrom(maxlen) => [mesg, ipaddr]
273  * ipsocket.recvfrom(maxlen, flags) => [mesg, ipaddr]
274  *
275  * Receives a message and return the message as a string and
276  * an address which the message come from.
277  *
278  * _maxlen_ is the maximum number of bytes to receive.
279  *
280  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
281  *
282  * ipaddr is same as IPSocket#{peeraddr,addr}.
283  *
284  * u1 = UDPSocket.new
285  * u1.bind("127.0.0.1", 4913)
286  * u2 = UDPSocket.new
287  * u2.send "uuuu", 0, "127.0.0.1", 4913
288  * p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
289  *
290  */
291 static VALUE
293 {
294  return rsock_s_recvfrom(sock, argc, argv, RECV_IP);
295 }
296 
297 /*
298  * call-seq:
299  * IPSocket.getaddress(host) => ipaddress
300  *
301  * Lookups the IP address of _host_.
302  *
303  * IPSocket.getaddress("localhost") #=> "127.0.0.1"
304  * IPSocket.getaddress("ip6-localhost") #=> "::1"
305  *
306  */
307 static VALUE
309 {
310  union_sockaddr addr;
311  struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0);
312  socklen_t len = res->ai->ai_addrlen;
313 
314  /* just take the first one */
315  memcpy(&addr, res->ai->ai_addr, len);
316  rb_freeaddrinfo(res);
317 
318  return rsock_make_ipaddr(&addr.addr, len);
319 }
320 
321 void
323 {
324  /*
325  * Document-class: IPSocket < BasicSocket
326  *
327  * IPSocket is the super class of TCPSocket and UDPSocket.
328  */
330  rb_define_method(rb_cIPSocket, "addr", ip_addr, -1);
331  rb_define_method(rb_cIPSocket, "peeraddr", ip_peeraddr, -1);
332  rb_define_method(rb_cIPSocket, "recvfrom", ip_recvfrom, -1);
334  rb_undef_method(rb_cIPSocket, "getpeereid");
335 
336  id_numeric = rb_intern_const("numeric");
337  id_hostname = rb_intern_const("hostname");
338 }
void rb_syserr_fail(int e, const char *mesg)
Definition: error.c:1964
VALUE rb_cBasicSocket
Definition: init.c:13
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1646
VALUE rsock_make_ipaddr(struct sockaddr *addr, socklen_t addrlen)
Definition: raddrinfo.c:367
Definition: io.h:61
int status
Definition: tcltklib.c:2197
VALUE serv
Definition: ipsocket.c:17
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:43
NIL_P(eventloop_thread)
Definition: tcltklib.c:4056
#define INET_SOCKS
Definition: rubysocket.h:226
VALUE rb_cIPSocket
Definition: init.c:14
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
return Qtrue
Definition: tcltklib.c:9618
#define AI_PASSIVE
Definition: addrinfo.h:96
#define FMODE_NOREVLOOKUP
Definition: rubysocket.h:229
static VALUE ip_peeraddr(int argc, VALUE *argv, VALUE sock)
Definition: ipsocket.c:254
VALUE rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
Definition: raddrinfo.c:505
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1497
#define GetOpenFile(obj, fp)
Definition: io.h:118
int mode
Definition: io.h:64
void rb_freeaddrinfo(struct rb_addrinfo *ai)
Definition: raddrinfo.c:293
struct rb_addrinfo * rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags)
Definition: raddrinfo.c:493
void rsock_syserr_fail_host_port(int err, const char *mesg, VALUE host, VALUE port)
Definition: socket.c:22
return Qfalse
Definition: tcltklib.c:6790
#define Qnil
Definition: enum.c:67
struct inetsock_arg::@115 local
static ID id_hostname
Definition: ipsocket.c:166
unsigned long ID
Definition: ripper.y:89
int rsock_socket(int domain, int type, int proto)
Definition: init.c:288
VALUE host
Definition: ipsocket.c:17
Check_Type(i, T_ARRAY)
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:611
static VALUE VALUE obj
Definition: tcltklib.c:3150
int fd
Definition: io.h:62
static VALUE inetsock_cleanup(struct inetsock_arg *arg)
Definition: ipsocket.c:25
int len
Definition: enumerator.c:1332
static VALUE init_inetsock_internal(struct inetsock_arg *arg)
Definition: ipsocket.c:42
VALUE arg
Definition: enum.c:2427
VALUE * argv
Definition: tcltklib.c:1969
memcpy(buf+1, str, len)
const int id
Definition: nkf.c:209
int errno
int socklen_t
Definition: getaddrinfo.c:84
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
Definition: init.c:114
#define INET_SERVER
Definition: rubysocket.h:225
int type
Definition: tcltklib.c:112
static VALUE ip_s_getaddress(VALUE obj, VALUE host)
Definition: ipsocket.c:308
int argc
Definition: tcltklib.c:1968
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
#define rb_intern_const(str)
static ID id_numeric
Definition: ipsocket.c:166
int ai_protocol
Definition: addrinfo.h:135
static VALUE ip_addr(int argc, VALUE *argv, VALUE sock)
Definition: ipsocket.c:213
#define T_SYMBOL
int ai_socktype
Definition: addrinfo.h:134
int rsock_revlookup_flag(VALUE revlookup, int *norevlookup)
Definition: ipsocket.c:169
#define return_norevlookup(x)
struct addrinfo * ai
Definition: rubysocket.h:282
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
Definition: init.c:389
static VALUE ip_recvfrom(int argc, VALUE *argv, VALUE sock)
Definition: ipsocket.c:292
struct addrinfo * ai_next
Definition: addrinfo.h:139
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type)
Definition: ipsocket.c:149
void rsock_init_ipsocket(void)
Definition: ipsocket.c:322
Real * res
Definition: bigdecimal.c:1251
const char * rb_id2name(ID id)
Definition: ripper.c:17271
unsigned long VALUE
Definition: ripper.y:88
size_t ai_addrlen
Definition: addrinfo.h:136
struct inetsock_arg::@115 remote
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
struct sockaddr * ai_addr
Definition: addrinfo.h:138
#define SYM2ID(x)
struct rb_addrinfo * res
Definition: ipsocket.c:18
VALUE rb_eArgError
Definition: error.c:549
VALUE sock
Definition: ipsocket.c:15
struct sockaddr addr
Definition: rubysocket.h:185
int ai_family
Definition: addrinfo.h:133