class BasicSocket - Documentation for Ruby 3.2

# class BasicSocket

`BasicSocket` is the super class for all the `Socket` classes.

### Public Class Methods

do_not_reverse_lookup → true or false click to toggle source

Gets the global `do_not_reverse_lookup` flag.

    BasicSocket.do_not_reverse_lookup  #=> false

    static VALUE
    bsock_do_not_rev_lookup(VALUE _)
    {
        return rsock_do_not_reverse_lookup?Qtrue:Qfalse;
    }

do_not_reverse_lookup = bool click to toggle source

Sets the global `do_not_reverse_lookup` flag.

The flag is used for initial value of `do_not_reverse_lookup` for each socket.

    s1 = TCPSocket.new("localhost", 80)
    p s1.do_not_reverse_lookup                 #=> true
    BasicSocket.do_not_reverse_lookup = false
    s2 = TCPSocket.new("localhost", 80)
    p s2.do_not_reverse_lookup                 #=> false
    p s1.do_not_reverse_lookup                 #=> true

    static VALUE
    bsock_do_not_rev_lookup_set(VALUE self, VALUE val)
    {
        rsock_do_not_reverse_lookup = RTEST(val);
        return val;
    }

for_fd(fd) → basicsocket click to toggle source

Returns a socket object which contains the file descriptor, fd.

    # If invoked by inetd, STDIN/STDOUT/STDERR is a socket.
    STDIN_SOCK = Socket.for_fd(STDIN.fileno)
    p STDIN_SOCK.remote_address

    static VALUE
    bsock_s_for_fd(VALUE klass, VALUE _descriptor)
    {
        rb_io_t *fptr;

        int descriptor = RB_NUM2INT(_descriptor);
        rsock_validate_descriptor(descriptor);

        VALUE sock = rsock_init_sock(rb_obj_alloc(klass), descriptor);

        GetOpenFile(sock, fptr);

        return sock;
    }

### Public Instance Methods

close_read → nil click to toggle source

Disallows further read using shutdown system call.

    s1, s2 = UNIXSocket.pair
    s1.close_read
    s2.puts #=> Broken pipe (Errno::EPIPE)

    static VALUE
    bsock_close_read(VALUE sock)
    {
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        shutdown(fptr->fd, 0);
        if (!(fptr->mode & FMODE_WRITABLE)) {
            return rb_io_close(sock);
        }
        fptr->mode &= ~FMODE_READABLE;

        return Qnil;
    }

close_write → nil click to toggle source

Disallows further write using shutdown system call.

    UNIXSocket.pair {|s1, s2|
      s1.print "ping"
      s1.close_write
      p s2.read        #=> "ping"
      s2.print "pong"
      s2.close
      p s1.read        #=> "pong"
    }

    static VALUE
    bsock_close_write(VALUE sock)
    {
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        if (!(fptr->mode & FMODE_READABLE)) {
            return rb_io_close(sock);
        }
        shutdown(fptr->fd, 1);
        fptr->mode &= ~FMODE_WRITABLE;

        return Qnil;
    }

connect_address() click to toggle source

Returns an address of the socket suitable for connect in the local machine.

This method returns self.local_address, except following condition.

- IPv4 unspecified address (0.0.0.0) is replaced by IPv4 loopback address (127.0.0.1).

- IPv6 unspecified address (::) is replaced by IPv6 loopback address (::1).

