1/************************************************
2
3  basicsocket.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 *   BasicSocket.for_fd(fd) => basicsocket
16 *
17 * Returns a socket object which contains the file descriptor, _fd_.
18 *
19 *   # If invoked by inetd, STDIN/STDOUT/STDERR is a socket.
20 *   STDIN_SOCK = Socket.for_fd(STDIN.fileno)
21 *   p STDIN_SOCK.remote_address
22 *
23 */
24static VALUE
25bsock_s_for_fd(VALUE klass, VALUE fd)
26{
27    rb_io_t *fptr;
28    VALUE sock = rsock_init_sock(rb_obj_alloc(klass), NUM2INT(fd));
29
30    GetOpenFile(sock, fptr);
31
32    return sock;
33}
34
35/*
36 * call-seq:
37 *   basicsocket.shutdown([how]) => 0
38 *
39 * Calls shutdown(2) system call.
40 *
41 * s.shutdown(Socket::SHUT_RD) disallows further read.
42 *
43 * s.shutdown(Socket::SHUT_WR) disallows further write.
44 *
45 * s.shutdown(Socket::SHUT_RDWR) disallows further read and write.
46 *
47 * _how_ can be symbol or string:
48 * - :RD, :SHUT_RD, "RD" and "SHUT_RD" are accepted as Socket::SHUT_RD.
49 * - :WR, :SHUT_WR, "WR" and "SHUT_WR" are accepted as Socket::SHUT_WR.
50 * - :RDWR, :SHUT_RDWR, "RDWR" and "SHUT_RDWR" are accepted as Socket::SHUT_RDWR.
51 *
52 *   UNIXSocket.pair {|s1, s2|
53 *     s1.puts "ping"
54 *     s1.shutdown(:WR)
55 *     p s2.read          #=> "ping\n"
56 *     s2.puts "pong"
57 *     s2.close
58 *     p s1.read          #=> "pong\n"
59 *   }
60 *
61 */
62static VALUE
63bsock_shutdown(int argc, VALUE *argv, VALUE sock)
64{
65    VALUE howto;
66    int how;
67    rb_io_t *fptr;
68
69    if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
70	rb_raise(rb_eSecurityError, "Insecure: can't shutdown socket");
71    }
72    rb_scan_args(argc, argv, "01", &howto);
73    if (howto == Qnil)
74	how = SHUT_RDWR;
75    else {
76	how = rsock_shutdown_how_arg(howto);
77        if (how != SHUT_WR && how != SHUT_RD && how != SHUT_RDWR) {
78	    rb_raise(rb_eArgError, "`how' should be either :SHUT_RD, :SHUT_WR, :SHUT_RDWR");
79	}
80    }
81    GetOpenFile(sock, fptr);
82    if (shutdown(fptr->fd, how) == -1)
83	rb_sys_fail(0);
84
85    return INT2FIX(0);
86}
87
88/*
89 * call-seq:
90 *   basicsocket.close_read => nil
91 *
92 * Disallows further read using shutdown system call.
93 *
94 *   s1, s2 = UNIXSocket.pair
95 *   s1.close_read
96 *   s2.puts #=> Broken pipe (Errno::EPIPE)
97 */
98static VALUE
99bsock_close_read(VALUE sock)
100{
101    rb_io_t *fptr;
102
103    if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
104	rb_raise(rb_eSecurityError, "Insecure: can't close socket");
105    }
106    GetOpenFile(sock, fptr);
107    shutdown(fptr->fd, 0);
108    if (!(fptr->mode & FMODE_WRITABLE)) {
109	return rb_io_close(sock);
110    }
111    fptr->mode &= ~FMODE_READABLE;
112
113    return Qnil;
114}
115
116/*
117 * call-seq:
118 *   basicsocket.close_write => nil
119 *
120 * Disallows further write using shutdown system call.
121 *
122 *   UNIXSocket.pair {|s1, s2|
123 *     s1.print "ping"
124 *     s1.close_write
125 *     p s2.read        #=> "ping"
126 *     s2.print "pong"
127 *     s2.close
128 *     p s1.read        #=> "pong"
129 *   }
130 */
131static VALUE
132bsock_close_write(VALUE sock)
133{
134    rb_io_t *fptr;
135
136    if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
137	rb_raise(rb_eSecurityError, "Insecure: can't close socket");
138    }
139    GetOpenFile(sock, fptr);
140    if (!(fptr->mode & FMODE_READABLE)) {
141	return rb_io_close(sock);
142    }
143    shutdown(fptr->fd, 1);
144    fptr->mode &= ~FMODE_WRITABLE;
145
146    return Qnil;
147}
148
149/*
150 * Document-method: setsockopt
151 * call-seq:
152 *   setsockopt(level, optname, optval)
153 *   setsockopt(socketoption)
154 *
155 * Sets a socket option. These are protocol and system specific, see your
156 * local system documentation for details.
157 *
158 * === Parameters
159 * * +level+ is an integer, usually one of the SOL_ constants such as
160 *   Socket::SOL_SOCKET, or a protocol level.
161 *   A string or symbol of the name, possibly without prefix, is also
162 *   accepted.
163 * * +optname+ is an integer, usually one of the SO_ constants, such
164 *   as Socket::SO_REUSEADDR.
165 *   A string or symbol of the name, possibly without prefix, is also
166 *   accepted.
167 * * +optval+ is the value of the option, it is passed to the underlying
168 *   setsockopt() as a pointer to a certain number of bytes. How this is
169 *   done depends on the type:
170 *   - Fixnum: value is assigned to an int, and a pointer to the int is
171 *     passed, with length of sizeof(int).
172 *   - true or false: 1 or 0 (respectively) is assigned to an int, and the
173 *     int is passed as for a Fixnum. Note that +false+ must be passed,
174 *     not +nil+.
175 *   - String: the string's data and length is passed to the socket.
176 * * +socketoption+ is an instance of Socket::Option
177 *
178 * === Examples
179 *
180 * Some socket options are integers with boolean values, in this case
181 * #setsockopt could be called like this:
182 *   sock.setsockopt(:SOCKET, :REUSEADDR, true)
183 *   sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
184 *   sock.setsockopt(Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true))
185 *
186 * Some socket options are integers with numeric values, in this case
187 * #setsockopt could be called like this:
188 *   sock.setsockopt(:IP, :TTL, 255)
189 *   sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
190 *   sock.setsockopt(Socket::Option.int(:INET, :IP, :TTL, 255))
191 *
192 * Option values may be structs. Passing them can be complex as it involves
193 * examining your system headers to determine the correct definition. An
194 * example is an +ip_mreq+, which may be defined in your system headers as:
195 *   struct ip_mreq {
196 *     struct  in_addr imr_multiaddr;
197 *     struct  in_addr imr_interface;
198 *   };
199 *
200 * In this case #setsockopt could be called like this:
201 *   optval = IPAddr.new("224.0.0.251").hton +
202 *            IPAddr.new(Socket::INADDR_ANY, Socket::AF_INET).hton
203 *   sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval)
204 *
205*/
206static VALUE
207bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
208{
209    VALUE lev, optname, val;
210    int family, level, option;
211    rb_io_t *fptr;
212    int i;
213    char *v;
214    int vlen;
215
216    if (argc == 1) {
217        lev = rb_funcall(argv[0], rb_intern("level"), 0);
218        optname = rb_funcall(argv[0], rb_intern("optname"), 0);
219        val = rb_funcall(argv[0], rb_intern("data"), 0);
220    }
221    else {
222        rb_scan_args(argc, argv, "30", &lev, &optname, &val);
223    }
224
225    rb_secure(2);
226    GetOpenFile(sock, fptr);
227    family = rsock_getfamily(fptr->fd);
228    level = rsock_level_arg(family, lev);
229    option = rsock_optname_arg(family, level, optname);
230
231    switch (TYPE(val)) {
232      case T_FIXNUM:
233	i = FIX2INT(val);
234	goto numval;
235      case T_FALSE:
236	i = 0;
237	goto numval;
238      case T_TRUE:
239	i = 1;
240      numval:
241	v = (char*)&i; vlen = (int)sizeof(i);
242	break;
243      default:
244	StringValue(val);
245	v = RSTRING_PTR(val);
246	vlen = RSTRING_LENINT(val);
247	break;
248    }
249
250#define rb_sys_fail_path(path) rb_sys_fail_str(path)
251
252    rb_io_check_closed(fptr);
253    if (setsockopt(fptr->fd, level, option, v, vlen) < 0)
254	rb_sys_fail_path(fptr->pathv);
255
256    return INT2FIX(0);
257}
258
259#if !defined(__BEOS__)
260/*
261 * Document-method: getsockopt
262 * call-seq:
263 *   getsockopt(level, optname) => socketoption
264 *
265 * Gets a socket option. These are protocol and system specific, see your
266 * local system documentation for details. The option is returned as
267 * a Socket::Option object.
268 *
269 * === Parameters
270 * * +level+ is an integer, usually one of the SOL_ constants such as
271 *   Socket::SOL_SOCKET, or a protocol level.
272 *   A string or symbol of the name, possibly without prefix, is also
273 *   accepted.
274 * * +optname+ is an integer, usually one of the SO_ constants, such
275 *   as Socket::SO_REUSEADDR.
276 *   A string or symbol of the name, possibly without prefix, is also
277 *   accepted.
278 *
279 * === Examples
280 *
281 * Some socket options are integers with boolean values, in this case
282 * #getsockopt could be called like this:
283 *
284 *   reuseaddr = sock.getsockopt(:SOCKET, :REUSEADDR).bool
285 *
286 *   optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR)
287 *   optval = optval.unpack "i"
288 *   reuseaddr = optval[0] == 0 ? false : true
289 *
290 * Some socket options are integers with numeric values, in this case
291 * #getsockopt could be called like this:
292 *
293 *   ipttl = sock.getsockopt(:IP, :TTL).int
294 *
295 *   optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
296 *   ipttl = optval.unpack("i")[0]
297 *
298 * Option values may be structs. Decoding them can be complex as it involves
299 * examining your system headers to determine the correct definition. An
300 * example is a +struct linger+, which may be defined in your system headers
301 * as:
302 *   struct linger {
303 *     int l_onoff;
304 *     int l_linger;
305 *   };
306 *
307 * In this case #getsockopt could be called like this:
308 *
309 *   # Socket::Option knows linger structure.
310 *   onoff, linger = sock.getsockopt(:SOCKET, :LINGER).linger
311 *
312 *   optval =  sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER)
313 *   onoff, linger = optval.unpack "ii"
314 *   onoff = onoff == 0 ? false : true
315*/
316static VALUE
317bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname)
318{
319    int level, option;
320    socklen_t len;
321    char *buf;
322    rb_io_t *fptr;
323    int family;
324
325    GetOpenFile(sock, fptr);
326    family = rsock_getfamily(fptr->fd);
327    level = rsock_level_arg(family, lev);
328    option = rsock_optname_arg(family, level, optname);
329    len = 256;
330    buf = ALLOCA_N(char,len);
331
332    rb_io_check_closed(fptr);
333
334    if (getsockopt(fptr->fd, level, option, buf, &len) < 0)
335	rb_sys_fail_path(fptr->pathv);
336
337    return rsock_sockopt_new(family, level, option, rb_str_new(buf, len));
338}
339#else
340#define bsock_getsockopt rb_f_notimplement
341#endif
342
343/*
344 * call-seq:
345 *   basicsocket.getsockname => sockaddr
346 *
347 * Returns the local address of the socket as a sockaddr string.
348 *
349 *   TCPServer.open("127.0.0.1", 15120) {|serv|
350 *     p serv.getsockname #=> "\x02\x00;\x10\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
351 *   }
352 *
353 * If Addrinfo object is preferred over the binary string,
354 * use BasicSocket#local_address.
355 */
356static VALUE
357bsock_getsockname(VALUE sock)
358{
359    struct sockaddr_storage buf;
360    socklen_t len = (socklen_t)sizeof buf;
361    socklen_t len0 = len;
362    rb_io_t *fptr;
363
364    GetOpenFile(sock, fptr);
365    if (getsockname(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
366	rb_sys_fail("getsockname(2)");
367    if (len0 < len) len = len0;
368    return rb_str_new((char*)&buf, len);
369}
370
371/*
372 * call-seq:
373 *   basicsocket.getpeername => sockaddr
374 *
375 * Returns the remote address of the socket as a sockaddr string.
376 *
377 *   TCPServer.open("127.0.0.1", 1440) {|serv|
378 *     c = TCPSocket.new("127.0.0.1", 1440)
379 *     s = serv.accept
380 *     p s.getpeername #=> "\x02\x00\x82u\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
381 *   }
382 *
383 * If Addrinfo object is preferred over the binary string,
384 * use BasicSocket#remote_address.
385 *
386 */
387static VALUE
388bsock_getpeername(VALUE sock)
389{
390    struct sockaddr_storage buf;
391    socklen_t len = (socklen_t)sizeof buf;
392    socklen_t len0 = len;
393    rb_io_t *fptr;
394
395    GetOpenFile(sock, fptr);
396    if (getpeername(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
397	rb_sys_fail("getpeername(2)");
398    if (len0 < len) len = len0;
399    return rb_str_new((char*)&buf, len);
400}
401
402#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(HAVE_GETPEERUCRED)
403/*
404 * call-seq:
405 *   basicsocket.getpeereid => [euid, egid]
406 *
407 * Returns the user and group on the peer of the UNIX socket.
408 * The result is a two element array which contains the effective uid and the effective gid.
409 *
410 *   Socket.unix_server_loop("/tmp/sock") {|s|
411 *     begin
412 *       euid, egid = s.getpeereid
413 *
414 *       # Check the connected client is myself or not.
415 *       next if euid != Process.uid
416 *
417 *       # do something about my resource.
418 *
419 *     ensure
420 *       s.close
421 *     end
422 *   }
423 *
424 */
425static VALUE
426bsock_getpeereid(VALUE self)
427{
428#if defined(HAVE_GETPEEREID)
429    rb_io_t *fptr;
430    uid_t euid;
431    gid_t egid;
432    GetOpenFile(self, fptr);
433    if (getpeereid(fptr->fd, &euid, &egid) == -1)
434	rb_sys_fail("getpeereid");
435    return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid));
436#elif defined(SO_PEERCRED) /* GNU/Linux */
437    rb_io_t *fptr;
438    struct ucred cred;
439    socklen_t len = sizeof(cred);
440    GetOpenFile(self, fptr);
441    if (getsockopt(fptr->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
442	rb_sys_fail("getsockopt(SO_PEERCRED)");
443    return rb_assoc_new(UIDT2NUM(cred.uid), GIDT2NUM(cred.gid));
444#elif defined(HAVE_GETPEERUCRED) /* Solaris */
445    rb_io_t *fptr;
446    ucred_t *uc = NULL;
447    VALUE ret;
448    GetOpenFile(self, fptr);
449    if (getpeerucred(fptr->fd, &uc) == -1)
450	rb_sys_fail("getpeerucred");
451    ret = rb_assoc_new(UIDT2NUM(ucred_geteuid(uc)), GIDT2NUM(ucred_getegid(uc)));
452    ucred_free(uc);
453    return ret;
454#endif
455}
456#else
457#define bsock_getpeereid rb_f_notimplement
458#endif
459
460/*
461 * call-seq:
462 *   bsock.local_address => addrinfo
463 *
464 * Returns an Addrinfo object for local address obtained by getsockname.
465 *
466 * Note that addrinfo.protocol is filled by 0.
467 *
468 *   TCPSocket.open("www.ruby-lang.org", 80) {|s|
469 *     p s.local_address #=> #<Addrinfo: 192.168.0.129:36873 TCP>
470 *   }
471 *
472 *   TCPServer.open("127.0.0.1", 1512) {|serv|
473 *     p serv.local_address #=> #<Addrinfo: 127.0.0.1:1512 TCP>
474 *   }
475 *
476 */
477static VALUE
478bsock_local_address(VALUE sock)
479{
480    struct sockaddr_storage buf;
481    socklen_t len = (socklen_t)sizeof buf;
482    socklen_t len0 = len;
483    rb_io_t *fptr;
484
485    GetOpenFile(sock, fptr);
486    if (getsockname(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
487	rb_sys_fail("getsockname(2)");
488    if (len0 < len) len = len0;
489    return rsock_fd_socket_addrinfo(fptr->fd, (struct sockaddr *)&buf, len);
490}
491
492/*
493 * call-seq:
494 *   bsock.remote_address => addrinfo
495 *
496 * Returns an Addrinfo object for remote address obtained by getpeername.
497 *
498 * Note that addrinfo.protocol is filled by 0.
499 *
500 *   TCPSocket.open("www.ruby-lang.org", 80) {|s|
501 *     p s.remote_address #=> #<Addrinfo: 221.186.184.68:80 TCP>
502 *   }
503 *
504 *   TCPServer.open("127.0.0.1", 1728) {|serv|
505 *     c = TCPSocket.new("127.0.0.1", 1728)
506 *     s = serv.accept
507 *     p s.remote_address #=> #<Addrinfo: 127.0.0.1:36504 TCP>
508 *   }
509 *
510 */
511static VALUE
512bsock_remote_address(VALUE sock)
513{
514    struct sockaddr_storage buf;
515    socklen_t len = (socklen_t)sizeof buf;
516    socklen_t len0 = len;
517    rb_io_t *fptr;
518
519    GetOpenFile(sock, fptr);
520    if (getpeername(fptr->fd, (struct sockaddr*)&buf, &len) < 0)
521	rb_sys_fail("getpeername(2)");
522    if (len0 < len) len = len0;
523    return rsock_fd_socket_addrinfo(fptr->fd, (struct sockaddr *)&buf, len);
524}
525
526/*
527 * call-seq:
528 *   basicsocket.send(mesg, flags [, dest_sockaddr]) => numbytes_sent
529 *
530 * send _mesg_ via _basicsocket_.
531 *
532 * _mesg_ should be a string.
533 *
534 * _flags_ should be a bitwise OR of Socket::MSG_* constants.
535 *
536 * _dest_sockaddr_ should be a packed sockaddr string or an addrinfo.
537 *
538 *   TCPSocket.open("localhost", 80) {|s|
539 *     s.send "GET / HTTP/1.0\r\n\r\n", 0
540 *     p s.read
541 *   }
542 */
543VALUE
544rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
545{
546    struct rsock_send_arg arg;
547    VALUE flags, to;
548    rb_io_t *fptr;
549    int n;
550    rb_blocking_function_t *func;
551
552    rb_secure(4);
553    rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
554
555    StringValue(arg.mesg);
556    if (!NIL_P(to)) {
557	SockAddrStringValue(to);
558	to = rb_str_new4(to);
559	arg.to = (struct sockaddr *)RSTRING_PTR(to);
560	arg.tolen = (socklen_t)RSTRING_LENINT(to);
561	func = rsock_sendto_blocking;
562    }
563    else {
564	func = rsock_send_blocking;
565    }
566    GetOpenFile(sock, fptr);
567    arg.fd = fptr->fd;
568    arg.flags = NUM2INT(flags);
569    while (rb_thread_fd_writable(arg.fd),
570	   (n = (int)BLOCKING_REGION_FD(func, &arg)) < 0) {
571	if (rb_io_wait_writable(arg.fd)) {
572	    continue;
573	}
574	rb_sys_fail("send(2)");
575    }
576    return INT2FIX(n);
577}
578
579/*
580 * call-seq:
581 *   basicsocket.do_not_reverse_lookup => true or false
582 *
583 * Gets the do_not_reverse_lookup flag of _basicsocket_.
584 *
585 *   TCPSocket.open("www.ruby-lang.org", 80) {|sock|
586 *     p sock.do_not_reverse_lookup      #=> false
587 *     p sock.peeraddr                   #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
588 *     sock.do_not_reverse_lookup = true
589 *     p sock.peeraddr                   #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
590 *   }
591 */
592static VALUE
593bsock_do_not_reverse_lookup(VALUE sock)
594{
595    rb_io_t *fptr;
596
597    GetOpenFile(sock, fptr);
598    return (fptr->mode & FMODE_NOREVLOOKUP) ? Qtrue : Qfalse;
599}
600
601/*
602 * call-seq:
603 *   basicsocket.do_not_reverse_lookup = bool
604 *
605 * Sets the do_not_reverse_lookup flag of _basicsocket_.
606 *
607 *   BasicSocket.do_not_reverse_lookup = false
608 *   p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> false
609 *   BasicSocket.do_not_reverse_lookup = true
610 *   p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> true
611 *
612 */
613static VALUE
614bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
615{
616    rb_io_t *fptr;
617
618    rb_secure(4);
619    GetOpenFile(sock, fptr);
620    if (RTEST(state)) {
621	fptr->mode |= FMODE_NOREVLOOKUP;
622    }
623    else {
624	fptr->mode &= ~FMODE_NOREVLOOKUP;
625    }
626    return sock;
627}
628
629/*
630 * call-seq:
631 *   basicsocket.recv(maxlen) => mesg
632 *   basicsocket.recv(maxlen, flags) => mesg
633 *
634 * Receives a message.
635 *
636 * _maxlen_ is the maximum number of bytes to receive.
637 *
638 * _flags_ should be a bitwise OR of Socket::MSG_* constants.
639 *
640 *   UNIXSocket.pair {|s1, s2|
641 *     s1.puts "Hello World"
642 *     p s2.recv(4)                     #=> "Hell"
643 *     p s2.recv(4, Socket::MSG_PEEK)   #=> "o Wo"
644 *     p s2.recv(4)                     #=> "o Wo"
645 *     p s2.recv(10)                    #=> "rld\n"
646 *   }
647 */
648static VALUE
649bsock_recv(int argc, VALUE *argv, VALUE sock)
650{
651    return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
652}
653
654/*
655 * call-seq:
656 * 	basicsocket.recv_nonblock(maxlen) => mesg
657 * 	basicsocket.recv_nonblock(maxlen, flags) => mesg
658 *
659 * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
660 * O_NONBLOCK is set for the underlying file descriptor.
661 * _flags_ is zero or more of the +MSG_+ options.
662 * The result, _mesg_, is the data received.
663 *
664 * When recvfrom(2) returns 0, Socket#recv_nonblock returns
665 * an empty string as data.
666 * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
667 *
668 * === Parameters
669 * * +maxlen+ - the number of bytes to receive from the socket
670 * * +flags+ - zero or more of the +MSG_+ options
671 *
672 * === Example
673 * 	serv = TCPServer.new("127.0.0.1", 0)
674 * 	af, port, host, addr = serv.addr
675 * 	c = TCPSocket.new(addr, port)
676 * 	s = serv.accept
677 * 	c.send "aaa", 0
678 * 	begin # emulate blocking recv.
679 * 	  p s.recv_nonblock(10) #=> "aaa"
680 * 	rescue IO::WaitReadable
681 * 	  IO.select([s])
682 * 	  retry
683 * 	end
684 *
685 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
686 * to _recv_nonblock_ fails.
687 *
688 * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
689 * including Errno::EWOULDBLOCK.
690 *
691 * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
692 * it is extended by IO::WaitReadable.
693 * So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
694 *
695 * === See
696 * * Socket#recvfrom
697 */
698
699static VALUE
700bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
701{
702    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
703}
704
705/*
706 * call-seq:
707 *   BasicSocket.do_not_reverse_lookup => true or false
708 *
709 * Gets the global do_not_reverse_lookup flag.
710 *
711 *   BasicSocket.do_not_reverse_lookup  #=> false
712 */
713static VALUE
714bsock_do_not_rev_lookup(void)
715{
716    return rsock_do_not_reverse_lookup?Qtrue:Qfalse;
717}
718
719/*
720 * call-seq:
721 *   BasicSocket.do_not_reverse_lookup = bool
722 *
723 * Sets the global do_not_reverse_lookup flag.
724 *
725 * The flag is used for initial value of do_not_reverse_lookup for each socket.
726 *
727 *   s1 = TCPSocket.new("localhost", 80)
728 *   p s1.do_not_reverse_lookup                 #=> true
729 *   BasicSocket.do_not_reverse_lookup = false
730 *   s2 = TCPSocket.new("localhost", 80)
731 *   p s2.do_not_reverse_lookup                 #=> false
732 *   p s1.do_not_reverse_lookup                 #=> true
733 *
734 */
735static VALUE
736bsock_do_not_rev_lookup_set(VALUE self, VALUE val)
737{
738    rb_secure(4);
739    rsock_do_not_reverse_lookup = RTEST(val);
740    return val;
741}
742
743void
744rsock_init_basicsocket(void)
745{
746    /*
747     * Document-class: BasicSocket < IO
748     *
749     * BasicSocket is the super class for all the Socket classes.
750     */
751    rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO);
752    rb_undef_method(rb_cBasicSocket, "initialize");
753
754    rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup",
755			       bsock_do_not_rev_lookup, 0);
756    rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup=",
757			       bsock_do_not_rev_lookup_set, 1);
758    rb_define_singleton_method(rb_cBasicSocket, "for_fd", bsock_s_for_fd, 1);
759
760    rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0);
761    rb_define_method(rb_cBasicSocket, "close_write", bsock_close_write, 0);
762    rb_define_method(rb_cBasicSocket, "shutdown", bsock_shutdown, -1);
763    rb_define_method(rb_cBasicSocket, "setsockopt", bsock_setsockopt, -1);
764    rb_define_method(rb_cBasicSocket, "getsockopt", bsock_getsockopt, 2);
765    rb_define_method(rb_cBasicSocket, "getsockname", bsock_getsockname, 0);
766    rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0);
767    rb_define_method(rb_cBasicSocket, "getpeereid", bsock_getpeereid, 0);
768    rb_define_method(rb_cBasicSocket, "local_address", bsock_local_address, 0);
769    rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
770    rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
771    rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
772    rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
773    rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
774    rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
775
776    rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
777    rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
778    rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -1); /* in ancdata.c */
779    rb_define_method(rb_cBasicSocket, "recvmsg_nonblock", rsock_bsock_recvmsg_nonblock, -1); /* in ancdata.c */
780
781}
782