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