If the local address is not suitable for connect, `SocketError` is raised. IPv4 and IPv6 address which port is 0 is not suitable for connect. Unix domain socket which has no path is not suitable for connect.

    Addrinfo.tcp("0.0.0.0", 0).listen {|serv|
      p serv.connect_address #=> #<Addrinfo: 127.0.0.1:53660 TCP>
      serv.connect_address.connect {|c|
        s, _ = serv.accept
        p [c, s] #=> [#<Socket:fd 4>, #<Socket:fd 6>]
      }
    }

    # File ext/socket/lib/socket.rb, line 255
    def connect_address
      addr = local_address
      afamily = addr.afamily
      if afamily == Socket::AF_INET
        raise SocketError, "unbound IPv4 socket" if addr.ip_port == 0
        if addr.ip_address == "0.0.0.0"
          addr = Addrinfo.new(["AF_INET", addr.ip_port, nil, "127.0.0.1"], addr.pfamily, addr.socktype, addr.protocol)
        end
      elsif defined?(Socket::AF_INET6) && afamily == Socket::AF_INET6
        raise SocketError, "unbound IPv6 socket" if addr.ip_port == 0
        if addr.ip_address == "::"
          addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
        elsif addr.ip_address == "0.0.0.0" # MacOS X 10.4 returns "a.b.c.d" for IPv4-mapped IPv6 address.
          addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
        elsif addr.ip_address == "::ffff:0.0.0.0" # MacOS X 10.6 returns "::ffff:a.b.c.d" for IPv4-mapped IPv6 address.
          addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
        end
      elsif defined?(Socket::AF_UNIX) && afamily == Socket::AF_UNIX
        raise SocketError, "unbound Unix socket" if addr.unix_path == ""
      end
      addr
    end

do_not_reverse_lookup → true or false click to toggle source

Gets the `do_not_reverse_lookup` flag of basicsocket.

    require 'socket'

    BasicSocket.do_not_reverse_lookup = false
    TCPSocket.open("www.ruby-lang.org", 80) {|sock|
      p sock.do_not_reverse_lookup      #=> false
    }
    BasicSocket.do_not_reverse_lookup = true
    TCPSocket.open("www.ruby-lang.org", 80) {|sock|
      p sock.do_not_reverse_lookup      #=> true
    }

    static VALUE
    bsock_do_not_reverse_lookup(VALUE sock)
    {
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        return (fptr->mode & FMODE_NOREVLOOKUP) ? Qtrue : Qfalse;
    }

do_not_reverse_lookup = bool click to toggle source

Sets the `do_not_reverse_lookup` flag of basicsocket.

    TCPSocket.open("www.ruby-lang.org", 80) {|sock|
      p sock.do_not_reverse_lookup       #=> true
      p sock.peeraddr                    #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
      sock.do_not_reverse_lookup = false
      p sock.peeraddr                    #=> ["AF_INET", 80, "carbon.ruby-lang.org", "54.163.249.195"]
    }

    static VALUE
    bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
    {
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        if (RTEST(state)) {
            fptr->mode |= FMODE_NOREVLOOKUP;
        }
        else {
            fptr->mode &= ~FMODE_NOREVLOOKUP;
        }
        return sock;
    }

getpeereid → [euid, egid] click to toggle source

