Class: UNIXSocket
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
| Subclasses: | |
| Super Chains via Extension / Inclusion / Inheritance | |
| Class Chain: 
          self,
           ::BasicSocket,::IO | |
| Instance Chain: 
          self,
           ::BasicSocket,::IO | |
| Inherits: | BasicSocket 
 | 
| Defined in: | ext/socket/unixsocket.c | 
Overview
UNIXSocket represents a UNIX domain stream client socket.
Class Attribute Summary
::BasicSocket - Inherited
| .do_not_reverse_lookup | Gets the global do_not_reverse_lookup flag. | 
| .do_not_reverse_lookup= | Sets the global do_not_reverse_lookup flag. | 
Class Method Summary
- 
    
      .new(path)  ⇒ UNIXSocket 
    
    constructor
    Creates a new UNIX client socket connected to path. 
- 
    
      .pair([type [, protocol]])  ⇒ UNIXSocket 
      (also: .socketpair)
    
    Creates a pair of sockets connected to each other. 
- 
    
      .socketpair([type [, protocol]])  ⇒ UNIXSocket 
    
    Alias for .pair. 
::BasicSocket - Inherited
| .for_fd | Returns a socket object which contains the file descriptor, fd. | 
Instance Attribute Summary
::BasicSocket - Inherited
| #do_not_reverse_lookup | Gets the do_not_reverse_lookup flag of basicsocket. | 
| #do_not_reverse_lookup= | Sets the do_not_reverse_lookup flag of basicsocket. | 
Instance Method Summary
- 
    
      #addr  ⇒ Array, unix_path 
    
    Returns the local address as an array which contains address_family and unix_path. 
- 
    
      #path  ⇒ path 
    
    Returns the path of the local address of unixsocket. 
- 
    
      #peeraddr  ⇒ Array, unix_path 
    
    Returns the remote address as an array which contains address_family and unix_path. 
- 
    
      #recv_io([klass [, mode]])  ⇒ IO 
    
    Example. 
- 
    
      #recvfrom(maxlen [, flags[, outbuf]])  ⇒ Array, unixaddress 
    
    Receives a message via unixsocket. 
- 
    
      #send_io(io)  ⇒ nil 
    
    Sends io as file descriptor passing. 
::BasicSocket - Inherited
| #close_read | Disallows further read using shutdown system call. | 
| #close_write | Disallows further write using shutdown system call. | 
| #connect_address | Returns an address of the socket suitable for connect in the local machine. | 
| #getpeereid | Returns the user and group on the peer of the UNIX socket. | 
| #getpeername | Returns the remote address of the socket as a sockaddr string. | 
| #getsockname | Returns the local address of the socket as a sockaddr string. | 
| #getsockopt | Gets a socket option. | 
| #local_address | Returns an  | 
| #recv | Receives a message. | 
| #recv_nonblock | Receives up to maxlen bytes from  | 
| #recvmsg | recvmsg receives a message using recvmsg(2) system call in blocking manner. | 
| #recvmsg_nonblock | recvmsg receives a message using recvmsg(2) system call in non-blocking manner. | 
| #remote_address | Returns an  | 
| #send | send mesg via basicsocket. | 
| #sendmsg | sendmsg sends a message using sendmsg(2) system call in blocking manner. | 
| #sendmsg_nonblock | sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner. | 
| #setsockopt | Sets a socket option. | 
| #shutdown | Calls shutdown(2) system call. | 
| #__recvmsg, #__recvmsg_nonblock, #__sendmsg, #__sendmsg_nonblock, #read_nonblock, #write_nonblock, #__read_nonblock, #__recv_nonblock, #__write_nonblock | |
Constructor Details
    .new(path)  ⇒ UNIXSocket   
Creates a new UNIX client socket connected to path.
require 'socket'
s = UNIXSocket.new("/tmp/sock")
s.send "hello", 0# File 'ext/socket/unixsocket.c', line 127
static VALUE
unix_init(VALUE sock, VALUE path)
{
    return rsock_init_unixsock(sock, path, 0);
}
  Class Method Details
    
      .pair([type [, protocol]])  ⇒ UNIXSocket 
      .socketpair([type [, protocol]])  ⇒ UNIXSocket 
    
    Also known as: .socketpair
  
