• 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 

Generated on Thu Sep 8 2011 03:50:38 for Ruby by  doxygen 1.7.1