Returns the user and group on the peer of the UNIX socket. The result is a two element array which contains the effective uid and the effective gid.

    Socket.unix_server_loop("/tmp/sock") {|s|
      begin
        euid, egid = s.getpeereid

        # Check the connected client is myself or not.
        next if euid != Process.uid

        # do something about my resource.

      ensure
        s.close
      end
    }

    static VALUE
    bsock_getpeereid(VALUE self)
    {
    #if defined(HAVE_GETPEEREID)
        rb_io_t *fptr;
        uid_t euid;
        gid_t egid;
        GetOpenFile(self, fptr);
        if (getpeereid(fptr->fd, &euid, &egid) == -1)
            rb_sys_fail("getpeereid(3)");
        return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid));
    #elif defined(SO_PEERCRED) /* GNU/Linux */
        rb_io_t *fptr;
        struct ucred cred;
        socklen_t len = sizeof(cred);
        GetOpenFile(self, fptr);
        if (getsockopt(fptr->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
            rb_sys_fail("getsockopt(SO_PEERCRED)");
        return rb_assoc_new(UIDT2NUM(cred.uid), GIDT2NUM(cred.gid));
    #elif defined(HAVE_GETPEERUCRED) /* Solaris */
        rb_io_t *fptr;
        ucred_t *uc = NULL;
        VALUE ret;
        GetOpenFile(self, fptr);
        if (getpeerucred(fptr->fd, &uc) == -1)
            rb_sys_fail("getpeerucred(3C)");
        ret = rb_assoc_new(UIDT2NUM(ucred_geteuid(uc)), GIDT2NUM(ucred_getegid(uc)));
        ucred_free(uc);
        return ret;
    #endif
    }

getpeername → sockaddr click to toggle source

Returns the remote address of the socket as a sockaddr string.

    TCPServer.open("127.0.0.1", 1440) {|serv|
      c = TCPSocket.new("127.0.0.1", 1440)
      s = serv.accept
      p s.getpeername #=> "\x02\x00\x82u\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
    }

If `Addrinfo` object is preferred over the binary string, use `BasicSocket#remote_address`.

    static VALUE
    bsock_getpeername(VALUE sock)
    {
        union_sockaddr buf;
        socklen_t len = (socklen_t)sizeof buf;
        socklen_t len0 = len;
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        if (getpeername(fptr->fd, &buf.addr, &len) < 0)
            rb_sys_fail("getpeername(2)");
        if (len0 < len) len = len0;
        return rb_str_new((char*)&buf, len);
    }

getsockname → sockaddr click to toggle source

Returns the local address of the socket as a sockaddr string.

    TCPServer.open("127.0.0.1", 15120) {|serv|
      p serv.getsockname #=> "\x02\x00;\x10\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
    }

If `Addrinfo` object is preferred over the binary string, use `BasicSocket#local_address`.

    static VALUE
    bsock_getsockname(VALUE sock)
    {
        union_sockaddr buf;
        socklen_t len = (socklen_t)sizeof buf;
        socklen_t len0 = len;
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        if (getsockname(fptr->fd, &buf.addr, &len) < 0)
            rb_sys_fail("getsockname(2)");
        if (len0 < len) len = len0;
        return rb_str_new((char*)&buf, len);
    }

getsockopt(level, optname) → socketoption click to toggle source

Gets a socket option. These are protocol and system specific, see your local system documentation for details. The option is returned as a `Socket::Option` object.

### Parameters¶ ↑

- `level` is an integer, usually one of the SOL_ constants such as Socket::SOL_SOCKET, or a protocol level. A string or symbol of the name, possibly without prefix, is also accepted.

- `optname` is an integer, usually one of the SO_ constants, such as Socket::SO_REUSEADDR. A string or symbol of the name, possibly without prefix, is also accepted.

### Examples¶ ↑

Some socket options are integers with boolean values, in this case `getsockopt` could be called like this:

    reuseaddr = sock.getsockopt(:SOCKET, :REUSEADDR).bool

    optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR)
    optval = optval.unpack "i"
    reuseaddr = optval[0] == 0 ? false : true

Some socket options are integers with numeric values, in this case `getsockopt` could be called like this:

    ipttl = sock.getsockopt(:IP, :TTL).int

    optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
    ipttl = optval.unpack1("i")

Option values may be structs. Decoding them can be complex as it involves examining your system headers to determine the correct definition. An example is a +struct linger+, which may be defined in your system headers as:

    struct linger {
      int l_onoff;
      int l_linger;
    };

In this case `getsockopt` could be called like this:

    # Socket::Option knows linger structure.
    onoff, linger = sock.getsockopt(:SOCKET, :LINGER).linger

    optval =  sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER)
    onoff, linger = optval.unpack "ii"
    onoff = onoff == 0 ? false : true

    static VALUE
    bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname)
    {
        int level, option;
        socklen_t len;
        char *buf;
        rb_io_t *fptr;
        int family;

        GetOpenFile(sock, fptr);
        family = rsock_getfamily(fptr);
        level = rsock_level_arg(family, lev);
        option = rsock_optname_arg(family, level, optname);
        len = 256;
    #ifdef _AIX
        switch (option) {
          case SO_DEBUG:
          case SO_REUSEADDR:
          case SO_KEEPALIVE:
          case SO_DONTROUTE:
          case SO_BROADCAST:
          case SO_OOBINLINE:
            /* AIX doesn't set len for boolean options */
            len = sizeof(int);
        }
    #endif
        buf = ALLOCA_N(char,len);

        rb_io_check_closed(fptr);

        if (getsockopt(fptr->fd, level, option, buf, &len) < 0)
            rsock_sys_fail_path("getsockopt(2)", fptr->pathv);

        return rsock_sockopt_new(family, level, option, rb_str_new(buf, len));
    }