UNIXSocket 
      .socketpair([type [, protocol]])  ⇒ UNIXSocket 
    Creates a pair of sockets connected to each other.
type should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
protocol should be a protocol defined in the domain. 0 is default protocol for the domain.
s1, s2 = UNIXSocket.pair
s1.send "a", 0
s1.send "b", 0
p s2.recv(10) #=> "ab"# File 'ext/socket/unixsocket.c', line 554
static VALUE
unix_s_socketpair(int argc, VALUE *argv, VALUE klass)
{
    VALUE domain, type, protocol;
    VALUE args[3];
    domain = INT2FIX(PF_UNIX);
    rb_scan_args(argc, argv, "02", &type, &protocol);
    if (argc == 0)
        type = INT2FIX(SOCK_STREAM);
    if (argc <= 1)
        protocol = INT2FIX(0);
    args[0] = domain;
    args[1] = type;
    args[2] = protocol;
    return rsock_sock_s_socketpair(3, args, klass);
}
  
    
      .pair([type [, protocol]])  ⇒ UNIXSocket 
      .socketpair([type [, protocol]])  ⇒ UNIXSocket 
    
  
UNIXSocket 
      .socketpair([type [, protocol]])  ⇒ UNIXSocket 
    Alias for .pair.
Instance Method Details
    #addr  ⇒ Array, unix_path   
Returns the local address as an array which contains address_family and unix_path.
Example
serv = UNIXServer.new("/tmp/sock")
p serv.addr #=> ["AF_UNIX", "/tmp/sock"]# File 'ext/socket/unixsocket.c', line 492
static VALUE
unix_addr(VALUE sock)
{
    rb_io_t *fptr;
    struct sockaddr_un addr;
    socklen_t len = (socklen_t)sizeof addr;
    socklen_t len0 = len;
    GetOpenFile(sock, fptr);
    if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
        rsock_sys_fail_path("getsockname(2)", fptr->pathv);
    if (len0 < len) len = len0;
    return rsock_unixaddr(&addr, len);
}
  #path ⇒ path
Returns the path of the local address of unixsocket.
s = UNIXServer.new("/tmp/sock")
p s.path #=> "/tmp/sock"# File 'ext/socket/unixsocket.c', line 143
static VALUE
unix_path(VALUE sock)
{
    rb_io_t *fptr;
    GetOpenFile(sock, fptr);
    if (NIL_P(fptr->pathv)) {
        struct sockaddr_un addr;
        socklen_t len = (socklen_t)sizeof(addr);
        socklen_t len0 = len;
        if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
            rsock_sys_fail_path("getsockname(2)", fptr->pathv);
        if (len0 < len) len = len0;
        fptr->pathv = rb_obj_freeze(rsock_unixpath_str(&addr, len));
    }
    return rb_str_dup(fptr->pathv);
}
  
    #peeraddr  ⇒ Array, unix_path   
Returns the remote address as an array which contains address_family and unix_path.
Example
serv = UNIXServer.new("/tmp/sock")
c = UNIXSocket.new("/tmp/sock")
p c.peeraddr #=> ["AF_UNIX", "/tmp/sock"]# File 'ext/socket/unixsocket.c', line 520
static VALUE
unix_peeraddr(VALUE sock)
{
    rb_io_t *fptr;
    struct sockaddr_un addr;
    socklen_t len = (socklen_t)sizeof addr;
    socklen_t len0 = len;
    GetOpenFile(sock, fptr);
    if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
        rsock_sys_fail_path("getpeername(2)", fptr->pathv);
    if (len0 < len) len = len0;
    return rsock_unixaddr(&addr, len);
}
  #recv_io([klass [, mode]]) ⇒ IO
