PageRenderTime 45ms CodeModel.GetById 3ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/ext/socket/socket.c

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

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