local_address → addrinfo click to toggle source

Returns an `Addrinfo` object for local address obtained by getsockname.

Note that addrinfo.protocol is filled by 0.

    TCPSocket.open("www.ruby-lang.org", 80) {|s|
      p s.local_address #=> #<Addrinfo: 192.168.0.129:36873 TCP>
    }

    TCPServer.open("127.0.0.1", 1512) {|serv|
      p serv.local_address #=> #<Addrinfo: 127.0.0.1:1512 TCP>
    }

    static VALUE
    bsock_local_address(VALUE sock)
    {
        union_sockaddr buf;
        socklen_t len = (socklen_t)sizeof buf;
        socklen_t len0 = len;
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        if (getsockname(fptr->fd, &buf.addr, &len) < 0)
            rb_sys_fail("getsockname(2)");
        if (len0 < len) len = len0;
        return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len);
    }

recv(maxlen[, flags[, outbuf]]) → mesg click to toggle source

Receives a message.

maxlen is the maximum number of bytes to receive.

flags should be a bitwise OR of Socket::MSG_* constants.

outbuf will contain only the received data after the method call even if it is not empty at the beginning.

    UNIXSocket.pair {|s1, s2|
      s1.puts "Hello World"
      p s2.recv(4)                     #=> "Hell"
      p s2.recv(4, Socket::MSG_PEEK)   #=> "o Wo"
      p s2.recv(4)                     #=> "o Wo"
      p s2.recv(10)                    #=> "rld\n"
    }

    static VALUE
    bsock_recv(int argc, VALUE *argv, VALUE sock)
    {
        return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
    }

recv_nonblock(maxlen [, flags [, buf [, options ]]]) → mesg click to toggle source

Receives up to maxlen bytes from `socket` using recvfrom(2) after O_NONBLOCK is set for the underlying file descriptor. flags is zero or more of the `MSG_` options. The result, mesg, is the data received.

When recvfrom(2) returns 0, `Socket#recv_nonblock` returns an empty string as data. The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.

### Parameters¶ ↑

- `maxlen` - the number of bytes to receive from the socket

- `flags` - zero or more of the `MSG_` options

- `buf` - destination `String` buffer

- `options` - keyword hash, supporting ‘exception: false`

### Example¶ ↑

    serv = TCPServer.new("127.0.0.1", 0)
    af, port, host, addr = serv.addr
    c = TCPSocket.new(addr, port)
    s = serv.accept
    c.send "aaa", 0
    begin # emulate blocking recv.
      p s.recv_nonblock(10) #=> "aaa"
    rescue IO::WaitReadable
      IO.select([s])
      retry
    end

Refer to `Socket#recvfrom` for the exceptions that may be thrown if the call to recv_nonblock fails.

`BasicSocket#recv_nonblock` may raise any error corresponding to recvfrom(2) failure, including Errno::EWOULDBLOCK.

If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN, it is extended by `IO::WaitReadable`. So `IO::WaitReadable` can be used to rescue the exceptions for retrying recv_nonblock.

By specifying a keyword argument exception to `false`, you can indicate that `recv_nonblock` should not raise an `IO::WaitReadable` exception, but return the symbol `:wait_readable` instead.

### See¶ ↑

- `Socket#recvfrom`

    # File ext/socket/lib/socket.rb, line 375
    def recv_nonblock(len, flag = 0, str = nil, exception: true)
      __recv_nonblock(len, flag, str, exception)
    end

recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) → [mesg, sender_addrinfo, rflags, *controls] click to toggle source