Example
UNIXServer.open("/tmp/sock") {|serv|
  UNIXSocket.open("/tmp/sock") {|c|
    s = serv.accept
    c.send_io STDOUT
    stdout = s.recv_io
    p STDOUT.fileno #=> 1
    p stdout.fileno #=> 7
    stdout.puts "hello" # outputs "hello\n" to standard output.
  }
}klass will determine the class of io returned (using the IO.for_fd singleton method or similar). If klass is nil, an integer file descriptor is returned.
mode is the same as the argument passed to IO.for_fd
# File 'ext/socket/unixsocket.c', line 337
static VALUE
unix_recv_io(int argc, VALUE *argv, VALUE sock)
{
    VALUE klass, mode;
    rb_io_t *fptr;
    struct iomsg_arg arg;
    struct iovec vec[2];
    char buf[1];
    unsigned int gc_reason = 0;
    enum {
        GC_REASON_EMSGSIZE = 0x1,
        GC_REASON_TRUNCATE = 0x2,
        GC_REASON_ENOMEM = 0x4
    };
    int fd;
#if FD_PASSING_BY_MSG_CONTROL
    union {
        struct cmsghdr hdr;
        char pad[sizeof(struct cmsghdr)8sizeof(int)+8];
    } cmsg;
#endif
    rb_scan_args(argc, argv, "02", &klass, &mode);
    if (argc == 0)
        klass = rb_cIO;
    if (argc <= 1)
        mode = Qnil;
retry:
    GetOpenFile(sock, fptr);
    arg.msg.msg_name = NULL;
    arg.msg.msg_namelen = 0;
    vec[0].iov_base = buf;
    vec[0].iov_len = sizeof(buf);
    arg.msg.msg_iov = vec;
    arg.msg.msg_iovlen = 1;
#if FD_PASSING_BY_MSG_CONTROL
    arg.msg.msg_control = (caddr_t)&cmsg;
    arg.msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof(int));
    arg.msg.msg_flags = 0;
    cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
    cmsg.hdr.cmsg_level = SOL_SOCKET;
    cmsg.hdr.cmsg_type = SCM_RIGHTS;
    fd = -1;
    memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
#else
    arg.msg.msg_accrights = (caddr_t)&fd;
    arg.msg.msg_accrightslen = sizeof(fd);
    fd = -1;
#endif
    arg.fd = fptr->fd;
    while ((int)BLOCKING_REGION_FD(recvmsg_blocking, &arg) == -1) {
        int e = errno;
        if (e == EMSGSIZE && !(gc_reason & GC_REASON_EMSGSIZE)) {
            /* FreeBSD gets here when we're out of FDs */
            gc_reason |= GC_REASON_EMSGSIZE;
            rb_gc_for_fd(EMFILE);
            goto retry;
        }
        else if (e == ENOMEM && !(gc_reason & GC_REASON_ENOMEM)) {
            /* ENOMEM is documented in recvmsg manpages */
            gc_reason |= GC_REASON_ENOMEM;
            rb_gc_for_fd(e);
            goto retry;
        }
        if (!rb_io_wait_readable(arg.fd))
            rsock_syserr_fail_path(e, "recvmsg(2)", fptr->pathv);
    }
#if FD_PASSING_BY_MSG_CONTROL
    if (arg.msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr)) {
        /* FreeBSD and Linux both get here when we're out of FDs */
        if (!(gc_reason & GC_REASON_TRUNCATE)) {
            gc_reason |= GC_REASON_TRUNCATE;
            rb_gc_for_fd(EMFILE);
            goto retry;
        }
        rb_raise(rb_eSocket,
                 "file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)",
                 (int)arg.msg.msg_controllen, (int)sizeof(struct cmsghdr));
    }
    if (cmsg.hdr.cmsg_level != SOL_SOCKET) {
        rb_raise(rb_eSocket,
                 "file descriptor was not passed (cmsg_level=%d, %d expected)",
                 cmsg.hdr.cmsg_level, SOL_SOCKET);
    }
    if (cmsg.hdr.cmsg_type != SCM_RIGHTS) {
        rb_raise(rb_eSocket,
                 "file descriptor was not passed (cmsg_type=%d, %d expected)",
                 cmsg.hdr.cmsg_type, SCM_RIGHTS);
    }
    if (arg.msg.msg_controllen < (socklen_t)CMSG_LEN(sizeof(int))) {
        rb_raise(rb_eSocket,
                 "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)",
                 (int)arg.msg.msg_controllen, (int)CMSG_LEN(sizeof(int)));
    }
    if ((socklen_t)CMSG_SPACE(sizeof(int)) < arg.msg.msg_controllen) {
        rb_raise(rb_eSocket,
                 "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)",
                 (int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int)));
    }
    if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) {
        rsock_discard_cmsg_resource(&arg.msg, 0);
        rb_raise(rb_eSocket,
                 "file descriptor was not passed (cmsg_len=%d, %d expected)",
                 (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int)));
    }
