PageRenderTime 240ms CodeModel.GetById 156ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 1ms

/components/ruby-2.1.0/ext/socket/socket.c

https://github.com/jhs/ruby-inabox
C | 2123 lines | 1019 code | 156 blank | 948 comment | 191 complexity | 0e4806ab2fa7a5bb6866818eefe4d881 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/************************************************
   2
   3  socket.c -
   4
   5  created at: Thu Mar 31 12:21:29 JST 1994
   6
   7  Copyright (C) 1993-2007 Yukihiro Matsumoto
   8
   9************************************************/
  10
  11#include "rubysocket.h"
  12
  13static VALUE sock_s_unpack_sockaddr_in(VALUE, VALUE);
  14
  15void
  16rsock_sys_fail_host_port(const char *mesg, VALUE host, VALUE port)
  17{
  18    VALUE message;
  19
  20    port = rb_String(port);
  21
  22    message = rb_sprintf("%s for \"%s\" port %s",
  23	    mesg, StringValueCStr(host), StringValueCStr(port));
  24
  25    rb_sys_fail_str(message);
  26}
  27
  28void
  29rsock_sys_fail_path(const char *mesg, VALUE path)
  30{
  31    VALUE message;
  32    if (RB_TYPE_P(path, T_STRING)) {
  33        if (memchr(RSTRING_PTR(path), '\0', RSTRING_LEN(path))) {
  34            path = rb_str_inspect(path);
  35            message = rb_sprintf("%s for %s", mesg,
  36                    StringValueCStr(path));
  37        }
  38        else {
  39            message = rb_sprintf("%s for \"%s\"", mesg,
  40                    StringValueCStr(path));
  41        }
  42        rb_sys_fail_str(message);
  43    }
  44    else {
  45        rb_sys_fail(mesg);
  46    }
  47}
  48
  49void
  50rsock_sys_fail_sockaddr(const char *mesg, struct sockaddr *addr, socklen_t len)
  51{
  52    VALUE rai;
  53
  54    rai = rsock_addrinfo_new(addr, len, PF_UNSPEC, 0, 0, Qnil, Qnil);
  55
  56    rsock_sys_fail_raddrinfo(mesg, rai);
  57}
  58
  59void
  60rsock_sys_fail_raddrinfo(const char *mesg, VALUE rai)
  61{
  62    VALUE str, message;
  63
  64    str = rsock_addrinfo_inspect_sockaddr(rai);
  65    message = rb_sprintf("%s for %s", mesg, StringValueCStr(str));
  66
  67    rb_sys_fail_str(message);
  68}
  69
  70void
  71rsock_sys_fail_raddrinfo_or_sockaddr(const char *mesg, VALUE addr, VALUE rai)
  72{
  73    if (NIL_P(rai)) {
  74        StringValue(addr);
  75        rsock_sys_fail_sockaddr(mesg,
  76            (struct sockaddr *)RSTRING_PTR(addr),
  77            (socklen_t)RSTRING_LEN(addr)); /* overflow should be checked already */
  78    }
  79    else
  80        rsock_sys_fail_raddrinfo(mesg, rai);
  81}
  82
  83static void
  84setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv)
  85{
  86    *dv = rsock_family_arg(domain);
  87    *tv = rsock_socktype_arg(type);
  88}
  89
  90/*
  91 * call-seq:
  92 *   Socket.new(domain, socktype [, protocol]) => socket
  93 *
  94 * Creates a new socket object.
  95 *
  96 * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc.
  97 *
  98 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
  99 *
 100 * _protocol_ is optional and should be a protocol defined in the domain.
 101 * If protocol is not given, 0 is used internally.
 102 *
 103 *   Socket.new(:INET, :STREAM) # TCP socket
 104 *   Socket.new(:INET, :DGRAM)  # UDP socket
 105 *   Socket.new(:UNIX, :STREAM) # UNIX stream socket
 106 *   Socket.new(:UNIX, :DGRAM)  # UNIX datagram socket
 107 */
 108static VALUE
 109sock_initialize(int argc, VALUE *argv, VALUE sock)
 110{
 111    VALUE domain, type, protocol;
 112    int fd;
 113    int d, t;
 114
 115    rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
 116    if (NIL_P(protocol))
 117        protocol = INT2FIX(0);
 118
 119    rb_secure(3);
 120    setup_domain_and_type(domain, &d, type, &t);
 121    fd = rsock_socket(d, t, NUM2INT(protocol));
 122    if (fd < 0) rb_sys_fail("socket(2)");
 123
 124    return rsock_init_sock(sock, fd);
 125}
 126
 127#if defined HAVE_SOCKETPAIR
 128static VALUE
 129io_call_close(VALUE io)
 130{
 131    return rb_funcall(io, rb_intern("close"), 0, 0);
 132}
 133
 134static VALUE
 135io_close(VALUE io)
 136{
 137    return rb_rescue(io_call_close, io, 0, 0);
 138}
 139
 140static VALUE
 141pair_yield(VALUE pair)
 142{
 143    return rb_ensure(rb_yield, pair, io_close, rb_ary_entry(pair, 1));
 144}
 145#endif
 146
 147#if defined HAVE_SOCKETPAIR
 148
 149static int
 150rsock_socketpair0(int domain, int type, int protocol, int sv[2])
 151{
 152    int ret;
 153
 154#ifdef SOCK_CLOEXEC
 155    static int try_sock_cloexec = 1;
 156    if (try_sock_cloexec) {
 157        ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
 158        if (ret == -1 && errno == EINVAL) {
 159            /* SOCK_CLOEXEC is available since Linux 2.6.27.  Linux 2.6.18 fails with EINVAL */
 160            ret = socketpair(domain, type, protocol, sv);
 161            if (ret != -1) {
 162                /* The reason of EINVAL may be other than SOCK_CLOEXEC.
 163                 * So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC.
 164                 * Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL.
 165                 */
 166                try_sock_cloexec = 0;
 167            }
 168        }
 169    }
 170    else {
 171        ret = socketpair(domain, type, protocol, sv);
 172    }
 173#else
 174    ret = socketpair(domain, type, protocol, sv);
 175#endif
 176
 177    if (ret == -1) {
 178        return -1;
 179    }
 180
 181    rb_fd_fix_cloexec(sv[0]);
 182    rb_fd_fix_cloexec(sv[1]);
 183
 184    return ret;
 185}
 186
 187static int
 188rsock_socketpair(int domain, int type, int protocol, int sv[2])
 189{
 190    int ret;
 191
 192    ret = rsock_socketpair0(domain, type, protocol, sv);
 193    if (ret < 0 && (errno == EMFILE || errno == ENFILE)) {
 194        rb_gc();
 195        ret = rsock_socketpair0(domain, type, protocol, sv);
 196    }
 197
 198    return ret;
 199}
 200
 201/*
 202 * call-seq:
 203 *   Socket.pair(domain, type, protocol)       => [socket1, socket2]
 204 *   Socket.socketpair(domain, type, protocol) => [socket1, socket2]
 205 *
 206 * Creates a pair of sockets connected each other.
 207 *
 208 * _domain_ should be a communications domain such as: :INET, :INET6, :UNIX, etc.
 209 *
 210 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
 211 *
 212 * _protocol_ should be a protocol defined in the domain,
 213 * defaults to 0 for the domain.
 214 *
 215 *   s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
 216 *   s1.send "a", 0
 217 *   s1.send "b", 0
 218 *   s1.close
 219 *   p s2.recv(10) #=> "ab"
 220 *   p s2.recv(10) #=> ""
 221 *   p s2.recv(10) #=> ""
 222 *
 223 *   s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
 224 *   s1.send "a", 0
 225 *   s1.send "b", 0
 226 *   p s2.recv(10) #=> "a"
 227 *   p s2.recv(10) #=> "b"
 228 *
 229 */
 230VALUE
 231rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
 232{
 233    VALUE domain, type, protocol;
 234    int d, t, p, sp[2];
 235    int ret;
 236    VALUE s1, s2, r;
 237
 238    rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
 239    if (NIL_P(protocol))
 240        protocol = INT2FIX(0);
 241
 242    setup_domain_and_type(domain, &d, type, &t);
 243    p = NUM2INT(protocol);
 244    ret = rsock_socketpair(d, t, p, sp);
 245    if (ret < 0) {
 246	rb_sys_fail("socketpair(2)");
 247    }
 248    rb_fd_fix_cloexec(sp[0]);
 249    rb_fd_fix_cloexec(sp[1]);
 250
 251    s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
 252    s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
 253    r = rb_assoc_new(s1, s2);
 254    if (rb_block_given_p()) {
 255        return rb_ensure(pair_yield, r, io_close, s1);
 256    }
 257    return r;
 258}
 259#else
 260#define rsock_sock_s_socketpair rb_f_notimplement
 261#endif
 262
 263/*
 264 * call-seq:
 265 *   socket.connect(remote_sockaddr) => 0
 266 *
 267 * Requests a connection to be made on the given +remote_sockaddr+. Returns 0 if
 268 * successful, otherwise an exception is raised.
 269 *
 270 * === Parameter
 271 * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
 272 *
 273 * === Example:
 274 * 	# Pull down Google's web page
 275 * 	require 'socket'
 276 * 	include Socket::Constants
 277 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 278 * 	sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
 279 * 	socket.connect( sockaddr )
 280 * 	socket.write( "GET / HTTP/1.0\r\n\r\n" )
 281 * 	results = socket.read
 282 *
 283 * === Unix-based Exceptions
 284 * On unix-based systems the following system exceptions may be raised if
 285 * the call to _connect_ fails:
 286 * * Errno::EACCES - search permission is denied for a component of the prefix
 287 *   path or write access to the +socket+ is denied
 288 * * Errno::EADDRINUSE - the _sockaddr_ is already in use
 289 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
 290 *   local machine
 291 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for
 292 *   the address family of the specified +socket+
 293 * * Errno::EALREADY - a connection is already in progress for the specified
 294 *   socket
 295 * * Errno::EBADF - the +socket+ is not a valid file descriptor
 296 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
 297 *   refused the connection request
 298 * * Errno::ECONNRESET - the remote host reset the connection request
 299 * * Errno::EFAULT - the _sockaddr_ cannot be accessed
 300 * * Errno::EHOSTUNREACH - the destination host cannot be reached (probably
 301 *   because the host is down or a remote router cannot reach it)
 302 * * Errno::EINPROGRESS - the O_NONBLOCK is set for the +socket+ and the
 303 *   connection cannot be immediately established; the connection will be
 304 *   established asynchronously
 305 * * Errno::EINTR - the attempt to establish the connection was interrupted by
 306 *   delivery of a signal that was caught; the connection will be established
 307 *   asynchronously
 308 * * Errno::EISCONN - the specified +socket+ is already connected
 309 * * Errno::EINVAL - the address length used for the _sockaddr_ is not a valid
 310 *   length for the address family or there is an invalid family in _sockaddr_
 311 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
 312 *   PATH_MAX
 313 * * Errno::ENETDOWN - the local interface used to reach the destination is down
 314 * * Errno::ENETUNREACH - no route to the network is present
 315 * * Errno::ENOBUFS - no buffer space is available
 316 * * Errno::ENOSR - there were insufficient STREAMS resources available to
 317 *   complete the operation
 318 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
 319 * * Errno::EOPNOTSUPP - the calling +socket+ is listening and cannot be connected
 320 * * Errno::EPROTOTYPE - the _sockaddr_ has a different type than the socket
 321 *   bound to the specified peer address
 322 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
 323 *   was made.
 324 *
 325 * On unix-based systems if the address family of the calling +socket+ is
 326 * AF_UNIX the follow exceptions may be raised if the call to _connect_
 327 * fails:
 328 * * Errno::EIO - an i/o error occurred while reading from or writing to the
 329 *   file system
 330 * * Errno::ELOOP - too many symbolic links were encountered in translating
 331 *   the pathname in _sockaddr_
 332 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
 333 *   characters, or an entire pathname exceeded PATH_MAX characters
 334 * * Errno::ENOENT - a component of the pathname does not name an existing file
 335 *   or the pathname is an empty string
 336 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
 337 *   is not a directory
 338 *
 339 * === Windows Exceptions
 340 * On Windows systems the following system exceptions may be raised if
 341 * the call to _connect_ fails:
 342 * * Errno::ENETDOWN - the network is down
 343 * * Errno::EADDRINUSE - the socket's local address is already in use
 344 * * Errno::EINTR - the socket was cancelled
 345 * * Errno::EINPROGRESS - a blocking socket is in progress or the service provider
 346 *   is still processing a callback function. Or a nonblocking connect call is
 347 *   in progress on the +socket+.
 348 * * Errno::EALREADY - see Errno::EINVAL
 349 * * Errno::EADDRNOTAVAIL - the remote address is not a valid address, such as
 350 *   ADDR_ANY TODO check ADDRANY TO INADDR_ANY
 351 * * Errno::EAFNOSUPPORT - addresses in the specified family cannot be used with
 352 *   with this +socket+
 353 * * Errno::ECONNREFUSED - the target _sockaddr_ was not listening for connections
 354 *   refused the connection request
 355 * * Errno::EFAULT - the socket's internal address or address length parameter
 356 *   is too small or is not a valid part of the user space address
 357 * * Errno::EINVAL - the +socket+ is a listening socket
 358 * * Errno::EISCONN - the +socket+ is already connected
 359 * * Errno::ENETUNREACH - the network cannot be reached from this host at this time
 360 * * Errno::EHOSTUNREACH - no route to the network is present
 361 * * Errno::ENOBUFS - no buffer space is available
 362 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
 363 * * Errno::ETIMEDOUT - the attempt to connect time out before a connection
 364 *   was made.
 365 * * Errno::EWOULDBLOCK - the socket is marked as nonblocking and the
 366 *   connection cannot be completed immediately
 367 * * Errno::EACCES - the attempt to connect the datagram socket to the
 368 *   broadcast address failed
 369 *
 370 * === See
 371 * * connect manual pages on unix-based systems
 372 * * connect function in Microsoft's Winsock functions reference
 373 */
 374static VALUE
 375sock_connect(VALUE sock, VALUE addr)
 376{
 377    VALUE rai;
 378    rb_io_t *fptr;
 379    int fd, n;
 380
 381    SockAddrStringValueWithAddrinfo(addr, rai);
 382    addr = rb_str_new4(addr);
 383    GetOpenFile(sock, fptr);
 384    fd = fptr->fd;
 385    n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0);
 386    if (n < 0) {
 387	rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
 388    }
 389
 390    return INT2FIX(n);
 391}
 392
 393/*
 394 * call-seq:
 395 *   socket.connect_nonblock(remote_sockaddr) => 0
 396 *
 397 * Requests a connection to be made on the given +remote_sockaddr+ after
 398 * O_NONBLOCK is set for the underlying file descriptor.
 399 * Returns 0 if successful, otherwise an exception is raised.
 400 *
 401 * === Parameter
 402 * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object
 403 *
 404 * === Example:
 405 * 	# Pull down Google's web page
 406 * 	require 'socket'
 407 * 	include Socket::Constants
 408 * 	socket = Socket.new(AF_INET, SOCK_STREAM, 0)
 409 * 	sockaddr = Socket.sockaddr_in(80, 'www.google.com')
 410 * 	begin # emulate blocking connect
 411 * 	  socket.connect_nonblock(sockaddr)
 412 * 	rescue IO::WaitWritable
 413 * 	  IO.select(nil, [socket]) # wait 3-way handshake completion
 414 * 	  begin
 415 * 	    socket.connect_nonblock(sockaddr) # check connection failure
 416 * 	  rescue Errno::EISCONN
 417 * 	  end
 418 * 	end
 419 * 	socket.write("GET / HTTP/1.0\r\n\r\n")
 420 * 	results = socket.read
 421 *
 422 * Refer to Socket#connect for the exceptions that may be thrown if the call
 423 * to _connect_nonblock_ fails.
 424 *
 425 * Socket#connect_nonblock may raise any error corresponding to connect(2) failure,
 426 * including Errno::EINPROGRESS.
 427 *
 428 * If the exception is Errno::EINPROGRESS,
 429 * it is extended by IO::WaitWritable.
 430 * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock.
 431 *
 432 * === See
 433 * * Socket#connect
 434 */
 435static VALUE
 436sock_connect_nonblock(VALUE sock, VALUE addr)
 437{
 438    VALUE rai;
 439    rb_io_t *fptr;
 440    int n;
 441
 442    SockAddrStringValueWithAddrinfo(addr, rai);
 443    addr = rb_str_new4(addr);
 444    GetOpenFile(sock, fptr);
 445    rb_io_set_nonblock(fptr);
 446    n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr));
 447    if (n < 0) {
 448        if (errno == EINPROGRESS)
 449            rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "connect(2) would block");
 450	rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
 451    }
 452
 453    return INT2FIX(n);
 454}
 455
 456/*
 457 * call-seq:
 458 *   socket.bind(local_sockaddr) => 0
 459 *
 460 * Binds to the given local address.
 461 *
 462 * === Parameter
 463 * * +local_sockaddr+ - the +struct+ sockaddr contained in a string or an Addrinfo object
 464 *
 465 * === Example
 466 * 	require 'socket'
 467 *
 468 * 	# use Addrinfo
 469 * 	socket = Socket.new(:INET, :STREAM, 0)
 470 * 	socket.bind(Addrinfo.tcp("127.0.0.1", 2222))
 471 * 	p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP>
 472 *
 473 * 	# use struct sockaddr
 474 * 	include Socket::Constants
 475 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 476 * 	sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
 477 * 	socket.bind( sockaddr )
 478 *
 479 * === Unix-based Exceptions
 480 * On unix-based based systems the following system exceptions may be raised if
 481 * the call to _bind_ fails:
 482 * * Errno::EACCES - the specified _sockaddr_ is protected and the current
 483 *   user does not have permission to bind to it
 484 * * Errno::EADDRINUSE - the specified _sockaddr_ is already in use
 485 * * Errno::EADDRNOTAVAIL - the specified _sockaddr_ is not available from the
 486 *   local machine
 487 * * Errno::EAFNOSUPPORT - the specified _sockaddr_ is not a valid address for
 488 *   the family of the calling +socket+
 489 * * Errno::EBADF - the _sockaddr_ specified is not a valid file descriptor
 490 * * Errno::EFAULT - the _sockaddr_ argument cannot be accessed
 491 * * Errno::EINVAL - the +socket+ is already bound to an address, and the
 492 *   protocol does not support binding to the new _sockaddr_ or the +socket+
 493 *   has been shut down.
 494 * * Errno::EINVAL - the address length is not a valid length for the address
 495 *   family
 496 * * Errno::ENAMETOOLONG - the pathname resolved had a length which exceeded
 497 *   PATH_MAX
 498 * * Errno::ENOBUFS - no buffer space is available
 499 * * Errno::ENOSR - there were insufficient STREAMS resources available to
 500 *   complete the operation
 501 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
 502 * * Errno::EOPNOTSUPP - the socket type of the +socket+ does not support
 503 *   binding to an address
 504 *
 505 * On unix-based based systems if the address family of the calling +socket+ is
 506 * Socket::AF_UNIX the follow exceptions may be raised if the call to _bind_
 507 * fails:
 508 * * Errno::EACCES - search permission is denied for a component of the prefix
 509 *   path or write access to the +socket+ is denied
 510 * * Errno::EDESTADDRREQ - the _sockaddr_ argument is a null pointer
 511 * * Errno::EISDIR - same as Errno::EDESTADDRREQ
 512 * * Errno::EIO - an i/o error occurred
 513 * * Errno::ELOOP - too many symbolic links were encountered in translating
 514 *   the pathname in _sockaddr_
 515 * * Errno::ENAMETOOLLONG - a component of a pathname exceeded NAME_MAX
 516 *   characters, or an entire pathname exceeded PATH_MAX characters
 517 * * Errno::ENOENT - a component of the pathname does not name an existing file
 518 *   or the pathname is an empty string
 519 * * Errno::ENOTDIR - a component of the path prefix of the pathname in _sockaddr_
 520 *   is not a directory
 521 * * Errno::EROFS - the name would reside on a read only filesystem
 522 *
 523 * === Windows Exceptions
 524 * On Windows systems the following system exceptions may be raised if
 525 * the call to _bind_ fails:
 526 * * Errno::ENETDOWN-- the network is down
 527 * * Errno::EACCES - the attempt to connect the datagram socket to the
 528 *   broadcast address failed
 529 * * Errno::EADDRINUSE - the socket's local address is already in use
 530 * * Errno::EADDRNOTAVAIL - the specified address is not a valid address for this
 531 *   computer
 532 * * Errno::EFAULT - the socket's internal address or address length parameter
 533 *   is too small or is not a valid part of the user space addressed
 534 * * Errno::EINVAL - the +socket+ is already bound to an address
 535 * * Errno::ENOBUFS - no buffer space is available
 536 * * Errno::ENOTSOCK - the +socket+ argument does not refer to a socket
 537 *
 538 * === See
 539 * * bind manual pages on unix-based systems
 540 * * bind function in Microsoft's Winsock functions reference
 541 */
 542static VALUE
 543sock_bind(VALUE sock, VALUE addr)
 544{
 545    VALUE rai;
 546    rb_io_t *fptr;
 547
 548    SockAddrStringValueWithAddrinfo(addr, rai);
 549    GetOpenFile(sock, fptr);
 550    if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr)) < 0)
 551	rsock_sys_fail_raddrinfo_or_sockaddr("bind(2)", addr, rai);
 552
 553    return INT2FIX(0);
 554}
 555
 556/*
 557 * call-seq:
 558 *   socket.listen( int ) => 0
 559 *
 560 * Listens for connections, using the specified +int+ as the backlog. A call
 561 * to _listen_ only applies if the +socket+ is of type SOCK_STREAM or
 562 * SOCK_SEQPACKET.
 563 *
 564 * === Parameter
 565 * * +backlog+ - the maximum length of the queue for pending connections.
 566 *
 567 * === Example 1
 568 * 	require 'socket'
 569 * 	include Socket::Constants
 570 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 571 * 	sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
 572 * 	socket.bind( sockaddr )
 573 * 	socket.listen( 5 )
 574 *
 575 * === Example 2 (listening on an arbitrary port, unix-based systems only):
 576 * 	require 'socket'
 577 * 	include Socket::Constants
 578 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 579 * 	socket.listen( 1 )
 580 *
 581 * === Unix-based Exceptions
 582 * On unix based systems the above will work because a new +sockaddr+ struct
 583 * is created on the address ADDR_ANY, for an arbitrary port number as handed
 584 * off by the kernel. It will not work on Windows, because Windows requires that
 585 * the +socket+ is bound by calling _bind_ before it can _listen_.
 586 *
 587 * If the _backlog_ amount exceeds the implementation-dependent maximum
 588 * queue length, the implementation's maximum queue length will be used.
 589 *
 590 * On unix-based based systems the following system exceptions may be raised if the
 591 * call to _listen_ fails:
 592 * * Errno::EBADF - the _socket_ argument is not a valid file descriptor
 593 * * Errno::EDESTADDRREQ - the _socket_ is not bound to a local address, and
 594 *   the protocol does not support listening on an unbound socket
 595 * * Errno::EINVAL - the _socket_ is already connected
 596 * * Errno::ENOTSOCK - the _socket_ argument does not refer to a socket
 597 * * Errno::EOPNOTSUPP - the _socket_ protocol does not support listen
 598 * * Errno::EACCES - the calling process does not have appropriate privileges
 599 * * Errno::EINVAL - the _socket_ has been shut down
 600 * * Errno::ENOBUFS - insufficient resources are available in the system to
 601 *   complete the call
 602 *
 603 * === Windows Exceptions
 604 * On Windows systems the following system exceptions may be raised if
 605 * the call to _listen_ fails:
 606 * * Errno::ENETDOWN - the network is down
 607 * * Errno::EADDRINUSE - the socket's local address is already in use. This
 608 *   usually occurs during the execution of _bind_ but could be delayed
 609 *   if the call to _bind_ was to a partially wildcard address (involving
 610 *   ADDR_ANY) and if a specific address needs to be committed at the
 611 *   time of the call to _listen_
 612 * * Errno::EINPROGRESS - a Windows Sockets 1.1 call is in progress or the
 613 *   service provider is still processing a callback function
 614 * * Errno::EINVAL - the +socket+ has not been bound with a call to _bind_.
 615 * * Errno::EISCONN - the +socket+ is already connected
 616 * * Errno::EMFILE - no more socket descriptors are available
 617 * * Errno::ENOBUFS - no buffer space is available
 618 * * Errno::ENOTSOC - +socket+ is not a socket
 619 * * Errno::EOPNOTSUPP - the referenced +socket+ is not a type that supports
 620 *   the _listen_ method
 621 *
 622 * === See
 623 * * listen manual pages on unix-based systems
 624 * * listen function in Microsoft's Winsock functions reference
 625 */
 626VALUE
 627rsock_sock_listen(VALUE sock, VALUE log)
 628{
 629    rb_io_t *fptr;
 630    int backlog;
 631
 632    backlog = NUM2INT(log);
 633    GetOpenFile(sock, fptr);
 634    if (listen(fptr->fd, backlog) < 0)
 635	rb_sys_fail("listen(2)");
 636
 637    return INT2FIX(0);
 638}
 639
 640/*
 641 * call-seq:
 642 *   socket.recvfrom(maxlen) => [mesg, sender_addrinfo]
 643 *   socket.recvfrom(maxlen, flags) => [mesg, sender_addrinfo]
 644 *
 645 * Receives up to _maxlen_ bytes from +socket+. _flags_ is zero or more
 646 * of the +MSG_+ options. The first element of the results, _mesg_, is the data
 647 * received. The second element, _sender_addrinfo_, contains protocol-specific
 648 * address information of the sender.
 649 *
 650 * === Parameters
 651 * * +maxlen+ - the maximum number of bytes to receive from the socket
 652 * * +flags+ - zero or more of the +MSG_+ options
 653 *
 654 * === Example
 655 * 	# In one file, start this first
 656 * 	require 'socket'
 657 * 	include Socket::Constants
 658 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 659 * 	sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
 660 * 	socket.bind( sockaddr )
 661 * 	socket.listen( 5 )
 662 * 	client, client_addrinfo = socket.accept
 663 * 	data = client.recvfrom( 20 )[0].chomp
 664 * 	puts "I only received 20 bytes '#{data}'"
 665 * 	sleep 1
 666 * 	socket.close
 667 *
 668 * 	# In another file, start this second
 669 * 	require 'socket'
 670 * 	include Socket::Constants
 671 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 672 * 	sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
 673 * 	socket.connect( sockaddr )
 674 * 	socket.puts "Watch this get cut short!"
 675 * 	socket.close
 676 *
 677 * === Unix-based Exceptions
 678 * On unix-based based systems the following system exceptions may be raised if the
 679 * call to _recvfrom_ fails:
 680 * * Errno::EAGAIN - the +socket+ file descriptor is marked as O_NONBLOCK and no
 681 *   data is waiting to be received; or MSG_OOB is set and no out-of-band data
 682 *   is available and either the +socket+ file descriptor is marked as
 683 *   O_NONBLOCK or the +socket+ does not support blocking to wait for
 684 *   out-of-band-data
 685 * * Errno::EWOULDBLOCK - see Errno::EAGAIN
 686 * * Errno::EBADF - the +socket+ is not a valid file descriptor
 687 * * Errno::ECONNRESET - a connection was forcibly closed by a peer
 688 * * Errno::EFAULT - the socket's internal buffer, address or address length
 689 *   cannot be accessed or written
 690 * * Errno::EINTR - a signal interrupted _recvfrom_ before any data was available
 691 * * Errno::EINVAL - the MSG_OOB flag is set and no out-of-band data is available
 692 * * Errno::EIO - an i/o error occurred while reading from or writing to the
 693 *   filesystem
 694 * * Errno::ENOBUFS - insufficient resources were available in the system to
 695 *   perform the operation
 696 * * Errno::ENOMEM - insufficient memory was available to fulfill the request
 697 * * Errno::ENOSR - there were insufficient STREAMS resources available to
 698 *   complete the operation
 699 * * Errno::ENOTCONN - a receive is attempted on a connection-mode socket that
 700 *   is not connected
 701 * * Errno::ENOTSOCK - the +socket+ does not refer to a socket
 702 * * Errno::EOPNOTSUPP - the specified flags are not supported for this socket type
 703 * * Errno::ETIMEDOUT - the connection timed out during connection establishment
 704 *   or due to a transmission timeout on an active connection
 705 *
 706 * === Windows Exceptions
 707 * On Windows systems the following system exceptions may be raised if
 708 * the call to _recvfrom_ fails:
 709 * * Errno::ENETDOWN - the network is down
 710 * * Errno::EFAULT - the internal buffer and from parameters on +socket+ are not
 711 *   part of the user address space, or the internal fromlen parameter is
 712 *   too small to accommodate the peer address
 713 * * Errno::EINTR - the (blocking) call was cancelled by an internal call to
 714 *   the WinSock function WSACancelBlockingCall
 715 * * Errno::EINPROGRESS - a blocking Windows Sockets 1.1 call is in progress or
 716 *   the service provider is still processing a callback function
 717 * * Errno::EINVAL - +socket+ has not been bound with a call to _bind_, or an
 718 *   unknown flag was specified, or MSG_OOB was specified for a socket with
 719 *   SO_OOBINLINE enabled, or (for byte stream-style sockets only) the internal
 720 *   len parameter on +socket+ was zero or negative
 721 * * Errno::EISCONN - +socket+ is already connected. The call to _recvfrom_ is
 722 *   not permitted with a connected socket on a socket that is connection
 723 *   oriented or connectionless.
 724 * * Errno::ENETRESET - the connection has been broken due to the keep-alive
 725 *   activity detecting a failure while the operation was in progress.
 726 * * Errno::EOPNOTSUPP - MSG_OOB was specified, but +socket+ is not stream-style
 727 *   such as type SOCK_STREAM. OOB data is not supported in the communication
 728 *   domain associated with +socket+, or +socket+ is unidirectional and
 729 *   supports only send operations
 730 * * Errno::ESHUTDOWN - +socket+ has been shutdown. It is not possible to
 731 *   call _recvfrom_ on a socket after _shutdown_ has been invoked.
 732 * * Errno::EWOULDBLOCK - +socket+ is marked as nonblocking and a  call to
 733 *   _recvfrom_ would block.
 734 * * Errno::EMSGSIZE - the message was too large to fit into the specified buffer
 735 *   and was truncated.
 736 * * Errno::ETIMEDOUT - the connection has been dropped, because of a network
 737 *   failure or because the system on the other end went down without
 738 *   notice
 739 * * Errno::ECONNRESET - the virtual circuit was reset by the remote side
 740 *   executing a hard or abortive close. The application should close the
 741 *   socket; it is no longer usable. On a UDP-datagram socket this error
 742 *   indicates a previous send operation resulted in an ICMP Port Unreachable
 743 *   message.
 744 */
 745static VALUE
 746sock_recvfrom(int argc, VALUE *argv, VALUE sock)
 747{
 748    return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
 749}
 750
 751/*
 752 * call-seq:
 753 *   socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
 754 *   socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
 755 *
 756 * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
 757 * O_NONBLOCK is set for the underlying file descriptor.
 758 * _flags_ is zero or more of the +MSG_+ options.
 759 * The first element of the results, _mesg_, is the data received.
 760 * The second element, _sender_addrinfo_, contains protocol-specific address
 761 * information of the sender.
 762 *
 763 * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
 764 * an empty string as data.
 765 * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
 766 *
 767 * === Parameters
 768 * * +maxlen+ - the maximum number of bytes to receive from the socket
 769 * * +flags+ - zero or more of the +MSG_+ options
 770 *
 771 * === Example
 772 * 	# In one file, start this first
 773 * 	require 'socket'
 774 * 	include Socket::Constants
 775 * 	socket = Socket.new(AF_INET, SOCK_STREAM, 0)
 776 * 	sockaddr = Socket.sockaddr_in(2200, 'localhost')
 777 * 	socket.bind(sockaddr)
 778 * 	socket.listen(5)
 779 * 	client, client_addrinfo = socket.accept
 780 * 	begin # emulate blocking recvfrom
 781 * 	  pair = client.recvfrom_nonblock(20)
 782 * 	rescue IO::WaitReadable
 783 * 	  IO.select([client])
 784 * 	  retry
 785 * 	end
 786 * 	data = pair[0].chomp
 787 * 	puts "I only received 20 bytes '#{data}'"
 788 * 	sleep 1
 789 * 	socket.close
 790 *
 791 * 	# In another file, start this second
 792 * 	require 'socket'
 793 * 	include Socket::Constants
 794 * 	socket = Socket.new(AF_INET, SOCK_STREAM, 0)
 795 * 	sockaddr = Socket.sockaddr_in(2200, 'localhost')
 796 * 	socket.connect(sockaddr)
 797 * 	socket.puts "Watch this get cut short!"
 798 * 	socket.close
 799 *
 800 * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
 801 * to _recvfrom_nonblock_ fails.
 802 *
 803 * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
 804 * including Errno::EWOULDBLOCK.
 805 *
 806 * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
 807 * it is extended by IO::WaitReadable.
 808 * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
 809 *
 810 * === See
 811 * * Socket#recvfrom
 812 */
 813static VALUE
 814sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
 815{
 816    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
 817}
 818
 819/*
 820 * call-seq:
 821 *   socket.accept => [client_socket, client_addrinfo]
 822 *
 823 * Accepts a next connection.
 824 * Returns a new Socket object and Addrinfo object.
 825 *
 826 *   serv = Socket.new(:INET, :STREAM, 0)
 827 *   serv.listen(5)
 828 *   c = Socket.new(:INET, :STREAM, 0)
 829 *   c.connect(serv.connect_address)
 830 *   p serv.accept #=> [#<Socket:fd 6>, #<Addrinfo: 127.0.0.1:48555 TCP>]
 831 *
 832 */
 833static VALUE
 834sock_accept(VALUE sock)
 835{
 836    rb_io_t *fptr;
 837    VALUE sock2;
 838    union_sockaddr buf;
 839    socklen_t len = (socklen_t)sizeof buf;
 840
 841    GetOpenFile(sock, fptr);
 842    sock2 = rsock_s_accept(rb_cSocket,fptr->fd,&buf.addr,&len);
 843
 844    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
 845}
 846
 847/*
 848 * call-seq:
 849 *   socket.accept_nonblock => [client_socket, client_addrinfo]
 850 *
 851 * Accepts an incoming connection using accept(2) after
 852 * O_NONBLOCK is set for the underlying file descriptor.
 853 * It returns an array containing the accepted socket
 854 * for the incoming connection, _client_socket_,
 855 * and an Addrinfo, _client_addrinfo_.
 856 *
 857 * === Example
 858 * 	# In one script, start this first
 859 * 	require 'socket'
 860 * 	include Socket::Constants
 861 * 	socket = Socket.new(AF_INET, SOCK_STREAM, 0)
 862 * 	sockaddr = Socket.sockaddr_in(2200, 'localhost')
 863 * 	socket.bind(sockaddr)
 864 * 	socket.listen(5)
 865 * 	begin # emulate blocking accept
 866 * 	  client_socket, client_addrinfo = socket.accept_nonblock
 867 * 	rescue IO::WaitReadable, Errno::EINTR
 868 * 	  IO.select([socket])
 869 * 	  retry
 870 * 	end
 871 * 	puts "The client said, '#{client_socket.readline.chomp}'"
 872 * 	client_socket.puts "Hello from script one!"
 873 * 	socket.close
 874 *
 875 * 	# In another script, start this second
 876 * 	require 'socket'
 877 * 	include Socket::Constants
 878 * 	socket = Socket.new(AF_INET, SOCK_STREAM, 0)
 879 * 	sockaddr = Socket.sockaddr_in(2200, 'localhost')
 880 * 	socket.connect(sockaddr)
 881 * 	socket.puts "Hello from script 2."
 882 * 	puts "The server said, '#{socket.readline.chomp}'"
 883 * 	socket.close
 884 *
 885 * Refer to Socket#accept for the exceptions that may be thrown if the call
 886 * to _accept_nonblock_ fails.
 887 *
 888 * Socket#accept_nonblock may raise any error corresponding to accept(2) failure,
 889 * including Errno::EWOULDBLOCK.
 890 *
 891 * If the exception is Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED or Errno::EPROTO,
 892 * it is extended by IO::WaitReadable.
 893 * So IO::WaitReadable can be used to rescue the exceptions for retrying accept_nonblock.
 894 *
 895 * === See
 896 * * Socket#accept
 897 */
 898static VALUE
 899sock_accept_nonblock(VALUE sock)
 900{
 901    rb_io_t *fptr;
 902    VALUE sock2;
 903    union_sockaddr buf;
 904    socklen_t len = (socklen_t)sizeof buf;
 905
 906    GetOpenFile(sock, fptr);
 907    sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, &buf.addr, &len);
 908    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
 909}
 910
 911/*
 912 * call-seq:
 913 *   socket.sysaccept => [client_socket_fd, client_addrinfo]
 914 *
 915 * Accepts an incoming connection returning an array containing the (integer)
 916 * file descriptor for the incoming connection, _client_socket_fd_,
 917 * and an Addrinfo, _client_addrinfo_.
 918 *
 919 * === Example
 920 * 	# In one script, start this first
 921 * 	require 'socket'
 922 * 	include Socket::Constants
 923 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 924 * 	sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
 925 * 	socket.bind( sockaddr )
 926 * 	socket.listen( 5 )
 927 * 	client_fd, client_addrinfo = socket.sysaccept
 928 * 	client_socket = Socket.for_fd( client_fd )
 929 * 	puts "The client said, '#{client_socket.readline.chomp}'"
 930 * 	client_socket.puts "Hello from script one!"
 931 * 	socket.close
 932 *
 933 * 	# In another script, start this second
 934 * 	require 'socket'
 935 * 	include Socket::Constants
 936 * 	socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
 937 * 	sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
 938 * 	socket.connect( sockaddr )
 939 * 	socket.puts "Hello from script 2."
 940 * 	puts "The server said, '#{socket.readline.chomp}'"
 941 * 	socket.close
 942 *
 943 * Refer to Socket#accept for the exceptions that may be thrown if the call
 944 * to _sysaccept_ fails.
 945 *
 946 * === See
 947 * * Socket#accept
 948 */
 949static VALUE
 950sock_sysaccept(VALUE sock)
 951{
 952    rb_io_t *fptr;
 953    VALUE sock2;
 954    union_sockaddr buf;
 955    socklen_t len = (socklen_t)sizeof buf;
 956
 957    GetOpenFile(sock, fptr);
 958    sock2 = rsock_s_accept(0,fptr->fd,&buf.addr,&len);
 959
 960    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
 961}
 962
 963#ifdef HAVE_GETHOSTNAME
 964/*
 965 * call-seq:
 966 *   Socket.gethostname => hostname
 967 *
 968 * Returns the hostname.
 969 *
 970 *   p Socket.gethostname #=> "hal"
 971 *
 972 * Note that it is not guaranteed to be able to convert to IP address using gethostbyname, getaddrinfo, etc.
 973 * If you need local IP address, use Socket.ip_address_list.
 974 */
 975static VALUE
 976sock_gethostname(VALUE obj)
 977{
 978#ifndef HOST_NAME_MAX
 979#  define HOST_NAME_MAX 1024
 980#endif
 981    char buf[HOST_NAME_MAX+1];
 982
 983    rb_secure(3);
 984    if (gethostname(buf, (int)sizeof buf - 1) < 0)
 985	rb_sys_fail("gethostname(3)");
 986
 987    buf[sizeof buf - 1] = '\0';
 988    return rb_str_new2(buf);
 989}
 990#else
 991#ifdef HAVE_UNAME
 992
 993#include <sys/utsname.h>
 994
 995static VALUE
 996sock_gethostname(VALUE obj)
 997{
 998    struct utsname un;
 999
1000    rb_secure(3);
1001    uname(&un);
1002    return rb_str_new2(un.nodename);
1003}
1004#else
1005#define sock_gethostname rb_f_notimplement
1006#endif
1007#endif
1008
1009static VALUE
1010make_addrinfo(struct addrinfo *res0, int norevlookup)
1011{
1012    VALUE base, ary;
1013    struct addrinfo *res;
1014
1015    if (res0 == NULL) {
1016	rb_raise(rb_eSocket, "host not found");
1017    }
1018    base = rb_ary_new();
1019    for (res = res0; res; res = res->ai_next) {
1020	ary = rsock_ipaddr(res->ai_addr, res->ai_addrlen, norevlookup);
1021	if (res->ai_canonname) {
1022	    RARRAY_PTR(ary)[2] = rb_str_new2(res->ai_canonname);
1023	}
1024	rb_ary_push(ary, INT2FIX(res->ai_family));
1025	rb_ary_push(ary, INT2FIX(res->ai_socktype));
1026	rb_ary_push(ary, INT2FIX(res->ai_protocol));
1027	rb_ary_push(base, ary);
1028    }
1029    return base;
1030}
1031
1032static VALUE
1033sock_sockaddr(struct sockaddr *addr, socklen_t len)
1034{
1035    char *ptr;
1036
1037    switch (addr->sa_family) {
1038      case AF_INET:
1039	ptr = (char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr;
1040	len = (socklen_t)sizeof(((struct sockaddr_in*)addr)->sin_addr.s_addr);
1041	break;
1042#ifdef AF_INET6
1043      case AF_INET6:
1044	ptr = (char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr;
1045	len = (socklen_t)sizeof(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr);
1046	break;
1047#endif
1048      default:
1049        rb_raise(rb_eSocket, "unknown socket family:%d", addr->sa_family);
1050	break;
1051    }
1052    return rb_str_new(ptr, len);
1053}
1054
1055/*
1056 * call-seq:
1057 *   Socket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list]
1058 *
1059 * Obtains the host information for _hostname_.
1060 *
1061 *   p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"]
1062 *
1063 */
1064static VALUE
1065sock_s_gethostbyname(VALUE obj, VALUE host)
1066{
1067    rb_secure(3);
1068    return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
1069}
1070
1071/*
1072 * call-seq:
1073 *   Socket.gethostbyaddr(address_string [, address_family]) => hostent
1074 *
1075 * Obtains the host information for _address_.
1076 *
1077 *   p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
1078 *   #=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]
1079 */
1080static VALUE
1081sock_s_gethostbyaddr(int argc, VALUE *argv)
1082{
1083    VALUE addr, family;
1084    struct hostent *h;
1085    char **pch;
1086    VALUE ary, names;
1087    int t = AF_INET;
1088
1089    rb_scan_args(argc, argv, "11", &addr, &family);
1090    StringValue(addr);
1091    if (!NIL_P(family)) {
1092	t = rsock_family_arg(family);
1093    }
1094#ifdef AF_INET6
1095    else if (RSTRING_LEN(addr) == 16) {
1096	t = AF_INET6;
1097    }
1098#endif
1099    h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), t);
1100    if (h == NULL) {
1101#ifdef HAVE_HSTRERROR
1102	extern int h_errno;
1103	rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno));
1104#else
1105	rb_raise(rb_eSocket, "host not found");
1106#endif
1107    }
1108    ary = rb_ary_new();
1109    rb_ary_push(ary, rb_str_new2(h->h_name));
1110    names = rb_ary_new();
1111    rb_ary_push(ary, names);
1112    if (h->h_aliases != NULL) {
1113	for (pch = h->h_aliases; *pch; pch++) {
1114	    rb_ary_push(names, rb_str_new2(*pch));
1115	}
1116    }
1117    rb_ary_push(ary, INT2NUM(h->h_addrtype));
1118#ifdef h_addr
1119    for (pch = h->h_addr_list; *pch; pch++) {
1120	rb_ary_push(ary, rb_str_new(*pch, h->h_length));
1121    }
1122#else
1123    rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
1124#endif
1125
1126    return ary;
1127}
1128
1129/*
1130 * call-seq:
1131 *   Socket.getservbyname(service_name)                => port_number
1132 *   Socket.getservbyname(service_name, protocol_name) => port_number
1133 *
1134 * Obtains the port number for _service_name_.
1135 *
1136 * If _protocol_name_ is not given, "tcp" is assumed.
1137 *
1138 *   Socket.getservbyname("smtp")          #=> 25
1139 *   Socket.getservbyname("shell")         #=> 514
1140 *   Socket.getservbyname("syslog", "udp") #=> 514
1141 */
1142static VALUE
1143sock_s_getservbyname(int argc, VALUE *argv)
1144{
1145    VALUE service, proto;
1146    struct servent *sp;
1147    long port;
1148    const char *servicename, *protoname = "tcp";
1149
1150    rb_scan_args(argc, argv, "11", &service, &proto);
1151    StringValue(service);
1152    if (!NIL_P(proto)) StringValue(proto);
1153    servicename = StringValueCStr(service);
1154    if (!NIL_P(proto)) protoname = StringValueCStr(proto);
1155    sp = getservbyname(servicename, protoname);
1156    if (sp) {
1157	port = ntohs(sp->s_port);
1158    }
1159    else {
1160	char *end;
1161
1162	port = STRTOUL(servicename, &end, 0);
1163	if (*end != '\0') {
1164	    rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname);
1165	}
1166    }
1167    return INT2FIX(port);
1168}
1169
1170/*
1171 * call-seq:
1172 *   Socket.getservbyport(port [, protocol_name]) => service
1173 *
1174 * Obtains the port number for _port_.
1175 *
1176 * If _protocol_name_ is not given, "tcp" is assumed.
1177 *
1178 *   Socket.getservbyport(80)         #=> "www"
1179 *   Socket.getservbyport(514, "tcp") #=> "shell"
1180 *   Socket.getservbyport(514, "udp") #=> "syslog"
1181 *
1182 */
1183static VALUE
1184sock_s_getservbyport(int argc, VALUE *argv)
1185{
1186    VALUE port, proto;
1187    struct servent *sp;
1188    long portnum;
1189    const char *protoname = "tcp";
1190
1191    rb_scan_args(argc, argv, "11", &port, &proto);
1192    portnum = NUM2LONG(port);
1193    if (portnum != (uint16_t)portnum) {
1194	const char *s = portnum > 0 ? "big" : "small";
1195	rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s);
1196    }
1197    if (!NIL_P(proto)) protoname = StringValueCStr(proto);
1198
1199    sp = getservbyport((int)htons((uint16_t)portnum), protoname);
1200    if (!sp) {
1201	rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname);
1202    }
1203    return rb_tainted_str_new2(sp->s_name);
1204}
1205
1206/*
1207 * call-seq:
1208 *   Socket.getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags[, reverse_lookup]]]]]) => array
1209 *
1210 * Obtains address information for _nodename_:_servname_.
1211 *
1212 * _family_ should be an address family such as: :INET, :INET6, :UNIX, etc.
1213 *
1214 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
1215 *
1216 * _protocol_ should be a protocol defined in the family,
1217 * and defaults to 0 for the family.
1218 *
1219 * _flags_ should be bitwise OR of Socket::AI_* constants.
1220 *
1221 *   Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM)
1222 *   #=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP
1223 *
1224 *   Socket.getaddrinfo("localhost", nil)
1225 *   #=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6],  # PF_INET/SOCK_STREAM/IPPROTO_TCP
1226 *   #    ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP
1227 *   #    ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]]  # PF_INET/SOCK_RAW/IPPROTO_IP
1228 *
1229 * _reverse_lookup_ directs the form of the third element, and has to
1230 * be one of below.  If _reverse_lookup_ is omitted, the default value is +nil+.
1231 *
1232 *   +true+, +:hostname+:  hostname is obtained from numeric address using reverse lookup, which may take a time.
1233 *   +false+, +:numeric+:  hostname is same as numeric address.
1234 *   +nil+:              obey to the current +do_not_reverse_lookup+ flag.
1235 *
1236 * If Addrinfo object is preferred, use Addrinfo.getaddrinfo.
1237 */
1238static VALUE
1239sock_s_getaddrinfo(int argc, VALUE *argv)
1240{
1241    VALUE host, port, family, socktype, protocol, flags, ret, revlookup;
1242    struct addrinfo hints, *res;
1243    int norevlookup;
1244
1245    rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup);
1246
1247    MEMZERO(&hints, struct addrinfo, 1);
1248    hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);
1249
1250    if (!NIL_P(socktype)) {
1251	hints.ai_socktype = rsock_socktype_arg(socktype);
1252    }
1253    if (!NIL_P(protocol)) {
1254	hints.ai_protocol = NUM2INT(protocol);
1255    }
1256    if (!NIL_P(flags)) {
1257	hints.ai_flags = NUM2INT(flags);
1258    }
1259    if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) {
1260	norevlookup = rsock_do_not_reverse_lookup;
1261    }
1262    res = rsock_getaddrinfo(host, port, &hints, 0);
1263
1264    ret = make_addrinfo(res, norevlookup);
1265    freeaddrinfo(res);
1266    return ret;
1267}
1268
1269/*
1270 * call-seq:
1271 *   Socket.getnameinfo(sockaddr [, flags]) => [hostname, servicename]
1272 *
1273 * Obtains name information for _sockaddr_.
1274 *
1275 * _sockaddr_ should be one of follows.
1276 * - packed sockaddr string such as Socket.sockaddr_in(80, "127.0.0.1")
1277 * - 3-elements array such as ["AF_INET", 80, "127.0.0.1"]
1278 * - 4-elements array such as ["AF_INET", 80, ignored, "127.0.0.1"]
1279 *
1280 * _flags_ should be bitwise OR of Socket::NI_* constants.
1281 *
1282 * Note:
1283 * The last form is compatible with IPSocket#addr and IPSocket#peeraddr.
1284 *
1285 *   Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1"))       #=> ["localhost", "www"]
1286 *   Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"])              #=> ["localhost", "www"]
1287 *   Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"]
1288 *
1289 * If Addrinfo object is preferred, use Addrinfo#getnameinfo.
1290 */
1291static VALUE
1292sock_s_getnameinfo(int argc, VALUE *argv)
1293{
1294    VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
1295    char *hptr, *pptr;
1296    char hbuf[1024], pbuf[1024];
1297    int fl;
1298    struct addrinfo hints, *res = NULL, *r;
1299    int error;
1300    union_sockaddr ss;
1301    struct sockaddr *sap;
1302    socklen_t salen;
1303
1304    sa = flags = Qnil;
1305    rb_scan_args(argc, argv, "11", &sa, &flags);
1306
1307    fl = 0;
1308    if (!NIL_P(flags)) {
1309	fl = NUM2INT(flags);
1310    }
1311    tmp = rb_check_sockaddr_string_type(sa);
1312    if (!NIL_P(tmp)) {
1313	sa = tmp;
1314	if (sizeof(ss) < (size_t)RSTRING_LEN(sa)) {
1315	    rb_raise(rb_eTypeError, "sockaddr length too big");
1316	}
1317	memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa));
1318        if (!VALIDATE_SOCKLEN(&ss.addr, RSTRING_LEN(sa))) {
1319	    rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
1320	}
1321	sap = &ss.addr;
1322        salen = RSTRING_SOCKLEN(sa);
1323	goto call_nameinfo;
1324    }
1325    tmp = rb_check_array_type(sa);
1326    if (!NIL_P(tmp)) {
1327	sa = tmp;
1328	MEMZERO(&hints, struct addrinfo, 1);
1329	if (RARRAY_LEN(sa) == 3) {
1330	    af = RARRAY_PTR(sa)[0];
1331	    port = RARRAY_PTR(sa)[1];
1332	    host = RARRAY_PTR(sa)[2];
1333	}
1334	else if (RARRAY_LEN(sa) >= 4) {
1335	    af = RARRAY_PTR(sa)[0];
1336	    port = RARRAY_PTR(sa)[1];
1337	    host = RARRAY_PTR(sa)[3];
1338	    if (NIL_P(host)) {
1339		host = RARRAY_PTR(sa)[2];
1340	    }
1341	    else {
1342		/*
1343		 * 4th element holds numeric form, don't resolve.
1344		 * see rsock_ipaddr().
1345		 */
1346#ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */
1347		hints.ai_flags |= AI_NUMERICHOST;
1348#endif
1349	    }
1350	}
1351	else {
1352	    rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given",
1353		     RARRAY_LEN(sa));
1354	}
1355	/* host */
1356	if (NIL_P(host)) {
1357	    hptr = NULL;
1358	}
1359	else {
1360	    strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
1361	    hbuf[sizeof(hbuf) - 1] = '\0';
1362	    hptr = hbuf;
1363	}
1364	/* port */
1365	if (NIL_P(port)) {
1366	    strcpy(pbuf, "0");
1367	    pptr = NULL;
1368	}
1369	else if (FIXNUM_P(port)) {
1370	    snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port));
1371	    pptr = pbuf;
1372	}
1373	else {
1374	    strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
1375	    pbuf[sizeof(pbuf) - 1] = '\0';
1376	    pptr = pbuf;
1377	}
1378	hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
1379	/* af */
1380        hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
1381	error = rb_getaddrinfo(hptr, pptr, &hints, &res);
1382	if (error) goto error_exit_addr;
1383	sap = res->ai_addr;
1384        salen = res->ai_addrlen;
1385    }
1386    else {
1387	rb_raise(rb_eTypeError, "expecting String or Array");
1388    }
1389
1390  call_nameinfo:
1391    error = rb_getnameinfo(sap, salen, hbuf, sizeof(hbuf),
1392			   pbuf, sizeof(pbuf), fl);
1393    if (error) goto error_exit_name;
1394    if (res) {
1395	for (r = res->ai_next; r; r = r->ai_next) {
1396	    char hbuf2[1024], pbuf2[1024];
1397
1398	    sap = r->ai_addr;
1399            salen = r->ai_addrlen;
1400	    error = rb_getnameinfo(sap, salen, hbuf2, sizeof(hbuf2),
1401				   pbuf2, sizeof(pbuf2), fl);
1402	    if (error) goto error_exit_name;
1403	    if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) {
1404		freeaddrinfo(res);
1405		rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename");
1406	    }
1407	}
1408	freeaddrinfo(res);
1409    }
1410    return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
1411
1412  error_exit_addr:
1413    if (res) freeaddrinfo(res);
1414    rsock_raise_socket_error("getaddrinfo", error);
1415
1416  error_exit_name:
1417    if (res) freeaddrinfo(res);
1418    rsock_raise_socket_error("getnameinfo", error);
1419
1420    UNREACHABLE;
1421}
1422
1423/*
1424 * call-seq:
1425 *   Socket.sockaddr_in(port, host)      => sockaddr
1426 *   Socket.pack_sockaddr_in(port, host) => sockaddr
1427 *
1428 * Packs _port_ and _host_ as an AF_INET/AF_INET6 sockaddr string.
1429 *
1430 *   Socket.sockaddr_in(80, "127.0.0.1")
1431 *   #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
1432 *
1433 *   Socket.sockaddr_in(80, "::1")
1434 *   #=> "\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"
1435 *
1436 */
1437static VALUE
1438sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
1439{
1440    struct addrinfo *res = rsock_addrinfo(host, port, 0, 0);
1441    VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen);
1442
1443    freeaddrinfo(res);
1444    OBJ_INFECT(addr, port);
1445    OBJ_INFECT(addr, host);
1446
1447    return addr;
1448}
1449
1450/*
1451 * call-seq:
1452 *   Socket.unpack_sockaddr_in(sockaddr) => [port, ip_address]
1453 *
1454 * Unpacks _sockaddr_ into port and ip_address.
1455 *
1456 * _sockaddr_ should be a string or an addrinfo for AF_INET/AF_INET6.
1457 *
1458 *   sockaddr = Socket.sockaddr_in(80, "127.0.0.1")
1459 *   p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
1460 *   p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"]
1461 *
1462 */
1463static VALUE
1464sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
1465{
1466    struct sockaddr_in * sockaddr;
1467    VALUE host;
1468
1469    sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr);
1470    if (RSTRING_LEN(addr) <
1471        (char*)&((struct sockaddr *)sockaddr)->sa_family +
1472        sizeof(((struct sockaddr *)sockaddr)->sa_family) -
1473        (char*)sockaddr)
1474        rb_raise(rb_eArgError, "too short sockaddr");
1475    if (((struct sockaddr *)sockaddr)->sa_family != AF_INET
1476#ifdef INET6
1477        && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6
1478#endif
1479        ) {
1480#ifdef INET6
1481        rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr");
1482#else
1483        rb_raise(rb_eArgError, "not an AF_INET sockaddr");
1484#endif
1485    }
1486    host = rsock_make_ipaddr((struct sockaddr*)sockaddr, RSTRING_SOCKLEN(addr));
1487    OBJ_INFECT(host, addr);
1488    return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
1489}
1490
1491#ifdef HAVE_SYS_UN_H
1492
1493/*
1494 * call-seq:
1495 *   Socket.sockaddr_un(path)      => sockaddr
1496 *   Socket.pack_sockaddr_un(path) => sockaddr
1497 *
1498 * Packs _path_ as an AF_UNIX sockaddr string.
1499 *
1500 *   Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
1501 *
1502 */
1503static VALUE
1504sock_s_pack_sockaddr_un(VALUE self, VALUE path)
1505{
1506    struct sockaddr_un sockaddr;
1507    VALUE addr;
1508
1509    StringValue(path);
1510    INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
1511    if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
1512        rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
1513            (size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path));
1514    }
1515    memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
1516    addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path));
1517    OBJ_INFECT(addr, path);
1518
1519    return addr;
1520}
1521
1522/*
1523 * call-seq:
1524 *   Socket.unpack_sockaddr_un(sockaddr) => path
1525 *
1526 * Unpacks _sockaddr_ into path.
1527 *
1528 * _sockaddr_ should be a …

Large files files are truncated, but you can click here to view the full file