Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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