Class: BasicSocket

Inherits:
IO show all
Defined in:
ext/socket/basicsocket.c,
ext/socket/basicsocket.c,
ext/socket/lib/socket.rb

Overview

BasicSocket is the super class for all the Socket classes.

Direct Known Subclasses

IPSocket, Socket, UNIXSocket

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from IO

#beep, #check_winsize_changed, #clear_screen, console, #console_mode, #console_mode=, #cooked, #cooked!, #cursor, #cursor=, #cursor_down, #cursor_left, #cursor_right, #cursor_up, default_console_size, #echo=, #echo?, #erase_line, #erase_screen, #expect, #getch, #getpass, #goto, #goto_column, #iflush, io_maybe_wait, io_maybe_wait_readable, io_maybe_wait_writable, io_wait, #ioflush, #noecho, #nonblock, #nonblock=, #nonblock?, #nread, #oflush, #pathconf, #pressed?, #raw, #raw!, #ready?, #scroll_backward, #scroll_forward, thread_fd_close, thread_fd_wait, thread_fd_writable, #wait, #wait_priority, #wait_readable, #wait_writable, #winsize, #winsize=

Class Method Details

.do_not_reverse_lookupBoolean

Gets the global do_not_reverse_lookup flag.

BasicSocket.do_not_reverse_lookup  #=> false

Returns:

  • (Boolean)


709
710
711
712
713
# File 'ext/socket/basicsocket.c', line 709

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

.do_not_reverse_lookup=(bool) ⇒ Object

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


731
732
733
734
735
736
# File 'ext/socket/basicsocket.c', line 731

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

.for_fd(fd) ⇒ Object

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


46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'ext/socket/basicsocket.c', line 46

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;
}

Instance Method Details

#close_readnil

Disallows further read using shutdown system call.

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

Returns:

  • (nil)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'ext/socket/basicsocket.c', line 121

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_writenil

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"
}

Returns:

  • (nil)


151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'ext/socket/basicsocket.c', line 151

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_addressObject

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>]
  }
}


255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# 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_lookupBoolean

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
}

Returns:

  • (Boolean)


629
630
631
632
633
634
635
636
# File 'ext/socket/basicsocket.c', line 629

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) ⇒ Object

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"]
}


652
653
654
655
656
657
658
659
660
661
662
663
664
665
# File 'ext/socket/basicsocket.c', line 652

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;
}

#getpeereidArray

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
}

Returns:



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'ext/socket/basicsocket.c', line 447

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
}

#getpeernameObject

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.



409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'ext/socket/basicsocket.c', line 409

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);
}

#getsocknameObject

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.



378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'ext/socket/basicsocket.c', line 378

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) ⇒ Object

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


329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'ext/socket/basicsocket.c', line 329

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_addressObject

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>
}


499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'ext/socket/basicsocket.c', line 499

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);
}

#read_nonblock(len, str = nil, exception: true) ⇒ Object

:nodoc:



456
457
458
# File 'ext/socket/lib/socket.rb', line 456

def read_nonblock(len, str = nil, exception: true) # :nodoc:
  __read_nonblock(len, str, exception)
end

#recv(maxlen[, flags[, outbuf]]) ⇒ Object

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"
}


688
689
690
691
692
# File 'ext/socket/basicsocket.c', line 688

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

#recv_nonblock(len, flag = 0, str = nil, exception: true) ⇒ Object

call-seq: basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg

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 nil. In most cases it means the connection was closed, but for UDP connections it may mean an empty packet was received, as the underlying API makes it impossible to distinguish these two cases.

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() 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



376
377
378
# File 'ext/socket/lib/socket.rb', line 376

def recv_nonblock(len, flag = 0, str = nil, exception: true)
  __recv_nonblock(len, flag, str, exception)
end

#recvmsg(dlen = nil, flags = 0, clen = nil, scm_rights: false) ⇒ Object

call-seq:

basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]

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
}


431
432
433
# File 'ext/socket/lib/socket.rb', line 431

def recvmsg(dlen = nil, flags = 0, clen = nil, scm_rights: false)
  __recvmsg(dlen, flags, clen, scm_rights)
end

#recvmsg_nonblock(dlen = nil, flags = 0, clen = nil, scm_rights: false, exception: true) ⇒ Object

call-seq:

basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]

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.



447
448
449
450
# File 'ext/socket/lib/socket.rb', line 447

def recvmsg_nonblock(dlen = nil, flags = 0, clen = nil,
                     scm_rights: false, exception: true)
  __recvmsg_nonblock(dlen, flags, clen, scm_rights, exception)
end

#remote_addressObject

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>
}


533
534
535
536
537
538
539
540
541
542
543
544
545
546
# File 'ext/socket/basicsocket.c', line 533

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]) ⇒ Object

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
}


565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
# File 'ext/socket/basicsocket.c', line 565

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) ⇒ Object

call-seq:

basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent

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)


307
308
309
# 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, exception: true) ⇒ Object

call-seq:

basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) => numbytes_sent

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.



323
324
325
326
# 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) ⇒ Object #setsockopt(socketoption) ⇒ Object

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)


223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'ext/socket/basicsocket.c', line 223

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

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"
    

    }

Returns:

  • (0)


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'ext/socket/basicsocket.c', line 88

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);
}

#write_nonblock(buf, exception: true) ⇒ Object

:nodoc:



460
461
462
# File 'ext/socket/lib/socket.rb', line 460

def write_nonblock(buf, exception: true) # :nodoc:
  __write_nonblock(buf, exception)
end