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