recvmsg receives a message using recvmsg(2) system call in blocking manner.

maxmesglen is the maximum length of mesg to receive.

flags is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.

maxcontrollen is the maximum length of controls (ancillary data) to receive.

opts is option hash. Currently :scm_rights=>bool is the only option.

:scm_rights option specifies that application expects SCM_RIGHTS control message. If the value is nil or false, application don’t expects SCM_RIGHTS control message. In this case, recvmsg closes the passed file descriptors immediately. This is the default behavior.

If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message. In this case, recvmsg creates `IO` objects for each file descriptors for `Socket::AncillaryData#unix_rights` method.

The return value is 4-elements array.

mesg is a string of the received message.

sender_addrinfo is a sender socket address for connection-less socket. It is an `Addrinfo` object. For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.

rflags is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC. It will be nil if the system uses 4.3BSD style old recvmsg system call.

controls is ancillary data which is an array of `Socket::AncillaryData` objects such as:

    #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>

maxmesglen and maxcontrollen can be nil. In that case, the buffer will be grown until the message is not truncated. Internally, MSG_PEEK is used. Buffer full and MSG_CTRUNC are checked for truncation.

recvmsg can be used to implement recv_io as follows:

    mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
    controls.each {|ancdata|
      if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
        return ancdata.unix_rights[0]
      end
    }

    # File ext/socket/lib/socket.rb, line 430
    def recvmsg(dlen = nil, flags = 0, clen = nil, scm_rights: false)
      __recvmsg(dlen, flags, clen, scm_rights)
    end

recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) → [data, sender_addrinfo, rflags, *controls] click to toggle source

recvmsg receives a message using recvmsg(2) system call in non-blocking manner.

It is similar to `BasicSocket#recvmsg` but non-blocking flag is set before the system call and it doesn’t retry the system call.

By specifying a keyword argument exception to `false`, you can indicate that `recvmsg_nonblock` should not raise an `IO::WaitReadable` exception, but return the symbol `:wait_readable` instead.

    # File ext/socket/lib/socket.rb, line 446
    def recvmsg_nonblock(dlen = nil, flags = 0, clen = nil,
                         scm_rights: false, exception: true)
      __recvmsg_nonblock(dlen, flags, clen, scm_rights, exception)
    end

remote_address → addrinfo click to toggle source

Returns an `Addrinfo` object for remote address obtained by getpeername.

Note that addrinfo.protocol is filled by 0.

    TCPSocket.open("www.ruby-lang.org", 80) {|s|
      p s.remote_address #=> #<Addrinfo: 221.186.184.68:80 TCP>
    }

    TCPServer.open("127.0.0.1", 1728) {|serv|
      c = TCPSocket.new("127.0.0.1", 1728)
      s = serv.accept
      p s.remote_address #=> #<Addrinfo: 127.0.0.1:36504 TCP>
    }

    static VALUE
    bsock_remote_address(VALUE sock)
    {
        union_sockaddr buf;
        socklen_t len = (socklen_t)sizeof buf;
        socklen_t len0 = len;
        rb_io_t *fptr;

        GetOpenFile(sock, fptr);
        if (getpeername(fptr->fd, &buf.addr, &len) < 0)
            rb_sys_fail("getpeername(2)");
        if (len0 < len) len = len0;
        return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len);
    }

send(mesg, flags [, dest_sockaddr]) → numbytes_sent click to toggle source

send mesg via basicsocket.

mesg should be a string.

flags should be a bitwise OR of Socket::MSG_* constants.

