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 123
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.
socktype 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 550
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 488
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 139
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 516
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 333
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 183
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 232
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; }