Ruby  2.0.0p247(2013-06-27revision41674)
ext/socket/socket.c
Go to the documentation of this file.
00001 /************************************************
00002 
00003   socket.c -
00004 
00005   created at: Thu Mar 31 12:21:29 JST 1994
00006 
00007   Copyright (C) 1993-2007 Yukihiro Matsumoto
00008 
00009 ************************************************/
00010 
00011 #include "rubysocket.h"
00012 
00013 static void
00014 setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv)
00015 {
00016     *dv = rsock_family_arg(domain);
00017     *tv = rsock_socktype_arg(type);
00018 }
00019 
00020 /*
00021  * call-seq:
00022  *   Socket.new(domain, socktype [, protocol]) => socket
00023  *
00024  * Creates a new socket object.
00025  *
00026  * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc.
00027  *
00028  * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
00029  *
00030  * _protocol_ is optional and should be a protocol defined in the domain.
00031  * If protocol is not given, 0 is used internally.
00032  *
00033  *   Socket.new(:INET, :STREAM) # TCP socket
00034  *   Socket.new(:INET, :DGRAM)  # UDP socket
00035  *   Socket.new(:UNIX, :STREAM) # UNIX stream socket
00036  *   Socket.new(:UNIX, :DGRAM)  # UNIX datagram socket
00037  */
00038 static VALUE
00039 sock_initialize(int argc, VALUE *argv, VALUE sock)
00040 {
00041     VALUE domain, type, protocol;
00042     int fd;
00043     int d, t;
00044 
00045     rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
00046     if (NIL_P(protocol))
00047         protocol = INT2FIX(0);
00048 
00049     rb_secure(3);
00050     setup_domain_and_type(domain, &d, type, &t);
00051     fd = rsock_socket(d, t, NUM2INT(protocol));
00052     if (fd < 0) rb_sys_fail("socket(2)");
00053 
00054     return rsock_init_sock(sock, fd);
00055 }
00056 
00057 #if defined HAVE_SOCKETPAIR
00058 static VALUE
00059 io_call_close(VALUE io)
00060 {
00061     return rb_funcall(io, rb_intern("close"), 0, 0);
00062 }
00063 
00064 static VALUE
00065 io_close(VALUE io)
00066 {
00067     return rb_rescue(io_call_close, io, 0, 0);
00068 }
00069 
00070 static VALUE
00071 pair_yield(VALUE pair)
00072 {
00073     return rb_ensure(rb_yield, pair, io_close, rb_ary_entry(pair, 1));
00074 }
00075 #endif
00076 
00077 #if defined HAVE_SOCKETPAIR
00078 
00079 static int
00080 rsock_socketpair0(int domain, int type, int protocol, int sv[2])
00081 {
00082     int ret;
00083 
00084 #ifdef SOCK_CLOEXEC
00085     static int try_sock_cloexec = 1;
00086     if (try_sock_cloexec) {
00087         ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
00088         if (ret == -1 && errno == EINVAL) {
00089             /* SOCK_CLOEXEC is available since Linux 2.6.27.  Linux 2.6.18 fails with EINVAL */
00090             ret = socketpair(domain, type, protocol, sv);
00091             if (ret != -1) {
00092                 /* The reason of EINVAL may be other than SOCK_CLOEXEC.
00093                  * So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC.
00094                  * Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL.
00095                  */
00096                 try_sock_cloexec = 0;
00097             }
00098         }
00099     }
00100     else {
00101         ret = socketpair(domain, type, protocol, sv);
00102     }
00103 #else
00104     ret = socketpair(domain, type, protocol, sv);
00105 #endif
00106 
00107     if (ret == -1) {
00108         return -1;
00109     }
00110 
00111     rb_fd_fix_cloexec(sv[0]);
00112     rb_fd_fix_cloexec(sv[1]);
00113 
00114     return ret;
00115 }
00116 
00117 static int
00118 rsock_socketpair(int domain, int type, int protocol, int sv[2])
00119 {
00120     int ret;
00121 
00122     ret = rsock_socketpair0(domain, type, protocol, sv);
00123     if (ret < 0 && (errno == EMFILE || errno == ENFILE)) {
00124         rb_gc();
00125         ret = rsock_socketpair0(domain, type, protocol, sv);
00126     }
00127 
00128     return ret;
00129 }
00130 
00131 /*
00132  * call-seq:
00133  *   Socket.pair(domain, type, protocol)       => [socket1, socket2]
00134  *   Socket.socketpair(domain, type, protocol) => [socket1, socket2]
00135  *
00136  * Creates a pair of sockets connected each other.
00137  *
00138  * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc.
00139  *
00140  * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
00141  *
00142  * _protocol_ should be a protocol defined in the domain,
00143  * defaults to 0 for the domain.
00144  *
00145  *   s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
00146  *   s1.send "a", 0
00147  *   s1.send "b", 0
00148  *   p s2.recv(10) #=> "a"
00149  *   p s2.recv(10) #=> "b"
00150  *
00151  */
00152 VALUE
00153 rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
00154 {
00155     VALUE domain, type, protocol;
00156     int d, t, p, sp[2];
00157     int ret;
00158     VALUE s1, s2, r;
00159 
00160     rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
00161     if (NIL_P(protocol))
00162         protocol = INT2FIX(0);
00163 
00164     setup_domain_and_type(domain, &d, type, &t);
00165     p = NUM2INT(protocol);
00166     ret = rsock_socketpair(d, t, p, sp);
00167     if (ret < 0) {
00168         rb_sys_fail("socketpair(2)");
00169     }
00170     rb_fd_fix_cloexec(sp[0]);
00171     rb_fd_fix_cloexec(sp[1]);
00172 
00173     s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
00174     s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
00175     r = rb_assoc_new(s1, s2);
00176     if (rb_block_given_p()) {
00177         return rb_ensure(pair_yield, r, io_close, s1);
00178     }
00179     return r;
00180 }
00181 #else
00182 #define rsock_sock_s_socketpair rb_f_notimplement
00183 #endif
00184 
00185 /*
00186  * call-seq:
00187  *      socket.connect(remote_sockaddr) => 0
00188  *
00189  * Requests a connection to be made on the given +remote_sockaddr+. Returns 0 if
00190  * successful, otherwise an exception is raised.
00191  *
00192  * === Parameter
00193  * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
00194  *
00195  * === Example:
00196  *      # Pull down Google's web page
00197  *      require 'socket'
00198  *      include Socket::Constants
00199  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00200  *      sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
00201  *      socket.connect( sockaddr )
00202  *      socket.write( "GET / HTTP/1.0\r\n\r\n" )
00203  *      results = socket.read
00204  *
00205  * === Unix-based Exceptions
00206  * On unix-based systems the following system exceptions may be raised if
00207  * the call to _connect_ fails:
00208  * * Errno::EACCES - search permission is denied for a component of the prefix
00209  *   path or write access to the +socket+ is denied
00210  * * Errno::EADDRINUSE - the _sockaddr_ is already in use
00211  * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
00212  *   local machine
00213  * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for
00214  *   the address family of the specified +socket+
00215  * * Errno::EALREADY - a connection is already in progress for the specified
00216  *   socket
00217  * * Errno::EBADF - the +socket+ is not a valid file descriptor
00218  * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
00219  *   refused the connection request
00220  * * Errno::ECONNRESET - the remote host reset the connection request
00221  * * Errno::EFAULT - the _sockaddr_ cannot be accessed
00222  * * Errno::EHOSTUNREACH - the destination host cannot be reached (probably
00223  *   because the host is down or a remote router cannot reach it)
00224  * * Errno::EINPROGRESS - the O_NONBLOCK is set for the +socket+ and the
00225  *   connection cannot be immediately established; the connection will be
00226  *   established asynchronously
00227  * * Errno::EINTR - the attempt to establish the connection was interrupted by
00228  *   delivery of a signal that was caught; the connection will be established
00229  *   asynchronously
00230  * * Errno::EISCONN - the specified +socket+ is already connected
00231  * * Errno::EINVAL - the address length used for the _sockaddr_ is not a valid
00232  *   length for the address family or there is an invalid family in _sockaddr_
00233  * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
00234  *   PATH_MAX
00235  * * Errno::ENETDOWN - the local interface used to reach the destination is down
00236  * * Errno::ENETUNREACH - no route to the network is present
00237  * * Errno::ENOBUFS - no buffer space is available
00238  * * Errno::ENOSR - there were insufficient STREAMS resources available to
00239  *   complete the operation
00240  * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
00241  * * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected
00242  * * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket
00243  *   bound to the specified peer address
00244  * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
00245  *   was made.
00246  *
00247  * On unix-based systems if the address family of the calling +socket+ is
00248  * AF_UNIX the follow exceptions may be raised if the call to _connect_
00249  * fails:
00250  * * Errno::EIO - an i/o error occurred while reading from or writing to the
00251  *   file system
00252  * * Errno::ELOOP - too many symbolic links were encountered in translating
00253  *   the pathname in _sockaddr_
00254  * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
00255  *   characters, or an entire pathname exceeded PATH_MAX characters
00256  * * Errno::ENOENT - a component of the pathname does not name an existing file
00257  *   or the pathname is an empty string
00258  * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
00259  *   is not a directory
00260  *
00261  * === Windows Exceptions
00262  * On Windows systems the following system exceptions may be raised if
00263  * the call to _connect_ fails:
00264  * * Errno::ENETDOWN - the network is down
00265  * * Errno::EADDRINUSE - the socket's local address is already in use
00266  * * Errno::EINTR - the socket was cancelled
00267  * * Errno::EINPROGRESS - a blocking socket is in progress or the service provider
00268  *   is still processing a callback function. Or a nonblocking connect call is
00269  *   in progress on the +socket+.
00270  * * Errno::EALREADY - see Errno::EINVAL
00271  * * Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as
00272  *   ADDR_ANY TODO check ADDRANY TO INADDR_ANY
00273  * * Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with
00274  *   with this +socket+
00275  * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
00276  *   refused the connection request
00277  * * Errno::EFAULT - the socket's internal address or address length parameter
00278  *   is too small or is not a valid part of the user space address
00279  * * Errno::EINVAL - the +socket+ is a listening socket
00280  * * Errno::EISCONN - the +socket+ is already connected
00281  * * Errno::ENETUNREACH - the network cannot be reached from this host at this time
00282  * * Errno::EHOSTUNREACH - no route to the network is present
00283  * * Errno::ENOBUFS - no buffer space is available
00284  * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
00285  * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
00286  *   was made.
00287  * * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the
00288  *   connection cannot be completed immediately
00289  * * Errno::EACCES - the attempt to connect the datagram socket to the
00290  *   broadcast address failed
00291  *
00292  * === See
00293  * * connect manual pages on unix-based systems
00294  * * connect function in Microsoft's Winsock functions reference
00295  */
00296 static VALUE
00297 sock_connect(VALUE sock, VALUE addr)
00298 {
00299     rb_io_t *fptr;
00300     int fd, n;
00301 
00302     SockAddrStringValue(addr);
00303     addr = rb_str_new4(addr);
00304     GetOpenFile(sock, fptr);
00305     fd = fptr->fd;
00306     n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr), 0);
00307     if (n < 0) {
00308         rb_sys_fail("connect(2)");
00309     }
00310 
00311     return INT2FIX(n);
00312 }
00313 
00314 /*
00315  * call-seq:
00316  *      socket.connect_nonblock(remote_sockaddr) => 0
00317  *
00318  * Requests a connection to be made on the given +remote_sockaddr+ after
00319  * O_NONBLOCK is set for the underlying file descriptor.
00320  * Returns 0 if successful, otherwise an exception is raised.
00321  *
00322  * === Parameter
00323  * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
00324  *
00325  * === Example:
00326  *      # Pull down Google's web page
00327  *      require 'socket'
00328  *      include Socket::Constants
00329  *      socket = Socket.new(AF_INET, SOCK_STREAM, 0)
00330  *      sockaddr = Socket.sockaddr_in(80, 'www.google.com')
00331  *      begin # emulate blocking connect
00332  *        socket.connect_nonblock(sockaddr)
00333  *      rescue IO::WaitWritable
00334  *        IO.select(nil, [socket]) # wait 3-way handshake completion
00335  *        begin
00336  *          socket.connect_nonblock(sockaddr) # check connection failure
00337  *        rescue Errno::EISCONN
00338  *        end
00339  *      end
00340  *      socket.write("GET / HTTP/1.0\r\n\r\n")
00341  *      results = socket.read
00342  *
00343  * Refer to Socket#connect for the exceptions that may be thrown if the call
00344  * to _connect_nonblock_ fails.
00345  *
00346  * Socket#connect_nonblock may raise any error corresponding to connect(2) failure,
00347  * including Errno::EINPROGRESS.
00348  *
00349  * If the exception is Errno::EINPROGRESS,
00350  * it is extended by IO::WaitWritable.
00351  * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock.
00352  *
00353  * === See
00354  * * Socket#connect
00355  */
00356 static VALUE
00357 sock_connect_nonblock(VALUE sock, VALUE addr)
00358 {
00359     rb_io_t *fptr;
00360     int n;
00361 
00362     SockAddrStringValue(addr);
00363     addr = rb_str_new4(addr);
00364     GetOpenFile(sock, fptr);
00365     rb_io_set_nonblock(fptr);
00366     n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr));
00367     if (n < 0) {
00368         if (errno == EINPROGRESS)
00369             rb_mod_sys_fail(rb_mWaitWritable, "connect(2) would block");
00370         rb_sys_fail("connect(2)");
00371     }
00372 
00373     return INT2FIX(n);
00374 }
00375 
00376 /*
00377  * call-seq:
00378  *      socket.bind(local_sockaddr) => 0
00379  *
00380  * Binds to the given local address.
00381  *
00382  * === Parameter
00383  * * +local_sockaddr+ - the +struct+ sockaddr contained in a string or an Addrinfo object
00384  *
00385  * === Example
00386  *      require 'socket'
00387  *
00388  *      # use Addrinfo
00389  *      socket = Socket.new(:INET, :STREAM, 0)
00390  *      socket.bind(Addrinfo.tcp("127.0.0.1", 2222))
00391  *      p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP>
00392  *
00393  *      # use struct sockaddr
00394  *      include Socket::Constants
00395  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00396  *      sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
00397  *      socket.bind( sockaddr )
00398  *
00399  * === Unix-based Exceptions
00400  * On unix-based based systems the following system exceptions may be raised if
00401  * the call to _bind_ fails:
00402  * * Errno::EACCES - the specified _sockaddr_ is protected and the current
00403  *   user does not have permission to bind to it
00404  * * Errno::EADDRINUSE - the specified _sockaddr_ is already in use
00405  * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
00406  *   local machine
00407  * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for
00408  *   the family of the calling +socket+
00409  * * Errno::EBADF - the _sockaddr_ specified is not a valid file descriptor
00410  * * Errno::EFAULT - the _sockaddr_ argument cannot be accessed
00411  * * Errno::EINVAL - the +socket+ is already bound to an address, and the
00412  *   protocol does not support binding to the new _sockaddr_ or the +socket+
00413  *   has been shut down.
00414  * * Errno::EINVAL - the address length is not a valid length for the address
00415  *   family
00416  * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
00417  *   PATH_MAX
00418  * * Errno::ENOBUFS - no buffer space is available
00419  * * Errno::ENOSR - there were insufficient STREAMS resources available to
00420  *   complete the operation
00421  * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
00422  * * Errno::EOPNOTSUPP - the socket type of the +socket+ does not support
00423  *   binding to an address
00424  *
00425  * On unix-based based systems if the address family of the calling +socket+ is
00426  * Socket::AF_UNIX the follow exceptions may be raised if the call to _bind_
00427  * fails:
00428  * * Errno::EACCES - search permission is denied for a component of the prefix
00429  *   path or write access to the +socket+ is denied
00430  * * Errno::EDESTADDRREQ - the _sockaddr_ argument is a null pointer
00431  * * Errno::EISDIR - same as Errno::EDESTADDRREQ
00432  * * Errno::EIO - an i/o error occurred
00433  * * Errno::ELOOP - too many symbolic links were encountered in translating
00434  *   the pathname in _sockaddr_
00435  * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
00436  *   characters, or an entire pathname exceeded PATH_MAX characters
00437  * * Errno::ENOENT - a component of the pathname does not name an existing file
00438  *   or the pathname is an empty string
00439  * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
00440  *   is not a directory
00441  * * Errno::EROFS - the name would reside on a read only filesystem
00442  *
00443  * === Windows Exceptions
00444  * On Windows systems the following system exceptions may be raised if
00445  * the call to _bind_ fails:
00446  * * Errno::ENETDOWN-- the network is down
00447  * * Errno::EACCES - the attempt to connect the datagram socket to the
00448  *   broadcast address failed
00449  * * Errno::EADDRINUSE - the socket's local address is already in use
00450  * * Errno::EADDRNOTAVAIL - the specified address is not a valid address for this
00451  *   computer
00452  * * Errno::EFAULT - the socket's internal address or address length parameter
00453  *   is too small or is not a valid part of the user space addressed
00454  * * Errno::EINVAL - the +socket+ is already bound to an address
00455  * * Errno::ENOBUFS - no buffer space is available
00456  * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
00457  *
00458  * === See
00459  * * bind manual pages on unix-based systems
00460  * * bind function in Microsoft's Winsock functions reference
00461  */
00462 static VALUE
00463 sock_bind(VALUE sock, VALUE addr)
00464 {
00465     rb_io_t *fptr;
00466 
00467     SockAddrStringValue(addr);
00468     GetOpenFile(sock, fptr);
00469     if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)) < 0)
00470         rb_sys_fail("bind(2)");
00471 
00472     return INT2FIX(0);
00473 }
00474 
00475 /*
00476  * call-seq:
00477  *      socket.listen( int ) => 0
00478  *
00479  * Listens for connections, using the specified +int+ as the backlog. A call
00480  * to _listen_ only applies if the +socket+ is of type SOCK_STREAM or
00481  * SOCK_SEQPACKET.
00482  *
00483  * === Parameter
00484  * * +backlog+ - the maximum length of the queue for pending connections.
00485  *
00486  * === Example 1
00487  *      require 'socket'
00488  *      include Socket::Constants
00489  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00490  *      sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
00491  *      socket.bind( sockaddr )
00492  *      socket.listen( 5 )
00493  *
00494  * === Example 2 (listening on an arbitrary port, unix-based systems only):
00495  *      require 'socket'
00496  *      include Socket::Constants
00497  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00498  *      socket.listen( 1 )
00499  *
00500  * === Unix-based Exceptions
00501  * On unix based systems the above will work because a new +sockaddr+ struct
00502  * is created on the address ADDR_ANY, for an arbitrary port number as handed
00503  * off by the kernel. It will not work on Windows, because Windows requires that
00504  * the +socket+ is bound by calling _bind_ before it can _listen_.
00505  *
00506  * If the _backlog_ amount exceeds the implementation-dependent maximum
00507  * queue length, the implementation's maximum queue length will be used.
00508  *
00509  * On unix-based based systems the following system exceptions may be raised if the
00510  * call to _listen_ fails:
00511  * * Errno::EBADF - the _socket_ argument is not a valid file descriptor
00512  * * Errno::EDESTADDRREQ - the _socket_ is not bound to a local address, and
00513  *   the protocol does not support listening on an unbound socket
00514  * * Errno::EINVAL - the _socket_ is already connected
00515  * * Errno::ENOTSOCK - the _socket_ argument does not refer to a socket
00516  * * Errno::EOPNOTSUPP - the _socket_ protocol does not support listen
00517  * * Errno::EACCES - the calling process does not have appropriate privileges
00518  * * Errno::EINVAL - the _socket_ has been shut down
00519  * * Errno::ENOBUFS - insufficient resources are available in the system to
00520  *   complete the call
00521  *
00522  * === Windows Exceptions
00523  * On Windows systems the following system exceptions may be raised if
00524  * the call to _listen_ fails:
00525  * * Errno::ENETDOWN - the network is down
00526  * * Errno::EADDRINUSE - the socket's local address is already in use. This
00527  *   usually occurs during the execution of _bind_ but could be delayed
00528  *   if the call to _bind_ was to a partially wildcard address (involving
00529  *   ADDR_ANY) and if a specific address needs to be committed at the
00530  *   time of the call to _listen_
00531  * * Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the
00532  *   service provider is still processing a callback function
00533  * * Errno::EINVAL - the +socket+ has not been bound with a call to _bind_.
00534  * * Errno::EISCONN - the +socket+ is already connected
00535  * * Errno::EMFILE - no more socket descriptors are available
00536  * * Errno::ENOBUFS - no buffer space is available
00537  * * Errno::ENOTSOC - +socket+ is not a socket
00538  * * Errno::EOPNOTSUPP - the referenced +socket+ is not a type that supports
00539  *   the _listen_ method
00540  *
00541  * === See
00542  * * listen manual pages on unix-based systems
00543  * * listen function in Microsoft's Winsock functions reference
00544  */
00545 VALUE
00546 rsock_sock_listen(VALUE sock, VALUE log)
00547 {
00548     rb_io_t *fptr;
00549     int backlog;
00550 
00551     rb_secure(4);
00552     backlog = NUM2INT(log);
00553     GetOpenFile(sock, fptr);
00554     if (listen(fptr->fd, backlog) < 0)
00555         rb_sys_fail("listen(2)");
00556 
00557     return INT2FIX(0);
00558 }
00559 
00560 /*
00561  * call-seq:
00562  *      socket.recvfrom(maxlen) => [mesg, sender_addrinfo]
00563  *      socket.recvfrom(maxlen, flags) => [mesg, sender_addrinfo]
00564  *
00565  * Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more
00566  * of the +MSG_+ options. The first element of the results, _mesg_, is the data
00567  * received. The second element, _sender_addrinfo_, contains protocol-specific
00568  * address information of the sender.
00569  *
00570  * === Parameters
00571  * * +maxlen+ - the maximum number of bytes to receive from the socket
00572  * * +flags+ - zero or more of the +MSG_+ options
00573  *
00574  * === Example
00575  *      # In one file, start this first
00576  *      require 'socket'
00577  *      include Socket::Constants
00578  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00579  *      sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
00580  *      socket.bind( sockaddr )
00581  *      socket.listen( 5 )
00582  *      client, client_addrinfo = socket.accept
00583  *      data = client.recvfrom( 20 )[0].chomp
00584  *      puts "I only received 20 bytes '#{data}'"
00585  *      sleep 1
00586  *      socket.close
00587  *
00588  *      # In another file, start this second
00589  *      require 'socket'
00590  *      include Socket::Constants
00591  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00592  *      sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
00593  *      socket.connect( sockaddr )
00594  *      socket.puts "Watch this get cut short!"
00595  *      socket.close
00596  *
00597  * === Unix-based Exceptions
00598  * On unix-based based systems the following system exceptions may be raised if the
00599  * call to _recvfrom_ fails:
00600  * * Errno::EAGAIN - the +socket+ file descriptor is marked as O_NONBLOCK and no
00601  *   data is waiting to be received; or MSG_OOB is set and no out-of-band data
00602  *   is available and either the +socket+ file descriptor is marked as
00603  *   O_NONBLOCK or the +socket+ does not support blocking to wait for
00604  *   out-of-band-data
00605  * * Errno::EWOULDBLOCK - see Errno::EAGAIN
00606  * * Errno::EBADF - the +socket+ is not a valid file descriptor
00607  * * Errno::ECONNRESET - a connection was forcibly closed by a peer
00608  * * Errno::EFAULT - the socket's internal buffer, address or address length
00609  *   cannot be accessed or written
00610  * * Errno::EINTR - a signal interrupted _recvfrom_ before any data was available
00611  * * Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available
00612  * * Errno::EIO - an i/o error occurred while reading from or writing to the
00613  *   filesystem
00614  * * Errno::ENOBUFS - insufficient resources were available in the system to
00615  *   perform the operation
00616  * * Errno::ENOMEM - insufficient memory was available to fulfill the request
00617  * * Errno::ENOSR - there were insufficient STREAMS resources available to
00618  *   complete the operation
00619  * * Errno::ENOTCONN - a receive is attempted on a connection-mode socket that
00620  *   is not connected
00621  * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
00622  * * Errno::EOPNOTSUPP - the specified flags are not supported for this socket type
00623  * * Errno::ETIMEDOUT - the connection timed out during connection establishment
00624  *   or due to a transmission timeout on an active connection
00625  *
00626  * === Windows Exceptions
00627  * On Windows systems the following system exceptions may be raised if
00628  * the call to _recvfrom_ fails:
00629  * * Errno::ENETDOWN - the network is down
00630  * * Errno::EFAULT - the internal buffer and from parameters on +socket+ are not
00631  *   part of the user address space, or the internal fromlen parameter is
00632  *   too small to accommodate the peer address
00633  * * Errno::EINTR - the (blocking) call was cancelled by an internal call to
00634  *   the WinSock function WSACancelBlockingCall
00635  * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or
00636  *   the service provider is still processing a callback function
00637  * * Errno::EINVAL - +socket+ has not been bound with a call to _bind_, or an
00638  *   unknown flag was specified, or MSG_OOB was specified for a socket with
00639  *   SO_OOBINLINE enabled, or (for byte stream-style sockets only) the internal
00640  *   len parameter on +socket+ was zero or negative
00641  * * Errno::EISCONN - +socket+ is already connected. The call to _recvfrom_ is
00642  *   not permitted with a connected socket on a socket that is connection
00643  *   oriented or connectionless.
00644  * * Errno::ENETRESET - the connection has been broken due to the keep-alive
00645  *   activity detecting a failure while the operation was in progress.
00646  * * Errno::EOPNOTSUPP - MSG_OOB was specified, but +socket+ is not stream-style
00647  *   such as type SOCK_STREAM. OOB data is not supported in the communication
00648  *   domain associated with +socket+, or +socket+ is unidirectional and
00649  *   supports only send operations
00650  * * Errno::ESHUTDOWN - +socket+ has been shutdown. It is not possible to
00651  *   call _recvfrom_ on a socket after _shutdown_ has been invoked.
00652  * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and a  call to
00653  *   _recvfrom_ would block.
00654  * * Errno::EMSGSIZE - the message was too large to fit into the specified buffer
00655  *   and was truncated.
00656  * * Errno::ETIMEDOUT - the connection has been dropped, because of a network
00657  *   failure or because the system on the other end went down without
00658  *   notice
00659  * * Errno::ECONNRESET - the virtual circuit was reset by the remote side
00660  *   executing a hard or abortive close. The application should close the
00661  *   socket; it is no longer usable. On a UDP-datagram socket this error
00662  *   indicates a previous send operation resulted in an ICMP Port Unreachable
00663  *   message.
00664  */
00665 static VALUE
00666 sock_recvfrom(int argc, VALUE *argv, VALUE sock)
00667 {
00668     return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
00669 }
00670 
00671 /*
00672  * call-seq:
00673  *      socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
00674  *      socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
00675  *
00676  * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
00677  * O_NONBLOCK is set for the underlying file descriptor.
00678  * _flags_ is zero or more of the +MSG_+ options.
00679  * The first element of the results, _mesg_, is the data received.
00680  * The second element, _sender_addrinfo_, contains protocol-specific address
00681  * information of the sender.
00682  *
00683  * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
00684  * an empty string as data.
00685  * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
00686  *
00687  * === Parameters
00688  * * +maxlen+ - the maximum number of bytes to receive from the socket
00689  * * +flags+ - zero or more of the +MSG_+ options
00690  *
00691  * === Example
00692  *      # In one file, start this first
00693  *      require 'socket'
00694  *      include Socket::Constants
00695  *      socket = Socket.new(AF_INET, SOCK_STREAM, 0)
00696  *      sockaddr = Socket.sockaddr_in(2200, 'localhost')
00697  *      socket.bind(sockaddr)
00698  *      socket.listen(5)
00699  *      client, client_addrinfo = socket.accept
00700  *      begin # emulate blocking recvfrom
00701  *        pair = client.recvfrom_nonblock(20)
00702  *      rescue IO::WaitReadable
00703  *        IO.select([client])
00704  *        retry
00705  *      end
00706  *      data = pair[0].chomp
00707  *      puts "I only received 20 bytes '#{data}'"
00708  *      sleep 1
00709  *      socket.close
00710  *
00711  *      # In another file, start this second
00712  *      require 'socket'
00713  *      include Socket::Constants
00714  *      socket = Socket.new(AF_INET, SOCK_STREAM, 0)
00715  *      sockaddr = Socket.sockaddr_in(2200, 'localhost')
00716  *      socket.connect(sockaddr)
00717  *      socket.puts "Watch this get cut short!"
00718  *      socket.close
00719  *
00720  * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
00721  * to _recvfrom_nonblock_ fails.
00722  *
00723  * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
00724  * including Errno::EWOULDBLOCK.
00725  *
00726  * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
00727  * it is extended by IO::WaitReadable.
00728  * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
00729  *
00730  * === See
00731  * * Socket#recvfrom
00732  */
00733 static VALUE
00734 sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
00735 {
00736     return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
00737 }
00738 
00739 /*
00740  * call-seq:
00741  *   socket.accept => [client_socket, client_addrinfo]
00742  *
00743  * Accepts a next connection.
00744  * Returns a new Socket object and Addrinfo object.
00745  *
00746  *   serv = Socket.new(:INET, :STREAM, 0)
00747  *   serv.listen(5)
00748  *   c = Socket.new(:INET, :STREAM, 0)
00749  *   c.connect(serv.connect_address)
00750  *   p serv.accept #=> [#<Socket:fd 6>, #<Addrinfo: 127.0.0.1:48555 TCP>]
00751  *
00752  */
00753 static VALUE
00754 sock_accept(VALUE sock)
00755 {
00756     rb_io_t *fptr;
00757     VALUE sock2;
00758     struct sockaddr_storage buf;
00759     socklen_t len = (socklen_t)sizeof buf;
00760 
00761     GetOpenFile(sock, fptr);
00762     sock2 = rsock_s_accept(rb_cSocket,fptr->fd,(struct sockaddr*)&buf,&len);
00763 
00764     return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
00765 }
00766 
00767 /*
00768  * call-seq:
00769  *      socket.accept_nonblock => [client_socket, client_addrinfo]
00770  *
00771  * Accepts an incoming connection using accept(2) after
00772  * O_NONBLOCK is set for the underlying file descriptor.
00773  * It returns an array containing the accepted socket
00774  * for the incoming connection, _client_socket_,
00775  * and an Addrinfo, _client_addrinfo_.
00776  *
00777  * === Example
00778  *      # In one script, start this first
00779  *      require 'socket'
00780  *      include Socket::Constants
00781  *      socket = Socket.new(AF_INET, SOCK_STREAM, 0)
00782  *      sockaddr = Socket.sockaddr_in(2200, 'localhost')
00783  *      socket.bind(sockaddr)
00784  *      socket.listen(5)
00785  *      begin # emulate blocking accept
00786  *        client_socket, client_addrinfo = socket.accept_nonblock
00787  *      rescue IO::WaitReadable, Errno::EINTR
00788  *        IO.select([socket])
00789  *        retry
00790  *      end
00791  *      puts "The client said, '#{client_socket.readline.chomp}'"
00792  *      client_socket.puts "Hello from script one!"
00793  *      socket.close
00794  *
00795  *      # In another script, start this second
00796  *      require 'socket'
00797  *      include Socket::Constants
00798  *      socket = Socket.new(AF_INET, SOCK_STREAM, 0)
00799  *      sockaddr = Socket.sockaddr_in(2200, 'localhost')
00800  *      socket.connect(sockaddr)
00801  *      socket.puts "Hello from script 2."
00802  *      puts "The server said, '#{socket.readline.chomp}'"
00803  *      socket.close
00804  *
00805  * Refer to Socket#accept for the exceptions that may be thrown if the call
00806  * to _accept_nonblock_ fails.
00807  *
00808  * Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
00809  * including Errno::EWOULDBLOCK.
00810  *
00811  * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO,
00812  * it is extended by IO::WaitReadable.
00813  * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
00814  *
00815  * === See
00816  * * Socket#accept
00817  */
00818 static VALUE
00819 sock_accept_nonblock(VALUE sock)
00820 {
00821     rb_io_t *fptr;
00822     VALUE sock2;
00823     struct sockaddr_storage buf;
00824     socklen_t len = (socklen_t)sizeof buf;
00825 
00826     GetOpenFile(sock, fptr);
00827     sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)&buf, &len);
00828     return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
00829 }
00830 
00831 /*
00832  * call-seq:
00833  *      socket.sysaccept => [client_socket_fd, client_addrinfo]
00834  *
00835  * Accepts an incoming connection returning an array containing the (integer)
00836  * file descriptor for the incoming connection, _client_socket_fd_,
00837  * and an Addrinfo, _client_addrinfo_.
00838  *
00839  * === Example
00840  *      # In one script, start this first
00841  *      require 'socket'
00842  *      include Socket::Constants
00843  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00844  *      sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
00845  *      socket.bind( sockaddr )
00846  *      socket.listen( 5 )
00847  *      client_fd, client_addrinfo = socket.sysaccept
00848  *      client_socket = Socket.for_fd( client_fd )
00849  *      puts "The client said, '#{client_socket.readline.chomp}'"
00850  *      client_socket.puts "Hello from script one!"
00851  *      socket.close
00852  *
00853  *      # In another script, start this second
00854  *      require 'socket'
00855  *      include Socket::Constants
00856  *      socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
00857  *      sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
00858  *      socket.connect( sockaddr )
00859  *      socket.puts "Hello from script 2."
00860  *      puts "The server said, '#{socket.readline.chomp}'"
00861  *      socket.close
00862  *
00863  * Refer to Socket#accept for the exceptions that may be thrown if the call
00864  * to _sysaccept_ fails.
00865  *
00866  * === See
00867  * * Socket#accept
00868  */
00869 static VALUE
00870 sock_sysaccept(VALUE sock)
00871 {
00872     rb_io_t *fptr;
00873     VALUE sock2;
00874     struct sockaddr_storage buf;
00875     socklen_t len = (socklen_t)sizeof buf;
00876 
00877     GetOpenFile(sock, fptr);
00878     sock2 = rsock_s_accept(0,fptr->fd,(struct sockaddr*)&buf,&len);
00879 
00880     return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, (struct sockaddr*)&buf, len));
00881 }
00882 
00883 #ifdef HAVE_GETHOSTNAME
00884 /*
00885  * call-seq:
00886  *   Socket.gethostname => hostname
00887  *
00888  * Returns the hostname.
00889  *
00890  *   p Socket.gethostname #=> "hal"
00891  *
00892  * Note that it is not guaranteed to be able to convert to IP address using gethostbyname, getaddrinfo, etc.
00893  * If you need local IP address, use Socket.ip_address_list.
00894  */
00895 static VALUE
00896 sock_gethostname(VALUE obj)
00897 {
00898 #ifndef HOST_NAME_MAX
00899 #  define HOST_NAME_MAX 1024
00900 #endif
00901     char buf[HOST_NAME_MAX+1];
00902 
00903     rb_secure(3);
00904     if (gethostname(buf, (int)sizeof buf - 1) < 0)
00905         rb_sys_fail("gethostname");
00906 
00907     buf[sizeof buf - 1] = '\0';
00908     return rb_str_new2(buf);
00909 }
00910 #else
00911 #ifdef HAVE_UNAME
00912 
00913 #include <sys/utsname.h>
00914 
00915 static VALUE
00916 sock_gethostname(VALUE obj)
00917 {
00918     struct utsname un;
00919 
00920     rb_secure(3);
00921     uname(&un);
00922     return rb_str_new2(un.nodename);
00923 }
00924 #else
00925 #define sock_gethostname rb_f_notimplement
00926 #endif
00927 #endif
00928 
00929 static VALUE
00930 make_addrinfo(struct addrinfo *res0, int norevlookup)
00931 {
00932     VALUE base, ary;
00933     struct addrinfo *res;
00934 
00935     if (res0 == NULL) {
00936         rb_raise(rb_eSocket, "host not found");
00937     }
00938     base = rb_ary_new();
00939     for (res = res0; res; res = res->ai_next) {
00940         ary = rsock_ipaddr(res->ai_addr, norevlookup);
00941         if (res->ai_canonname) {
00942             RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname);
00943         }
00944         rb_ary_push(ary, INT2FIX(res->ai_family));
00945         rb_ary_push(ary, INT2FIX(res->ai_socktype));
00946         rb_ary_push(ary, INT2FIX(res->ai_protocol));
00947         rb_ary_push(base, ary);
00948     }
00949     return base;
00950 }
00951 
00952 static VALUE
00953 sock_sockaddr(struct sockaddr *addr, size_t len)
00954 {
00955     char *ptr;
00956 
00957     switch (addr->sa_family) {
00958       case AF_INET:
00959         ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr;
00960         len = sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr);
00961         break;
00962 #ifdef AF_INET6
00963       case AF_INET6:
00964         ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr;
00965         len = sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr);
00966         break;
00967 #endif
00968       default:
00969         rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family);
00970         break;
00971     }
00972     return rb_str_new(ptr, len);
00973 }
00974 
00975 /*
00976  * call-seq:
00977  *   Socket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list]
00978  *
00979  * Obtains the host information for _hostname_.
00980  *
00981  *   p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"]
00982  *
00983  */
00984 static VALUE
00985 sock_s_gethostbyname(VALUE obj, VALUE host)
00986 {
00987     rb_secure(3);
00988     return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
00989 }
00990 
00991 /*
00992  * call-seq:
00993  *   Socket.gethostbyaddr(address_string [, address_family]) => hostent
00994  *
00995  * Obtains the host information for _address_.
00996  *
00997  *   p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
00998  *   #=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]
00999  */
01000 static VALUE
01001 sock_s_gethostbyaddr(int argc, VALUE *argv)
01002 {
01003     VALUE addr, family;
01004     struct hostent *h;
01005     char **pch;
01006     VALUE ary, names;
01007     int t = AF_INET;
01008 
01009     rb_scan_args(argc, argv, "11", &addr, &family);
01010     StringValue(addr);
01011     if (!NIL_P(family)) {
01012         t = rsock_family_arg(family);
01013     }
01014 #ifdef AF_INET6
01015     else if (RSTRING_LEN(addr) == 16) {
01016         t = AF_INET6;
01017     }
01018 #endif
01019     h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_LENINT(addr), t);
01020     if (h == NULL) {
01021 #ifdef HAVE_HSTRERROR
01022         extern int h_errno;
01023         rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno));
01024 #else
01025         rb_raise(rb_eSocket, "host not found");
01026 #endif
01027     }
01028     ary = rb_ary_new();
01029     rb_ary_push(ary, rb_str_new2(h->h_name));
01030     names = rb_ary_new();
01031     rb_ary_push(ary, names);
01032     if (h->h_aliases != NULL) {
01033         for (pch = h->h_aliases; *pch; pch++) {
01034             rb_ary_push(names, rb_str_new2(*pch));
01035         }
01036     }
01037     rb_ary_push(ary, INT2NUM(h->h_addrtype));
01038 #ifdef h_addr
01039     for (pch = h->h_addr_list; *pch; pch++) {
01040         rb_ary_push(ary, rb_str_new(*pch, h->h_length));
01041     }
01042 #else
01043     rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
01044 #endif
01045 
01046     return ary;
01047 }
01048 
01049 /*
01050  * call-seq:
01051  *   Socket.getservbyname(service_name)                => port_number
01052  *   Socket.getservbyname(service_name, protocol_name) => port_number
01053  *
01054  * Obtains the port number for _service_name_.
01055  *
01056  * If _protocol_name_ is not given, "tcp" is assumed.
01057  *
01058  *   Socket.getservbyname("smtp")          #=> 25
01059  *   Socket.getservbyname("shell")         #=> 514
01060  *   Socket.getservbyname("syslog", "udp") #=> 514
01061  */
01062 static VALUE
01063 sock_s_getservbyname(int argc, VALUE *argv)
01064 {
01065     VALUE service, proto;
01066     struct servent *sp;
01067     long port;
01068     const char *servicename, *protoname = "tcp";
01069 
01070     rb_scan_args(argc, argv, "11", &service, &proto);
01071     StringValue(service);
01072     if (!NIL_P(proto)) StringValue(proto);
01073     servicename = StringValueCStr(service);
01074     if (!NIL_P(proto)) protoname = StringValueCStr(proto);
01075     sp = getservbyname(servicename, protoname);
01076     if (sp) {
01077         port = ntohs(sp->s_port);
01078     }
01079     else {
01080         char *end;
01081 
01082         port = STRTOUL(servicename, &end, 0);
01083         if (*end != '\0') {
01084             rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname);
01085         }
01086     }
01087     return INT2FIX(port);
01088 }
01089 
01090 /*
01091  * call-seq:
01092  *   Socket.getservbyport(port [, protocol_name]) => service
01093  *
01094  * Obtains the port number for _port_.
01095  *
01096  * If _protocol_name_ is not given, "tcp" is assumed.
01097  *
01098  *   Socket.getservbyport(80)         #=> "www"
01099  *   Socket.getservbyport(514, "tcp") #=> "shell"
01100  *   Socket.getservbyport(514, "udp") #=> "syslog"
01101  *
01102  */
01103 static VALUE
01104 sock_s_getservbyport(int argc, VALUE *argv)
01105 {
01106     VALUE port, proto;
01107     struct servent *sp;
01108     long portnum;
01109     const char *protoname = "tcp";
01110 
01111     rb_scan_args(argc, argv, "11", &port, &proto);
01112     portnum = NUM2LONG(port);
01113     if (portnum != (uint16_t)portnum) {
01114         const char *s = portnum > 0 ? "big" : "small";
01115         rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s);
01116     }
01117     if (!NIL_P(proto)) protoname = StringValueCStr(proto);
01118 
01119     sp = getservbyport((int)htons((uint16_t)portnum), protoname);
01120     if (!sp) {
01121         rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname);
01122     }
01123     return rb_tainted_str_new2(sp->s_name);
01124 }
01125 
01126 /*
01127  * call-seq:
01128  *   Socket.getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags[, reverse_lookup]]]]]) => array
01129  *
01130  * Obtains address information for _nodename_:_servname_.
01131  *
01132  * _family_ should be an address family such as: :INET, :INET6, :UNIX, etc.
01133  *
01134  * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
01135  *
01136  * _protocol_ should be a protocol defined in the family,
01137  * and defaults to 0 for the family.
01138  *
01139  * _flags_ should be bitwise OR of Socket::AI_* constants.
01140  *
01141  *   Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM)
01142  *   #=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP
01143  *
01144  *   Socket.getaddrinfo("localhost", nil)
01145  *   #=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6],  # PF_INET/SOCK_STREAM/IPPROTO_TCP
01146  *   #    ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP
01147  *   #    ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]]  # PF_INET/SOCK_RAW/IPPROTO_IP
01148  *
01149  * _reverse_lookup_ directs the form of the third element, and has to
01150  * be one of below.  If _reverse_lookup_ is omitted, the default value is +nil+.
01151  *
01152  *   +true+, +:hostname+:  hostname is obtained from numeric address using reverse lookup, which may take a time.
01153  *   +false+, +:numeric+:  hostname is same as numeric address.
01154  *   +nil+:              obey to the current +do_not_reverse_lookup+ flag.
01155  *
01156  * If Addrinfo object is preferred, use Addrinfo.getaddrinfo.
01157  */
01158 static VALUE
01159 sock_s_getaddrinfo(int argc, VALUE *argv)
01160 {
01161     VALUE host, port, family, socktype, protocol, flags, ret, revlookup;
01162     struct addrinfo hints, *res;
01163     int norevlookup;
01164 
01165     rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup);
01166 
01167     MEMZERO(&hints, struct addrinfo, 1);
01168     hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
01169 
01170     if (!NIL_P(socktype)) {
01171         hints.ai_socktype = rsock_socktype_arg(socktype);
01172     }
01173     if (!NIL_P(protocol)) {
01174         hints.ai_protocol = NUM2INT(protocol);
01175     }
01176     if (!NIL_P(flags)) {
01177         hints.ai_flags = NUM2INT(flags);
01178     }
01179     if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) {
01180         norevlookup = rsock_do_not_reverse_lookup;
01181     }
01182     res = rsock_getaddrinfo(host, port, &hints, 0);
01183 
01184     ret = make_addrinfo(res, norevlookup);
01185     freeaddrinfo(res);
01186     return ret;
01187 }
01188 
01189 /*
01190  * call-seq:
01191  *   Socket.getnameinfo(sockaddr [, flags]) => [hostname, servicename]
01192  *
01193  * Obtains name information for _sockaddr_.
01194  *
01195  * _sockaddr_ should be one of follows.
01196  * - packed sockaddr string such as Socket.sockaddr_in(80, "127.0.0.1")
01197  * - 3-elements array such as ["AF_INET", 80, "127.0.0.1"]
01198  * - 4-elements array such as ["AF_INET", 80, ignored, "127.0.0.1"]
01199  *
01200  * _flags_ should be bitwise OR of Socket::NI_* constants.
01201  *
01202  * Note:
01203  * The last form is compatible with IPSocket#addr and IPSocket#peeraddr.
01204  *
01205  *   Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1"))       #=> ["localhost", "www"]
01206  *   Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"])              #=> ["localhost", "www"]
01207  *   Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"]
01208  *
01209  * If Addrinfo object is preferred, use Addrinfo#getnameinfo.
01210  */
01211 static VALUE
01212 sock_s_getnameinfo(int argc, VALUE *argv)
01213 {
01214     VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
01215     char *hptr, *pptr;
01216     char hbuf[1024], pbuf[1024];
01217     int fl;
01218     struct addrinfo hints, *res = NULL, *r;
01219     int error;
01220     struct sockaddr_storage ss;
01221     struct sockaddr *sap;
01222 
01223     sa = flags = Qnil;
01224     rb_scan_args(argc, argv, "11", &sa, &flags);
01225 
01226     fl = 0;
01227     if (!NIL_P(flags)) {
01228         fl = NUM2INT(flags);
01229     }
01230     tmp = rb_check_sockaddr_string_type(sa);
01231     if (!NIL_P(tmp)) {
01232         sa = tmp;
01233         if (sizeof(ss) < (size_t)RSTRING_LEN(sa)) {
01234             rb_raise(rb_eTypeError, "sockaddr length too big");
01235         }
01236         memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa));
01237         if ((size_t)RSTRING_LEN(sa) != SS_LEN(&ss)) {
01238             rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
01239         }
01240         sap = (struct sockaddr*)&ss;
01241         goto call_nameinfo;
01242     }
01243     tmp = rb_check_array_type(sa);
01244     if (!NIL_P(tmp)) {
01245         sa = tmp;
01246         MEMZERO(&hints, struct addrinfo, 1);
01247         if (RARRAY_LEN(sa) == 3) {
01248             af = RARRAY_PTR(sa)[0];
01249             port = RARRAY_PTR(sa)[1];
01250             host = RARRAY_PTR(sa)[2];
01251         }
01252         else if (RARRAY_LEN(sa) >= 4) {
01253             af = RARRAY_PTR(sa)[0];
01254             port = RARRAY_PTR(sa)[1];
01255             host = RARRAY_PTR(sa)[3];
01256             if (NIL_P(host)) {
01257                 host = RARRAY_PTR(sa)[2];
01258             }
01259             else {
01260                 /*
01261                  * 4th element holds numeric form, don't resolve.
01262                  * see rsock_ipaddr().
01263                  */
01264 #ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */
01265                 hints.ai_flags |= AI_NUMERICHOST;
01266 #endif
01267             }
01268         }
01269         else {
01270             rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given",
01271                      RARRAY_LEN(sa));
01272         }
01273         /* host */
01274         if (NIL_P(host)) {
01275             hptr = NULL;
01276         }
01277         else {
01278             strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
01279             hbuf[sizeof(hbuf) - 1] = '\0';
01280             hptr = hbuf;
01281         }
01282         /* port */
01283         if (NIL_P(port)) {
01284             strcpy(pbuf, "0");
01285             pptr = NULL;
01286         }
01287         else if (FIXNUM_P(port)) {
01288             snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port));
01289             pptr = pbuf;
01290         }
01291         else {
01292             strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
01293             pbuf[sizeof(pbuf) - 1] = '\0';
01294             pptr = pbuf;
01295         }
01296         hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
01297         /* af */
01298         hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
01299         error = rb_getaddrinfo(hptr, pptr, &hints, &res);
01300         if (error) goto error_exit_addr;
01301         sap = res->ai_addr;
01302     }
01303     else {
01304         rb_raise(rb_eTypeError, "expecting String or Array");
01305     }
01306 
01307   call_nameinfo:
01308     error = rb_getnameinfo(sap, SA_LEN(sap), hbuf, sizeof(hbuf),
01309                            pbuf, sizeof(pbuf), fl);
01310     if (error) goto error_exit_name;
01311     if (res) {
01312         for (r = res->ai_next; r; r = r->ai_next) {
01313             char hbuf2[1024], pbuf2[1024];
01314 
01315             sap = r->ai_addr;
01316             error = rb_getnameinfo(sap, SA_LEN(sap), hbuf2, sizeof(hbuf2),
01317                                    pbuf2, sizeof(pbuf2), fl);
01318             if (error) goto error_exit_name;
01319             if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) {
01320                 freeaddrinfo(res);
01321                 rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename");
01322             }
01323         }
01324         freeaddrinfo(res);
01325     }
01326     return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
01327 
01328   error_exit_addr:
01329     if (res) freeaddrinfo(res);
01330     rsock_raise_socket_error("getaddrinfo", error);
01331 
01332   error_exit_name:
01333     if (res) freeaddrinfo(res);
01334     rsock_raise_socket_error("getnameinfo", error);
01335 
01336     UNREACHABLE;
01337 }
01338 
01339 /*
01340  * call-seq:
01341  *   Socket.sockaddr_in(port, host)      => sockaddr
01342  *   Socket.pack_sockaddr_in(port, host) => sockaddr
01343  *
01344  * Packs _port_ and _host_ as an AF_INET/AF_INET6 sockaddr string.
01345  *
01346  *   Socket.sockaddr_in(80, "127.0.0.1")
01347  *   #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
01348  *
01349  *   Socket.sockaddr_in(80, "::1")
01350  *   #=> "\n\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
01351  *
01352  */
01353 static VALUE
01354 sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
01355 {
01356     struct addrinfo *res = rsock_addrinfo(host, port, 0, 0);
01357     VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen);
01358 
01359     freeaddrinfo(res);
01360     OBJ_INFECT(addr, port);
01361     OBJ_INFECT(addr, host);
01362 
01363     return addr;
01364 }
01365 
01366 /*
01367  * call-seq:
01368  *   Socket.unpack_sockaddr_in(sockaddr) => [port, ip_address]
01369  *
01370  * Unpacks _sockaddr_ into port and ip_address.
01371  *
01372  * _sockaddr_ should be a string or an addrinfo for AF_INET/AF_INET6.
01373  *
01374  *   sockaddr = Socket.sockaddr_in(80, "127.0.0.1")
01375  *   p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
01376  *   p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"]
01377  *
01378  */
01379 static VALUE
01380 sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
01381 {
01382     struct sockaddr_in * sockaddr;
01383     VALUE host;
01384 
01385     sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr);
01386     if (RSTRING_LEN(addr) <
01387         (char*)&((struct sockaddr *)sockaddr)->sa_family +
01388         sizeof(((struct sockaddr *)sockaddr)->sa_family) -
01389         (char*)sockaddr)
01390         rb_raise(rb_eArgError, "too short sockaddr");
01391     if (((struct sockaddr *)sockaddr)->sa_family != AF_INET
01392 #ifdef INET6
01393         && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6
01394 #endif
01395         ) {
01396 #ifdef INET6
01397         rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr");
01398 #else
01399         rb_raise(rb_eArgError, "not an AF_INET sockaddr");
01400 #endif
01401     }
01402     host = rsock_make_ipaddr((struct sockaddr*)sockaddr);
01403     OBJ_INFECT(host, addr);
01404     return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
01405 }
01406 
01407 #ifdef HAVE_SYS_UN_H
01408 
01409 /*
01410  * call-seq:
01411  *   Socket.sockaddr_un(path)      => sockaddr
01412  *   Socket.pack_sockaddr_un(path) => sockaddr
01413  *
01414  * Packs _path_ as an AF_UNIX sockaddr string.
01415  *
01416  *   Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
01417  *
01418  */
01419 static VALUE
01420 sock_s_pack_sockaddr_un(VALUE self, VALUE path)
01421 {
01422     struct sockaddr_un sockaddr;
01423     VALUE addr;
01424 
01425     StringValue(path);
01426     MEMZERO(&sockaddr, struct sockaddr_un, 1);
01427     sockaddr.sun_family = AF_UNIX;
01428     if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
01429         rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
01430             (size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path));
01431     }
01432     memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
01433     addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path));
01434     OBJ_INFECT(addr, path);
01435 
01436     return addr;
01437 }
01438 
01439 /*
01440  * call-seq:
01441  *   Socket.unpack_sockaddr_un(sockaddr) => path
01442  *
01443  * Unpacks _sockaddr_ into path.
01444  *
01445  * _sockaddr_ should be a string or an addrinfo for AF_UNIX.
01446  *
01447  *   sockaddr = Socket.sockaddr_un("/tmp/sock")
01448  *   p Socket.unpack_sockaddr_un(sockaddr) #=> "/tmp/sock"
01449  *
01450  */
01451 static VALUE
01452 sock_s_unpack_sockaddr_un(VALUE self, VALUE addr)
01453 {
01454     struct sockaddr_un * sockaddr;
01455     VALUE path;
01456 
01457     sockaddr = (struct sockaddr_un*)SockAddrStringValuePtr(addr);
01458     if (RSTRING_LEN(addr) <
01459         (char*)&((struct sockaddr *)sockaddr)->sa_family +
01460         sizeof(((struct sockaddr *)sockaddr)->sa_family) -
01461         (char*)sockaddr)
01462         rb_raise(rb_eArgError, "too short sockaddr");
01463     if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) {
01464         rb_raise(rb_eArgError, "not an AF_UNIX sockaddr");
01465     }
01466     if (sizeof(struct sockaddr_un) < (size_t)RSTRING_LEN(addr)) {
01467         rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d",
01468                  RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un));
01469     }
01470     path = rsock_unixpath_str(sockaddr, RSTRING_LENINT(addr));
01471     OBJ_INFECT(path, addr);
01472     return path;
01473 }
01474 #endif
01475 
01476 #if defined(HAVE_GETIFADDRS) || defined(SIOCGLIFCONF) || defined(SIOCGIFCONF) || defined(_WIN32)
01477 static VALUE
01478 sockaddr_obj(struct sockaddr *addr)
01479 {
01480     socklen_t len;
01481 #if defined(AF_INET6) && defined(__KAME__)
01482     struct sockaddr_in6 addr6;
01483 #endif
01484 
01485     if (addr == NULL)
01486         return Qnil;
01487 
01488     switch (addr->sa_family) {
01489       case AF_INET:
01490         len = (socklen_t)sizeof(struct sockaddr_in);
01491         break;
01492 
01493 #ifdef AF_INET6
01494       case AF_INET6:
01495         len = (socklen_t)sizeof(struct sockaddr_in6);
01496 #  ifdef __KAME__
01497         /* KAME uses the 2nd 16bit word of link local IPv6 address as interface index internally */
01498         /* http://orange.kame.net/dev/cvsweb.cgi/kame/IMPLEMENTATION */
01499         /* convert fe80:1::1 to fe80::1%1 */
01500         memcpy(&addr6, addr, len);
01501         addr = (struct sockaddr *)&addr6;
01502         if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) &&
01503             addr6.sin6_scope_id == 0 &&
01504             (addr6.sin6_addr.s6_addr[2] || addr6.sin6_addr.s6_addr[3])) {
01505             addr6.sin6_scope_id = (addr6.sin6_addr.s6_addr[2] << 8) | addr6.sin6_addr.s6_addr[3];
01506             addr6.sin6_addr.s6_addr[2] = 0;
01507             addr6.sin6_addr.s6_addr[3] = 0;
01508         }
01509 #  endif
01510         break;
01511 #endif
01512 
01513 #ifdef HAVE_SYS_UN_H
01514       case AF_UNIX:
01515         len = (socklen_t)sizeof(struct sockaddr_un);
01516         break;
01517 #endif
01518 
01519       default:
01520         len = (socklen_t)sizeof(struct sockaddr_in);
01521         break;
01522     }
01523 #ifdef SA_LEN
01524     if (len < (socklen_t)SA_LEN(addr))
01525         len = (socklen_t)SA_LEN(addr);
01526 #endif
01527 
01528     return rsock_addrinfo_new(addr, len, addr->sa_family, 0, 0, Qnil, Qnil);
01529 }
01530 #endif
01531 
01532 #if defined(HAVE_GETIFADDRS) || (defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)) || defined(SIOCGIFCONF) ||  defined(_WIN32)
01533 /*
01534  * call-seq:
01535  *   Socket.ip_address_list => array
01536  *
01537  * Returns local IP addresses as an array.
01538  *
01539  * The array contains Addrinfo objects.
01540  *
01541  *  pp Socket.ip_address_list
01542  *  #=> [#<Addrinfo: 127.0.0.1>,
01543  *       #<Addrinfo: 192.168.0.128>,
01544  *       #<Addrinfo: ::1>,
01545  *       ...]
01546  *
01547  */
01548 static VALUE
01549 socket_s_ip_address_list(VALUE self)
01550 {
01551 #if defined(HAVE_GETIFADDRS)
01552     struct ifaddrs *ifp = NULL;
01553     struct ifaddrs *p;
01554     int ret;
01555     VALUE list;
01556 
01557     ret = getifaddrs(&ifp);
01558     if (ret == -1) {
01559         rb_sys_fail("getifaddrs");
01560     }
01561 
01562     list = rb_ary_new();
01563     for (p = ifp; p; p = p->ifa_next) {
01564         if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) {
01565             rb_ary_push(list, sockaddr_obj(p->ifa_addr));
01566         }
01567     }
01568 
01569     freeifaddrs(ifp);
01570 
01571     return list;
01572 #elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && !defined(__hpux)
01573     /* Solaris if_tcp(7P) */
01574     /* HP-UX has SIOCGLIFCONF too.  But it uses different struct */
01575     int fd = -1;
01576     int ret;
01577     struct lifnum ln;
01578     struct lifconf lc;
01579     char *reason = NULL;
01580     int save_errno;
01581     int i;
01582     VALUE list = Qnil;
01583 
01584     lc.lifc_buf = NULL;
01585 
01586     fd = socket(AF_INET, SOCK_DGRAM, 0);
01587     if (fd == -1)
01588         rb_sys_fail("socket");
01589 
01590     memset(&ln, 0, sizeof(ln));
01591     ln.lifn_family = AF_UNSPEC;
01592 
01593     ret = ioctl(fd, SIOCGLIFNUM, &ln);
01594     if (ret == -1) {
01595         reason = "SIOCGLIFNUM";
01596         goto finish;
01597     }
01598 
01599     memset(&lc, 0, sizeof(lc));
01600     lc.lifc_family = AF_UNSPEC;
01601     lc.lifc_flags = 0;
01602     lc.lifc_len = sizeof(struct lifreq) * ln.lifn_count;
01603     lc.lifc_req = xmalloc(lc.lifc_len);
01604 
01605     ret = ioctl(fd, SIOCGLIFCONF, &lc);
01606     if (ret == -1) {
01607         reason = "SIOCGLIFCONF";
01608         goto finish;
01609     }
01610 
01611     list = rb_ary_new();
01612     for (i = 0; i < ln.lifn_count; i++) {
01613         struct lifreq *req = &lc.lifc_req[i];
01614         if (IS_IP_FAMILY(req->lifr_addr.ss_family)) {
01615             if (req->lifr_addr.ss_family == AF_INET6 &&
01616                 IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_addr) &&
01617                 ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id == 0) {
01618                 struct lifreq req2;
01619                 memcpy(req2.lifr_name, req->lifr_name, LIFNAMSIZ);
01620                 ret = ioctl(fd, SIOCGLIFINDEX, &req2);
01621                 if (ret == -1) {
01622                     reason = "SIOCGLIFINDEX";
01623                     goto finish;
01624                 }
01625                 ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id = req2.lifr_index;
01626             }
01627             rb_ary_push(list, sockaddr_obj((struct sockaddr *)&req->lifr_addr));
01628         }
01629     }
01630 
01631   finish:
01632     save_errno = errno;
01633     if (lc.lifc_buf != NULL)
01634         xfree(lc.lifc_req);
01635     if (fd != -1)
01636         close(fd);
01637     errno = save_errno;
01638 
01639     if (reason)
01640         rb_sys_fail(reason);
01641     return list;
01642 
01643 #elif defined(SIOCGIFCONF)
01644     int fd = -1;
01645     int ret;
01646 #define EXTRA_SPACE (sizeof(struct ifconf) + sizeof(struct sockaddr_storage))
01647     char initbuf[4096+EXTRA_SPACE];
01648     char *buf = initbuf;
01649     int bufsize;
01650     struct ifconf conf;
01651     struct ifreq *req;
01652     VALUE list = Qnil;
01653     const char *reason = NULL;
01654     int save_errno;
01655 
01656     fd = socket(AF_INET, SOCK_DGRAM, 0);
01657     if (fd == -1)
01658         rb_sys_fail("socket");
01659 
01660     bufsize = sizeof(initbuf);
01661     buf = initbuf;
01662 
01663   retry:
01664     conf.ifc_len = bufsize;
01665     conf.ifc_req = (struct ifreq *)buf;
01666 
01667     /* fprintf(stderr, "bufsize: %d\n", bufsize); */
01668 
01669     ret = ioctl(fd, SIOCGIFCONF, &conf);
01670     if (ret == -1) {
01671         reason = "SIOCGIFCONF";
01672         goto finish;
01673     }
01674 
01675     /* fprintf(stderr, "conf.ifc_len: %d\n", conf.ifc_len); */
01676 
01677     if (bufsize - EXTRA_SPACE < conf.ifc_len) {
01678         if (bufsize < conf.ifc_len) {
01679             /* NetBSD returns required size for all interfaces. */
01680             bufsize = conf.ifc_len + EXTRA_SPACE;
01681         }
01682         else {
01683             bufsize = bufsize << 1;
01684         }
01685         if (buf == initbuf)
01686             buf = NULL;
01687         buf = xrealloc(buf, bufsize);
01688         goto retry;
01689     }
01690 
01691     close(fd);
01692     fd = -1;
01693 
01694     list = rb_ary_new();
01695     req = conf.ifc_req;
01696     while ((char*)req < (char*)conf.ifc_req + conf.ifc_len) {
01697         struct sockaddr *addr = &req->ifr_addr;
01698         if (IS_IP_FAMILY(addr->sa_family)) {
01699             rb_ary_push(list, sockaddr_obj(addr));
01700         }
01701 #ifdef HAVE_SA_LEN
01702 # ifndef _SIZEOF_ADDR_IFREQ
01703 #  define _SIZEOF_ADDR_IFREQ(r) \
01704           (sizeof(struct ifreq) + \
01705            (sizeof(struct sockaddr) < (r).ifr_addr.sa_len ? \
01706             (r).ifr_addr.sa_len - sizeof(struct sockaddr) : \
01707             0))
01708 # endif
01709         req = (struct ifreq *)((char*)req + _SIZEOF_ADDR_IFREQ(*req));
01710 #else
01711         req = (struct ifreq *)((char*)req + sizeof(struct ifreq));
01712 #endif
01713     }
01714 
01715   finish:
01716 
01717     save_errno = errno;
01718     if (buf != initbuf)
01719         xfree(buf);
01720     if (fd != -1)
01721         close(fd);
01722     errno = save_errno;
01723 
01724     if (reason)
01725         rb_sys_fail(reason);
01726     return list;
01727 
01728 #undef EXTRA_SPACE
01729 #elif defined(_WIN32)
01730     typedef struct ip_adapter_unicast_address_st {
01731         unsigned LONG_LONG dummy0;
01732         struct ip_adapter_unicast_address_st *Next;
01733         struct {
01734             struct sockaddr *lpSockaddr;
01735             int iSockaddrLength;
01736         } Address;
01737         int dummy1;
01738         int dummy2;
01739         int dummy3;
01740         long dummy4;
01741         long dummy5;
01742         long dummy6;
01743     } ip_adapter_unicast_address_t;
01744     typedef struct ip_adapter_anycast_address_st {
01745         unsigned LONG_LONG dummy0;
01746         struct ip_adapter_anycast_address_st *Next;
01747         struct {
01748             struct sockaddr *lpSockaddr;
01749             int iSockaddrLength;
01750         } Address;
01751     } ip_adapter_anycast_address_t;
01752     typedef struct ip_adapter_addresses_st {
01753         unsigned LONG_LONG dummy0;
01754         struct ip_adapter_addresses_st *Next;
01755         void *dummy1;
01756         ip_adapter_unicast_address_t *FirstUnicastAddress;
01757         ip_adapter_anycast_address_t *FirstAnycastAddress;
01758         void *dummy2;
01759         void *dummy3;
01760         void *dummy4;
01761         void *dummy5;
01762         void *dummy6;
01763         BYTE dummy7[8];
01764         DWORD dummy8;
01765         DWORD dummy9;
01766         DWORD dummy10;
01767         DWORD IfType;
01768         int OperStatus;
01769         DWORD dummy12;
01770         DWORD dummy13[16];
01771         void *dummy14;
01772     } ip_adapter_addresses_t;
01773     typedef ULONG (WINAPI *GetAdaptersAddresses_t)(ULONG, ULONG, PVOID, ip_adapter_addresses_t *, PULONG);
01774     HMODULE h;
01775     GetAdaptersAddresses_t pGetAdaptersAddresses;
01776     ULONG len;
01777     DWORD ret;
01778     ip_adapter_addresses_t *adapters;
01779     VALUE list;
01780 
01781     h = LoadLibrary("iphlpapi.dll");
01782     if (!h)
01783         rb_notimplement();
01784     pGetAdaptersAddresses = (GetAdaptersAddresses_t)GetProcAddress(h, "GetAdaptersAddresses");
01785     if (!pGetAdaptersAddresses) {
01786         FreeLibrary(h);
01787         rb_notimplement();
01788     }
01789 
01790     ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len);
01791     if (ret != ERROR_SUCCESS && ret != ERROR_BUFFER_OVERFLOW) {
01792         errno = rb_w32_map_errno(ret);
01793         FreeLibrary(h);
01794         rb_sys_fail("GetAdaptersAddresses");
01795     }
01796     adapters = (ip_adapter_addresses_t *)ALLOCA_N(BYTE, len);
01797     ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &len);
01798     if (ret != ERROR_SUCCESS) {
01799         errno = rb_w32_map_errno(ret);
01800         FreeLibrary(h);
01801         rb_sys_fail("GetAdaptersAddresses");
01802     }
01803 
01804     list = rb_ary_new();
01805     for (; adapters; adapters = adapters->Next) {
01806         ip_adapter_unicast_address_t *uni;
01807         ip_adapter_anycast_address_t *any;
01808         if (adapters->OperStatus != 1)  /* 1 means IfOperStatusUp */
01809             continue;
01810         for (uni = adapters->FirstUnicastAddress; uni; uni = uni->Next) {
01811 #ifndef INET6
01812             if (uni->Address.lpSockaddr->sa_family == AF_INET)
01813 #else
01814             if (IS_IP_FAMILY(uni->Address.lpSockaddr->sa_family))
01815 #endif
01816                 rb_ary_push(list, sockaddr_obj(uni->Address.lpSockaddr));
01817         }
01818         for (any = adapters->FirstAnycastAddress; any; any = any->Next) {
01819 #ifndef INET6
01820             if (any->Address.lpSockaddr->sa_family == AF_INET)
01821 #else
01822             if (IS_IP_FAMILY(any->Address.lpSockaddr->sa_family))
01823 #endif
01824                 rb_ary_push(list, sockaddr_obj(any->Address.lpSockaddr));
01825         }
01826     }
01827 
01828     FreeLibrary(h);
01829     return list;
01830 #endif
01831 }
01832 #else
01833 #define socket_s_ip_address_list rb_f_notimplement
01834 #endif
01835 
01836 void
01837 Init_socket()
01838 {
01839     rsock_init_basicsocket();
01840 
01841     /*
01842      * Document-class: Socket < BasicSocket
01843      *
01844      * Class +Socket+ provides access to the underlying operating system
01845      * socket implementations.  It can be used to provide more operating system
01846      * specific functionality than the protocol-specific socket classes.
01847      *
01848      * The constants defined under Socket::Constants are also defined under
01849      * Socket.  For example, Socket::AF_INET is usable as well as
01850      * Socket::Constants::AF_INET.  See Socket::Constants for the list of
01851      * constants.
01852      *
01853      * === What's a socket?
01854      *
01855      * Sockets are endpoints of a bidirectionnal communication channel.
01856      * Sockets can communicate within a process, between processes on the same
01857      * machine or between different machines.  There are many types of socket:
01858      * TCPSocket, UDPSocket or UNIXSocket for example.
01859      *
01860      * Sockets have their own vocabulary:
01861      *
01862      * *domain:*
01863      * The family of protocols:
01864      * *    Socket::PF_INET
01865      * *    Socket::PF_INET6
01866      * *    Socket::PF_UNIX
01867      * *    etc.
01868      *
01869      * *type:*
01870      * The type of communications between the two endpoints, typically
01871      * *    Socket::SOCK_STREAM
01872      * *    Socket::SOCK_DGRAM.
01873      *
01874      * *protocol:*
01875      * Typically _zero_.
01876      * This may be used to identify a variant of a protocol.
01877      *
01878      * *hostname:*
01879      * The identifier of a network interface:
01880      * *    a string (hostname, IPv4 or IPv6 adress or +broadcast+
01881      *      which specifies a broadcast address)
01882      * *    a zero-length string which specifies INADDR_ANY
01883      * *    an integer (interpreted as binary address in host byte order).
01884      *
01885      * === Quick start
01886      *
01887      * Many of the classes, such as TCPSocket, UDPSocket or UNIXSocket,
01888      * ease the use of sockets comparatively to the equivalent C programming interface.
01889      *
01890      * Let's create an internet socket using the IPv4 protocol in a C-like manner:
01891      *
01892      *   s = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
01893      *   s.connect Socket.pack_sockaddr_in(80, 'example.com')
01894      *
01895      * You could also use the TCPSocket class:
01896      *
01897      *   s = TCPSocket.new 'example.com', 80
01898      *
01899      * A simple server might look like this:
01900      *
01901      *   require 'socket'
01902      *
01903      *   server = TCPServer.new 2000 # Server bound to port 2000
01904      *
01905      *   loop do
01906      *     client = server.accept    # Wait for a client to connect
01907      *     client.puts "Hello !"
01908      *     client.puts "Time is #{Time.now}"
01909      *     client.close
01910      *   end
01911      *
01912      * A simple client may look like this:
01913      *
01914      *   require 'socket'
01915      *
01916      *   s = TCPSocket.new 'localhost', 2000
01917      *
01918      *   while line = s.gets # Read lines from socket
01919      *     puts line         # and print them
01920      *   end
01921      *
01922      *   s.close             # close socket when done
01923      *
01924      * === Exception Handling
01925      *
01926      * Ruby's Socket implementation raises exceptions based on the error
01927      * generated by the system dependent implementation.  This is why the
01928      * methods are documented in a way that isolate Unix-based system
01929      * exceptions from Windows based exceptions. If more information on a
01930      * particular exception is needed, please refer to the Unix manual pages or
01931      * the Windows WinSock reference.
01932      *
01933      * === Convenience methods
01934      *
01935      * Although the general way to create socket is Socket.new,
01936      * there are several methods of socket creation for most cases.
01937      *
01938      * TCP client socket::
01939      *   Socket.tcp, TCPSocket.open
01940      * TCP server socket::
01941      *   Socket.tcp_server_loop, TCPServer.open
01942      * UNIX client socket::
01943      *   Socket.unix, UNIXSocket.open
01944      * UNIX server socket::
01945      *   Socket.unix_server_loop, UNIXServer.open
01946      *
01947      * === Documentation by
01948      *
01949      * * Zach Dennis
01950      * * Sam Roberts
01951      * * <em>Programming Ruby</em> from The Pragmatic Bookshelf.
01952      *
01953      * Much material in this documentation is taken with permission from
01954      * <em>Programming Ruby</em> from The Pragmatic Bookshelf.
01955      */
01956     rb_cSocket = rb_define_class("Socket", rb_cBasicSocket);
01957 
01958     rsock_init_socket_init();
01959 
01960     rb_define_method(rb_cSocket, "initialize", sock_initialize, -1);
01961     rb_define_method(rb_cSocket, "connect", sock_connect, 1);
01962     rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, 1);
01963     rb_define_method(rb_cSocket, "bind", sock_bind, 1);
01964     rb_define_method(rb_cSocket, "listen", rsock_sock_listen, 1);
01965     rb_define_method(rb_cSocket, "accept", sock_accept, 0);
01966     rb_define_method(rb_cSocket, "accept_nonblock", sock_accept_nonblock, 0);
01967     rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
01968 
01969     rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
01970     rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
01971 
01972     rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1);
01973     rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1);
01974     rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0);
01975     rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1);
01976     rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1);
01977     rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyname, -1);
01978     rb_define_singleton_method(rb_cSocket, "getservbyport", sock_s_getservbyport, -1);
01979     rb_define_singleton_method(rb_cSocket, "getaddrinfo", sock_s_getaddrinfo, -1);
01980     rb_define_singleton_method(rb_cSocket, "getnameinfo", sock_s_getnameinfo, -1);
01981     rb_define_singleton_method(rb_cSocket, "sockaddr_in", sock_s_pack_sockaddr_in, 2);
01982     rb_define_singleton_method(rb_cSocket, "pack_sockaddr_in", sock_s_pack_sockaddr_in, 2);
01983     rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_in", sock_s_unpack_sockaddr_in, 1);
01984 #ifdef HAVE_SYS_UN_H
01985     rb_define_singleton_method(rb_cSocket, "sockaddr_un", sock_s_pack_sockaddr_un, 1);
01986     rb_define_singleton_method(rb_cSocket, "pack_sockaddr_un", sock_s_pack_sockaddr_un, 1);
01987     rb_define_singleton_method(rb_cSocket, "unpack_sockaddr_un", sock_s_unpack_sockaddr_un, 1);
01988 #endif
01989 
01990     rb_define_singleton_method(rb_cSocket, "ip_address_list", socket_s_ip_address_list, 0);
01991 }
01992