#else
    if (arg.msg.msg_accrightslen != sizeof(fd)) {
        rb_raise(rb_eSocket,
                 "file descriptor was not passed (accrightslen=%d, %d expected)",
                 arg.msg.msg_accrightslen, (int)sizeof(fd));
    }
#endif
#if FD_PASSING_BY_MSG_CONTROL
    memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
#endif
    rb_update_max_fd(fd);
    rb_maygvl_fd_fix_cloexec(fd);
    if (klass == Qnil)
        return INT2FIX(fd);
    else {
        ID for_fd;
        int ff_argc;
        VALUE ff_argv[2];
        CONST_ID(for_fd, "for_fd");
        ff_argc = mode == Qnil ? 1 : 2;
        ff_argv[0] = INT2FIX(fd);
        ff_argv[1] = mode;
        return rb_funcallv(klass, for_fd, ff_argc, ff_argv);
    }
}
  
    #recvfrom(maxlen [, flags[, outbuf]])  ⇒ Array, unixaddress   
Receives a message via unixsocket.
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.
s1 = Socket.new(:UNIX, :DGRAM, 0)
s1_ai = Addrinfo.unix("/tmp/sock1")
s1.bind(s1_ai)
s2 = Socket.new(:UNIX, :DGRAM, 0)
s2_ai = Addrinfo.unix("/tmp/sock2")
s2.bind(s2_ai)
s3 = UNIXSocket.for_fd(s2.fileno)
s1.send "a", 0, s2_ai
p s3.recvfrom(10) #=> ["a", ["AF_UNIX", "/tmp/sock1"]]# File 'ext/socket/unixsocket.c', line 187
static VALUE
unix_recvfrom(int argc, VALUE *argv, VALUE sock)
{
    return rsock_s_recvfrom(sock, argc, argv, RECV_UNIX);
}
  
    #send_io(io)  ⇒ nil   
# File 'ext/socket/unixsocket.c', line 236
static VALUE
unix_send_io(VALUE sock, VALUE val)
{
    int fd;
    rb_io_t *fptr;
    struct iomsg_arg arg;
    struct iovec vec[1];
    char buf[1];
#if FD_PASSING_BY_MSG_CONTROL
    union {
        struct cmsghdr hdr;
        char pad[sizeof(struct cmsghdr)8sizeof(int)+8];
    } cmsg;
#endif
    if (rb_obj_is_kind_of(val, rb_cIO)) {
        rb_io_t *valfptr;
        GetOpenFile(val, valfptr);
        fd = valfptr->fd;
    }
    else if (FIXNUM_P(val)) {
        fd = FIX2INT(val);
    }
    else {
        rb_raise(rb_eTypeError, "neither IO nor file descriptor");
    }
    GetOpenFile(sock, fptr);
    arg.msg.msg_name = NULL;
    arg.msg.msg_namelen = 0;
    /* Linux and Solaris doesn't work if msg_iov is NULL. */
    buf[0] = '\0';
    vec[0].iov_base = buf;
    vec[0].iov_len = 1;
    arg.msg.msg_iov = vec;
    arg.msg.msg_iovlen = 1;
#if FD_PASSING_BY_MSG_CONTROL
    arg.msg.msg_control = (caddr_t)&cmsg;
    arg.msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof(int));
    arg.msg.msg_flags = 0;
    MEMZERO((char*)&cmsg, char, sizeof(cmsg));
    cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
    cmsg.hdr.cmsg_level = SOL_SOCKET;
    cmsg.hdr.cmsg_type = SCM_RIGHTS;
    memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
#else
    arg.msg.msg_accrights = (caddr_t)&fd;
    arg.msg.msg_accrightslen = sizeof(fd);
#endif
    arg.fd = fptr->fd;
    while ((int)BLOCKING_REGION_FD(sendmsg_blocking, &arg) == -1) {
        if (!rb_io_wait_writable(arg.fd))
            rsock_sys_fail_path("sendmsg(2)", fptr->pathv);
    }
    return Qnil;
}