dest_sockaddr should be a packed sockaddr string or an addrinfo.

    TCPSocket.open("localhost", 80) {|s|
      s.send "GET / HTTP/1.0\r\n\r\n", 0
      p s.read
    }

    VALUE
    rsock_bsock_send(int argc, VALUE *argv, VALUE socket)
    {
        struct rsock_send_arg arg;
        VALUE flags, to;
        rb_io_t *fptr;
        rb_blocking_function_t *func;
        const char *funcname;

        rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);

        StringValue(arg.mesg);
        if (!NIL_P(to)) {
            SockAddrStringValue(to);
            to = rb_str_new4(to);
            arg.to = (struct sockaddr *)RSTRING_PTR(to);
            arg.tolen = RSTRING_SOCKLEN(to);
            func = rsock_sendto_blocking;
            funcname = "sendto(2)";
        }
        else {
            func = rsock_send_blocking;
            funcname = "send(2)";
        }

        RB_IO_POINTER(socket, fptr);

        arg.fd = fptr->fd;
        arg.flags = NUM2INT(flags);

        while (true) {
    #ifdef RSOCK_WAIT_BEFORE_BLOCKING
            rb_io_wait(socket, RB_INT2NUM(RUBY_IO_WRITABLE), Qnil);
    #endif

            ssize_t n = (ssize_t)BLOCKING_REGION_FD(func, &arg);

            if (n >= 0) return SSIZET2NUM(n);

            if (rb_io_maybe_wait_writable(errno, socket, RUBY_IO_TIMEOUT_DEFAULT)) {
                continue;
            }

            rb_sys_fail(funcname);
        }
    }

sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) → numbytes_sent click to toggle source

sendmsg sends a message using sendmsg(2) system call in blocking manner.

mesg is a string to send.

flags is bitwise OR of MSG_* constants such as Socket::MSG_OOB.

dest_sockaddr is a destination socket address for connection-less socket. It should be a sockaddr such as a result of `Socket.sockaddr_in`. An `Addrinfo` object can be used too.

controls is a list of ancillary data. The element of controls should be `Socket::AncillaryData` or 3-elements array. The 3-element array should contains cmsg_level, cmsg_type and data.

The return value, numbytes_sent is an integer which is the number of bytes sent.

sendmsg can be used to implement send_io as follows:

    # use Socket::AncillaryData.
    ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
    sock.sendmsg("a", 0, nil, ancdata)

    # use 3-element array.
    ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
    sock.sendmsg("\0", 0, nil, ancdata)

    # File ext/socket/lib/socket.rb, line 307
    def sendmsg(mesg, flags = 0, dest_sockaddr = nil, *controls)
      __sendmsg(mesg, flags, dest_sockaddr, controls)
    end

sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) → numbytes_sent click to toggle source

`sendmsg_nonblock` sends a message using sendmsg(2) system call in non-blocking manner.

It is similar to `BasicSocket#sendmsg` but the non-blocking flag is set before the system call and it doesn’t retry the system call.

By specifying a keyword argument exception to `false`, you can indicate that `sendmsg_nonblock` should not raise an `IO::WaitWritable` exception, but return the symbol `:wait_writable` instead.

    # File ext/socket/lib/socket.rb, line 323
    def sendmsg_nonblock(mesg, flags = 0, dest_sockaddr = nil, *controls,
                         exception: true)
      __sendmsg_nonblock(mesg, flags, dest_sockaddr, controls, exception)
    end

setsockopt(level, optname, optval) click to toggle source
setsockopt(socketoption)

Sets a socket option. These are protocol and system specific, see your local system documentation for details.

### Parameters¶ ↑

- `level` is an integer, usually one of the SOL_ constants such as Socket::SOL_SOCKET, or a protocol level. A string or symbol of the name, possibly without prefix, is also accepted.

- `optname` is an integer, usually one of the SO_ constants, such as Socket::SO_REUSEADDR. A string or symbol of the name, possibly without prefix, is also accepted.

- `optval` is the value of the option, it is passed to the underlying setsockopt() as a pointer to a certain number of bytes. How this is done depends on the type:

  - Integer: value is assigned to an int, and a pointer to the int is passed, with length of sizeof(int).

  - true or false: 1 or 0 (respectively) is assigned to an int, and the int is passed as for an `Integer`. Note that `false` must be passed, not `nil`.

  - String: the string’s data and length is passed to the socket.

- `socketoption` is an instance of `Socket::Option`

### Examples¶ ↑

