Ruby  2.1.10p492(2016-04-01revision54464)
unixsocket.c
Go to the documentation of this file.
1 /************************************************
2 
3  unixsocket.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 
13 #ifdef HAVE_SYS_UN_H
14 struct unixsock_arg {
15  struct sockaddr_un *sockaddr;
16  socklen_t sockaddrlen;
17  int fd;
18 };
19 
20 static VALUE
21 unixsock_connect_internal(VALUE a)
22 {
23  struct unixsock_arg *arg = (struct unixsock_arg *)a;
24  return (VALUE)rsock_connect(arg->fd, (struct sockaddr*)arg->sockaddr,
25  arg->sockaddrlen, 0);
26 }
27 
28 VALUE
29 rsock_init_unixsock(VALUE sock, VALUE path, int server)
30 {
31  struct sockaddr_un sockaddr;
32  socklen_t sockaddrlen;
33  int fd, status;
34  rb_io_t *fptr;
35 
36  SafeStringValue(path);
37  fd = rsock_socket(AF_UNIX, SOCK_STREAM, 0);
38  if (fd < 0) {
39  rsock_sys_fail_path("socket(2)", path);
40  }
41 
42  INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
43  if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
44  rb_raise(rb_eArgError, "too long unix socket path (%ldbytes given but %dbytes max)",
45  RSTRING_LEN(path), (int)sizeof(sockaddr.sun_path));
46  }
47  memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
48  sockaddrlen = rsock_unix_sockaddr_len(path);
49 
50  if (server) {
51  status = bind(fd, (struct sockaddr*)&sockaddr, sockaddrlen);
52  }
53  else {
54  int prot;
55  struct unixsock_arg arg;
56  arg.sockaddr = &sockaddr;
57  arg.sockaddrlen = sockaddrlen;
58  arg.fd = fd;
59  status = (int)rb_protect(unixsock_connect_internal, (VALUE)&arg, &prot);
60  if (prot) {
61  close(fd);
62  rb_jump_tag(prot);
63  }
64  }
65 
66  if (status < 0) {
67  close(fd);
68  rsock_sys_fail_path("connect(2)", path);
69  }
70 
71  if (server) {
72  if (listen(fd, SOMAXCONN) < 0) {
73  close(fd);
74  rsock_sys_fail_path("listen(2)", path);
75  }
76  }
77 
78  rsock_init_sock(sock, fd);
79  if (server) {
80  GetOpenFile(sock, fptr);
81  fptr->pathv = rb_str_new_frozen(path);
82  }
83 
84  return sock;
85 }
86 
87 /*
88  * call-seq:
89  * UNIXSocket.new(path) => unixsocket
90  *
91  * Creates a new UNIX client socket connected to _path_.
92  *
93  * s = UNIXSocket.new("/tmp/sock")
94  * s.send "hello", 0
95  *
96  */
97 static VALUE
98 unix_init(VALUE sock, VALUE path)
99 {
100  return rsock_init_unixsock(sock, path, 0);
101 }
102 
103 /*
104  * call-seq:
105  * unixsocket.path => path
106  *
107  * Returns the path of the local address of unixsocket.
108  *
109  * s = UNIXServer.new("/tmp/sock")
110  * p s.path #=> "/tmp/sock"
111  *
112  */
113 static VALUE
114 unix_path(VALUE sock)
115 {
116  rb_io_t *fptr;
117 
118  GetOpenFile(sock, fptr);
119  if (NIL_P(fptr->pathv)) {
120  struct sockaddr_un addr;
121  socklen_t len = (socklen_t)sizeof(addr);
122  socklen_t len0 = len;
123  if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
124  rsock_sys_fail_path("getsockname(2)", fptr->pathv);
125  if (len0 < len) len = len0;
126  fptr->pathv = rb_obj_freeze(rsock_unixpath_str(&addr, len));
127  }
128  return rb_str_dup(fptr->pathv);
129 }
130 
131 /*
132  * call-seq:
133  * unixsocket.recvfrom(maxlen [, flags]) => [mesg, unixaddress]
134  *
135  * Receives a message via _unixsocket_.
136  *
137  * _maxlen_ is the maximum number of bytes to receive.
138  *
139  * _flags_ should be a bitwise OR of Socket::MSG_* constants.
140  *
141  * s1 = Socket.new(:UNIX, :DGRAM, 0)
142  * s1_ai = Addrinfo.unix("/tmp/sock1")
143  * s1.bind(s1_ai)
144  *
145  * s2 = Socket.new(:UNIX, :DGRAM, 0)
146  * s2_ai = Addrinfo.unix("/tmp/sock2")
147  * s2.bind(s2_ai)
148  * s3 = UNIXSocket.for_fd(s2.fileno)
149  *
150  * s1.send "a", 0, s2_ai
151  * p s3.recvfrom(10) #=> ["a", ["AF_UNIX", "/tmp/sock1"]]
152  *
153  */
154 static VALUE
155 unix_recvfrom(int argc, VALUE *argv, VALUE sock)
156 {
157  return rsock_s_recvfrom(sock, argc, argv, RECV_UNIX);
158 }
159 
160 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(SCM_RIGHTS)
161 #define FD_PASSING_BY_MSG_CONTROL 1
162 #else
163 #define FD_PASSING_BY_MSG_CONTROL 0
164 #endif
165 
166 #if defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
167 #define FD_PASSING_BY_MSG_ACCRIGHTS 1
168 #else
169 #define FD_PASSING_BY_MSG_ACCRIGHTS 0
170 #endif
171 
172 struct iomsg_arg {
173  int fd;
174  struct msghdr msg;
175 };
176 
177 #if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
178 static VALUE
179 sendmsg_blocking(void *data)
180 {
181  struct iomsg_arg *arg = data;
182  return sendmsg(arg->fd, &arg->msg, 0);
183 }
184 
185 /*
186  * call-seq:
187  * unixsocket.send_io(io) => nil
188  *
189  * Sends _io_ as file descriptor passing.
190  *
191  * s1, s2 = UNIXSocket.pair
192  *
193  * s1.send_io STDOUT
194  * stdout = s2.recv_io
195  *
196  * p STDOUT.fileno #=> 1
197  * p stdout.fileno #=> 6
198  *
199  * stdout.puts "hello" # outputs "hello\n" to standard output.
200  */
201 static VALUE
202 unix_send_io(VALUE sock, VALUE val)
203 {
204  int fd;
205  rb_io_t *fptr;
206  struct iomsg_arg arg;
207  struct iovec vec[1];
208  char buf[1];
209 
210 #if FD_PASSING_BY_MSG_CONTROL
211  union {
212  struct cmsghdr hdr;
213  char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8];
214  } cmsg;
215 #endif
216 
217  if (rb_obj_is_kind_of(val, rb_cIO)) {
218  rb_io_t *valfptr;
219  GetOpenFile(val, valfptr);
220  fd = valfptr->fd;
221  }
222  else if (FIXNUM_P(val)) {
223  fd = FIX2INT(val);
224  }
225  else {
226  rb_raise(rb_eTypeError, "neither IO nor file descriptor");
227  }
228 
229  GetOpenFile(sock, fptr);
230 
231  arg.msg.msg_name = NULL;
232  arg.msg.msg_namelen = 0;
233 
234  /* Linux and Solaris doesn't work if msg_iov is NULL. */
235  buf[0] = '\0';
236  vec[0].iov_base = buf;
237  vec[0].iov_len = 1;
238  arg.msg.msg_iov = vec;
239  arg.msg.msg_iovlen = 1;
240 
241 #if FD_PASSING_BY_MSG_CONTROL
242  arg.msg.msg_control = (caddr_t)&cmsg;
243  arg.msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof(int));
244  arg.msg.msg_flags = 0;
245  MEMZERO((char*)&cmsg, char, sizeof(cmsg));
246  cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
247  cmsg.hdr.cmsg_level = SOL_SOCKET;
248  cmsg.hdr.cmsg_type = SCM_RIGHTS;
249  memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
250 #else
251  arg.msg.msg_accrights = (caddr_t)&fd;
252  arg.msg.msg_accrightslen = sizeof(fd);
253 #endif
254 
255  arg.fd = fptr->fd;
256  while ((int)BLOCKING_REGION_FD(sendmsg_blocking, &arg) == -1) {
257  if (!rb_io_wait_writable(arg.fd))
258  rsock_sys_fail_path("sendmsg(2)", fptr->pathv);
259  }
260 
261  return Qnil;
262 }
263 #else
264 #define unix_send_io rb_f_notimplement
265 #endif
266 
267 #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
268 static VALUE
269 recvmsg_blocking(void *data)
270 {
271  struct iomsg_arg *arg = data;
272  int flags = 0;
273  return rsock_recvmsg(arg->fd, &arg->msg, flags);
274 }
275 
276 /*
277  * call-seq:
278  * unixsocket.recv_io([klass [, mode]]) => io
279  *
280  * UNIXServer.open("/tmp/sock") {|serv|
281  * UNIXSocket.open("/tmp/sock") {|c|
282  * s = serv.accept
283  *
284  * c.send_io STDOUT
285  * stdout = s.recv_io
286  *
287  * p STDOUT.fileno #=> 1
288  * p stdout.fileno #=> 7
289  *
290  * stdout.puts "hello" # outputs "hello\n" to standard output.
291  * }
292  * }
293  *
294  */
295 static VALUE
296 unix_recv_io(int argc, VALUE *argv, VALUE sock)
297 {
298  VALUE klass, mode;
299  rb_io_t *fptr;
300  struct iomsg_arg arg;
301  struct iovec vec[2];
302  char buf[1];
303 
304  int fd;
305 #if FD_PASSING_BY_MSG_CONTROL
306  union {
307  struct cmsghdr hdr;
308  char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8];
309  } cmsg;
310 #endif
311 
312  rb_scan_args(argc, argv, "02", &klass, &mode);
313  if (argc == 0)
314  klass = rb_cIO;
315  if (argc <= 1)
316  mode = Qnil;
317 
318  GetOpenFile(sock, fptr);
319 
320  arg.msg.msg_name = NULL;
321  arg.msg.msg_namelen = 0;
322 
323  vec[0].iov_base = buf;
324  vec[0].iov_len = sizeof(buf);
325  arg.msg.msg_iov = vec;
326  arg.msg.msg_iovlen = 1;
327 
328 #if FD_PASSING_BY_MSG_CONTROL
329  arg.msg.msg_control = (caddr_t)&cmsg;
330  arg.msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof(int));
331  arg.msg.msg_flags = 0;
332  cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
333  cmsg.hdr.cmsg_level = SOL_SOCKET;
334  cmsg.hdr.cmsg_type = SCM_RIGHTS;
335  fd = -1;
336  memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
337 #else
338  arg.msg.msg_accrights = (caddr_t)&fd;
339  arg.msg.msg_accrightslen = sizeof(fd);
340  fd = -1;
341 #endif
342 
343  arg.fd = fptr->fd;
344  while ((int)BLOCKING_REGION_FD(recvmsg_blocking, &arg) == -1) {
345  if (!rb_io_wait_readable(arg.fd))
346  rsock_sys_fail_path("recvmsg(2)", fptr->pathv);
347  }
348 
349 #if FD_PASSING_BY_MSG_CONTROL
350  if (arg.msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr)) {
352  "file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)",
353  (int)arg.msg.msg_controllen, (int)sizeof(struct cmsghdr));
354  }
355  if (cmsg.hdr.cmsg_level != SOL_SOCKET) {
357  "file descriptor was not passed (cmsg_level=%d, %d expected)",
358  cmsg.hdr.cmsg_level, SOL_SOCKET);
359  }
360  if (cmsg.hdr.cmsg_type != SCM_RIGHTS) {
362  "file descriptor was not passed (cmsg_type=%d, %d expected)",
363  cmsg.hdr.cmsg_type, SCM_RIGHTS);
364  }
365  if (arg.msg.msg_controllen < (socklen_t)CMSG_LEN(sizeof(int))) {
367  "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)",
368  (int)arg.msg.msg_controllen, (int)CMSG_LEN(sizeof(int)));
369  }
370  if ((socklen_t)CMSG_SPACE(sizeof(int)) < arg.msg.msg_controllen) {
372  "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)",
373  (int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int)));
374  }
375  if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) {
376  rsock_discard_cmsg_resource(&arg.msg, 0);
378  "file descriptor was not passed (cmsg_len=%d, %d expected)",
379  (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int)));
380  }
381 #else
382  if (arg.msg.msg_accrightslen != sizeof(fd)) {
384  "file descriptor was not passed (accrightslen=%d, %d expected)",
385  arg.msg.msg_accrightslen, (int)sizeof(fd));
386  }
387 #endif
388 
389 #if FD_PASSING_BY_MSG_CONTROL
390  memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
391 #endif
392  rb_fd_fix_cloexec(fd);
393 
394  if (klass == Qnil)
395  return INT2FIX(fd);
396  else {
397  ID for_fd;
398  int ff_argc;
399  VALUE ff_argv[2];
400  CONST_ID(for_fd, "for_fd");
401  ff_argc = mode == Qnil ? 1 : 2;
402  ff_argv[0] = INT2FIX(fd);
403  ff_argv[1] = mode;
404  return rb_funcall2(klass, for_fd, ff_argc, ff_argv);
405  }
406 }
407 #else
408 #define unix_recv_io rb_f_notimplement
409 #endif
410 
411 /*
412  * call-seq:
413  * unixsocket.addr => [address_family, unix_path]
414  *
415  * Returns the local address as an array which contains
416  * address_family and unix_path.
417  *
418  * Example
419  * serv = UNIXServer.new("/tmp/sock")
420  * p serv.addr #=> ["AF_UNIX", "/tmp/sock"]
421  */
422 static VALUE
423 unix_addr(VALUE sock)
424 {
425  rb_io_t *fptr;
426  struct sockaddr_un addr;
427  socklen_t len = (socklen_t)sizeof addr;
428  socklen_t len0 = len;
429 
430  GetOpenFile(sock, fptr);
431 
432  if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
433  rsock_sys_fail_path("getsockname(2)", fptr->pathv);
434  if (len0 < len) len = len0;
435  return rsock_unixaddr(&addr, len);
436 }
437 
438 /*
439  * call-seq:
440  * unixsocket.peeraddr => [address_family, unix_path]
441  *
442  * Returns the remote address as an array which contains
443  * address_family and unix_path.
444  *
445  * Example
446  * serv = UNIXServer.new("/tmp/sock")
447  * c = UNIXSocket.new("/tmp/sock")
448  * p c.peeraddr #=> ["AF_UNIX", "/tmp/sock"]
449  */
450 static VALUE
451 unix_peeraddr(VALUE sock)
452 {
453  rb_io_t *fptr;
454  struct sockaddr_un addr;
455  socklen_t len = (socklen_t)sizeof addr;
456  socklen_t len0 = len;
457 
458  GetOpenFile(sock, fptr);
459 
460  if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
461  rsock_sys_fail_path("getpeername(2)", fptr->pathv);
462  if (len0 < len) len = len0;
463  return rsock_unixaddr(&addr, len);
464 }
465 
466 /*
467  * call-seq:
468  * UNIXSocket.pair([type [, protocol]]) => [unixsocket1, unixsocket2]
469  * UNIXSocket.socketpair([type [, protocol]]) => [unixsocket1, unixsocket2]
470  *
471  * Creates a pair of sockets connected each other.
472  *
473  * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
474  *
475  * _protocol_ should be a protocol defined in the domain.
476  * 0 is default protocol for the domain.
477  *
478  * s1, s2 = UNIXSocket.pair
479  * s1.send "a", 0
480  * s1.send "b", 0
481  * p s2.recv(10) #=> "ab"
482  *
483  */
484 static VALUE
485 unix_s_socketpair(int argc, VALUE *argv, VALUE klass)
486 {
487  VALUE domain, type, protocol;
488  VALUE args[3];
489 
490  domain = INT2FIX(PF_UNIX);
491  rb_scan_args(argc, argv, "02", &type, &protocol);
492  if (argc == 0)
493  type = INT2FIX(SOCK_STREAM);
494  if (argc <= 1)
495  protocol = INT2FIX(0);
496 
497  args[0] = domain;
498  args[1] = type;
499  args[2] = protocol;
500 
501  return rsock_sock_s_socketpair(3, args, klass);
502 }
503 #endif
504 
505 void
507 {
508 #ifdef HAVE_SYS_UN_H
509  /*
510  * Document-class: UNIXSocket < BasicSocket
511  *
512  * UNIXSocket represents a UNIX domain stream client socket.
513  */
514  rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket);
515  rb_define_method(rb_cUNIXSocket, "initialize", unix_init, 1);
516  rb_define_method(rb_cUNIXSocket, "path", unix_path, 0);
517  rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0);
518  rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0);
519  rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
520  rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1);
521  rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1);
522  rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1);
523  rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1);
524 #endif
525 }
VALUE data
Definition: tcltklib.c:3360
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server)
VP_EXPORT int
Definition: bigdecimal.c:5172
rb_funcall2(argv[0], id_yield, argc-1, argv+1)
VALUE rb_cBasicSocket
Definition: init.c:13
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1646
int sendmsg(int, const struct msghdr *, int)
Definition: win32.c:3442
Definition: io.h:61
Definition: win32.h:235
int status
Definition: tcltklib.c:2197
Real * a
Definition: bigdecimal.c:1198
VALUE rb_obj_freeze(VALUE)
Definition: object.c:1070
VALUE rb_eTypeError
Definition: error.c:548
VALUE rsock_init_sock(VALUE sock, int fd)
Definition: init.c:43
gz path
Definition: zlib.c:2279
void rsock_init_unixsocket(void)
Definition: unixsocket.c:506
#define RSTRING_PTR(str)
NIL_P(eventloop_thread)
Definition: tcltklib.c:4056
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:807
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
#define SafeStringValue(v)
#define GetOpenFile(obj, fp)
Definition: io.h:118
VALUE rb_str_new_frozen(VALUE)
Definition: string.c:833
void rb_fd_fix_cloexec(int fd)
Definition: io.c:221
#define MEMZERO(p, type, n)
#define FIXNUM_P(f)
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
#define Qnil
Definition: enum.c:67
#define val
Definition: tcltklib.c:1935
int flags
Definition: tcltklib.c:3015
unsigned long ID
Definition: ripper.y:89
int rsock_socket(int domain, int type, int proto)
Definition: init.c:288
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:611
#define RSTRING_LEN(str)
#define FIX2INT(x)
#define INT2FIX(i)
int fd
Definition: io.h:62
int rb_io_wait_writable(int)
Definition: io.c:1103
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
int len
Definition: enumerator.c:1332
VALUE arg
Definition: enum.c:2427
VALUE rb_str_dup(VALUE)
Definition: string.c:1062
VALUE * argv
Definition: tcltklib.c:1969
memcpy(buf+1, str, len)
int socklen_t
Definition: getaddrinfo.c:84
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
Definition: init.c:114
#define CONST_ID(var, str)
VALUE mode
Definition: tcltklib.c:1668
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
int type
Definition: tcltklib.c:112
int argc
Definition: tcltklib.c:1968
Definition: win32.h:231
void rb_jump_tag(int tag)
Definition: eval.c:706
RUBY_EXTERN VALUE rb_cIO
Definition: ripper.y:1577
VALUE msg
Definition: tcltklib.c:851
VALUE rb_eSocket
Definition: init.c:25
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Definition: object.c:646
#define sizeof(x)
Definition: zlib.c:58
args[0]
Definition: enum.c:585
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
Definition: init.c:389
VALUE pathv
Definition: io.h:67
klass
Definition: tcltklib.c:3496
unsigned long VALUE
Definition: ripper.y:88
void rsock_sys_fail_path(const char *mesg, VALUE path)
Definition: socket.c:33
#define NULL
Definition: _sdbm.c:102
int rb_io_wait_readable(int)
Definition: io.c:1077
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
VALUE rb_eArgError
Definition: error.c:549
#define BLOCKING_REGION_FD(func, arg)
Definition: rubysocket.h:259