Some socket options are integers with boolean values, in this case `setsockopt` could be called like this:

    sock.setsockopt(:SOCKET, :REUSEADDR, true)
    sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
    sock.setsockopt(Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true))

Some socket options are integers with numeric values, in this case `setsockopt` could be called like this:

    sock.setsockopt(:IP, :TTL, 255)
    sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
    sock.setsockopt(Socket::Option.int(:INET, :IP, :TTL, 255))

Option values may be structs. Passing them can be complex as it involves examining your system headers to determine the correct definition. An example is an `ip_mreq`, which may be defined in your system headers as:

    struct ip_mreq {
      struct  in_addr imr_multiaddr;
      struct  in_addr imr_interface;
    };

In this case `setsockopt` could be called like this:

    optval = IPAddr.new("224.0.0.251").hton +
             IPAddr.new(Socket::INADDR_ANY, Socket::AF_INET).hton
    sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval)

    static VALUE
    bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
    {
        VALUE lev, optname, val;
        int family, level, option;
        rb_io_t *fptr;
        int i;
        char *v;
        int vlen;

        if (argc == 1) {
            lev = rb_funcall(argv[0], rb_intern("level"), 0);
            optname = rb_funcall(argv[0], rb_intern("optname"), 0);
            val = rb_funcall(argv[0], rb_intern("data"), 0);
        }
        else {
            rb_scan_args(argc, argv, "30", &lev, &optname, &val);
        }

        GetOpenFile(sock, fptr);
        family = rsock_getfamily(fptr);
        level = rsock_level_arg(family, lev);
        option = rsock_optname_arg(family, level, optname);

        switch (TYPE(val)) {
          case T_FIXNUM:
            i = FIX2INT(val);
            goto numval;
          case T_FALSE:
            i = 0;
            goto numval;
          case T_TRUE:
            i = 1;
          numval:
            v = (char*)&i; vlen = (int)sizeof(i);
            break;
          default:
            StringValue(val);
            v = RSTRING_PTR(val);
            vlen = RSTRING_SOCKLEN(val);
            break;
        }

        rb_io_check_closed(fptr);
        if (setsockopt(fptr->fd, level, option, v, vlen) < 0)
            rsock_sys_fail_path("setsockopt(2)", fptr->pathv);

        return INT2FIX(0);
    }

shutdown([how]) → 0 click to toggle source

Calls shutdown(2) system call.

s.shutdown(Socket::SHUT_RD) disallows further read.

s.shutdown(Socket::SHUT_WR) disallows further write.

s.shutdown(Socket::SHUT_RDWR) disallows further read and write.

how can be symbol or string:

- :RD, :SHUT_RD, “RD” and “SHUT_RD” are accepted as Socket::SHUT_RD.

- :WR, :SHUT_WR, “WR” and “SHUT_WR” are accepted as Socket::SHUT_WR.

- :RDWR, :SHUT_RDWR, “RDWR” and “SHUT_RDWR” are accepted as Socket::SHUT_RDWR.

  `UNIXSocket.pair` {|s1, s2|

      s1.puts "ping"
      s1.shutdown(:WR)
      p s2.read          #=> "ping\n"
      s2.puts "pong"
      s2.close
      p s1.read          #=> "pong\n"

  }

    static VALUE
    bsock_shutdown(int argc, VALUE *argv, VALUE sock)
    {
        VALUE howto;
        int how;
        rb_io_t *fptr;

        rb_scan_args(argc, argv, "01", &howto);
        if (howto == Qnil)
            how = SHUT_RDWR;
        else {
            how = rsock_shutdown_how_arg(howto);
            if (how != SHUT_WR && how != SHUT_RD && how != SHUT_RDWR) {
                rb_raise(rb_eArgError, "`how' should be either :SHUT_RD, :SHUT_WR, :SHUT_RDWR");
            }
        }
        GetOpenFile(sock, fptr);
        if (shutdown(fptr->fd, how) == -1)
            rb_sys_fail("shutdown(2)");

        return INT2FIX(0);
    }