Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /************************************************ 00002 00003 unixsocket.c - 00004 00005 created at: Thu Mar 31 12:21:29 JST 1994 00006 00007 Copyright (C) 1993-2007 Yukihiro Matsumoto 00008 00009 ************************************************/ 00010 00011 #include "rubysocket.h" 00012 00013 #ifdef HAVE_SYS_UN_H 00014 struct unixsock_arg { 00015 struct sockaddr_un *sockaddr; 00016 socklen_t sockaddrlen; 00017 int fd; 00018 }; 00019 00020 static VALUE 00021 unixsock_connect_internal(VALUE a) 00022 { 00023 struct unixsock_arg *arg = (struct unixsock_arg *)a; 00024 return (VALUE)rsock_connect(arg->fd, (struct sockaddr*)arg->sockaddr, 00025 arg->sockaddrlen, 0); 00026 } 00027 00028 VALUE 00029 rsock_init_unixsock(VALUE sock, VALUE path, int server) 00030 { 00031 struct sockaddr_un sockaddr; 00032 socklen_t sockaddrlen; 00033 int fd, status; 00034 rb_io_t *fptr; 00035 00036 SafeStringValue(path); 00037 fd = rsock_socket(AF_UNIX, SOCK_STREAM, 0); 00038 if (fd < 0) { 00039 rb_sys_fail("socket(2)"); 00040 } 00041 00042 MEMZERO(&sockaddr, struct sockaddr_un, 1); 00043 sockaddr.sun_family = AF_UNIX; 00044 if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) { 00045 rb_raise(rb_eArgError, "too long unix socket path (%ldbytes given but %dbytes max)", 00046 RSTRING_LEN(path), (int)sizeof(sockaddr.sun_path)); 00047 } 00048 memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); 00049 sockaddrlen = rsock_unix_sockaddr_len(path); 00050 00051 if (server) { 00052 status = bind(fd, (struct sockaddr*)&sockaddr, sockaddrlen); 00053 } 00054 else { 00055 int prot; 00056 struct unixsock_arg arg; 00057 arg.sockaddr = &sockaddr; 00058 arg.sockaddrlen = sockaddrlen; 00059 arg.fd = fd; 00060 status = (int)rb_protect(unixsock_connect_internal, (VALUE)&arg, &prot); 00061 if (prot) { 00062 close(fd); 00063 rb_jump_tag(prot); 00064 } 00065 } 00066 00067 if (status < 0) { 00068 close(fd); 00069 rb_sys_fail_str(rb_inspect(path)); 00070 } 00071 00072 if (server) { 00073 if (listen(fd, SOMAXCONN) < 0) { 00074 close(fd); 00075 rb_sys_fail("listen(2)"); 00076 } 00077 } 00078 00079 rsock_init_sock(sock, fd); 00080 if (server) { 00081 GetOpenFile(sock, fptr); 00082 fptr->pathv = rb_str_new_frozen(path); 00083 } 00084 00085 return sock; 00086 } 00087 00088 /* 00089 * call-seq: 00090 * UNIXSocket.new(path) => unixsocket 00091 * 00092 * Creates a new UNIX client socket connected to _path_. 00093 * 00094 * s = UNIXSocket.new("/tmp/sock") 00095 * s.send "hello", 0 00096 * 00097 */ 00098 static VALUE 00099 unix_init(VALUE sock, VALUE path) 00100 { 00101 return rsock_init_unixsock(sock, path, 0); 00102 } 00103 00104 /* 00105 * call-seq: 00106 * unixsocket.path => path 00107 * 00108 * Returns the path of the local address of unixsocket. 00109 * 00110 * s = UNIXServer.new("/tmp/sock") 00111 * p s.path #=> "/tmp/sock" 00112 * 00113 */ 00114 static VALUE 00115 unix_path(VALUE sock) 00116 { 00117 rb_io_t *fptr; 00118 00119 GetOpenFile(sock, fptr); 00120 if (NIL_P(fptr->pathv)) { 00121 struct sockaddr_un addr; 00122 socklen_t len = (socklen_t)sizeof(addr); 00123 socklen_t len0 = len; 00124 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0) 00125 rb_sys_fail(0); 00126 if (len0 < len) len = len0; 00127 fptr->pathv = rb_obj_freeze(rsock_unixpath_str(&addr, len)); 00128 } 00129 return rb_str_dup(fptr->pathv); 00130 } 00131 00132 /* 00133 * call-seq: 00134 * unixsocket.recvfrom(maxlen [, flags]) => [mesg, unixaddress] 00135 * 00136 * Receives a message via _unixsocket_. 00137 * 00138 * _maxlen_ is the maximum number of bytes to receive. 00139 * 00140 * _flags_ should be a bitwise OR of Socket::MSG_* constants. 00141 * 00142 * s1 = Socket.new(:UNIX, :DGRAM, 0) 00143 * s1_ai = Addrinfo.unix("/tmp/sock1") 00144 * s1.bind(s1_ai) 00145 * 00146 * s2 = Socket.new(:UNIX, :DGRAM, 0) 00147 * s2_ai = Addrinfo.unix("/tmp/sock2") 00148 * s2.bind(s2_ai) 00149 * s3 = UNIXSocket.for_fd(s2.fileno) 00150 * 00151 * s1.send "a", 0, s2_ai 00152 * p s3.recvfrom(10) #=> ["a", ["AF_UNIX", "/tmp/sock1"]] 00153 * 00154 */ 00155 static VALUE 00156 unix_recvfrom(int argc, VALUE *argv, VALUE sock) 00157 { 00158 return rsock_s_recvfrom(sock, argc, argv, RECV_UNIX); 00159 } 00160 00161 #if defined(HAVE_ST_MSG_CONTROL) && defined(SCM_RIGHTS) 00162 #define FD_PASSING_BY_MSG_CONTROL 1 00163 #else 00164 #define FD_PASSING_BY_MSG_CONTROL 0 00165 #endif 00166 00167 #if defined(HAVE_ST_MSG_ACCRIGHTS) 00168 #define FD_PASSING_BY_MSG_ACCRIGHTS 1 00169 #else 00170 #define FD_PASSING_BY_MSG_ACCRIGHTS 0 00171 #endif 00172 00173 struct iomsg_arg { 00174 int fd; 00175 struct msghdr msg; 00176 }; 00177 00178 #if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS) 00179 static VALUE 00180 sendmsg_blocking(void *data) 00181 { 00182 struct iomsg_arg *arg = data; 00183 return sendmsg(arg->fd, &arg->msg, 0); 00184 } 00185 00186 /* 00187 * call-seq: 00188 * unixsocket.send_io(io) => nil 00189 * 00190 * Sends _io_ as file descriptor passing. 00191 * 00192 * s1, s2 = UNIXSocket.pair 00193 * 00194 * s1.send_io STDOUT 00195 * stdout = s2.recv_io 00196 * 00197 * p STDOUT.fileno #=> 1 00198 * p stdout.fileno #=> 6 00199 * 00200 * stdout.puts "hello" # outputs "hello\n" to standard output. 00201 */ 00202 static VALUE 00203 unix_send_io(VALUE sock, VALUE val) 00204 { 00205 int fd; 00206 rb_io_t *fptr; 00207 struct iomsg_arg arg; 00208 struct iovec vec[1]; 00209 char buf[1]; 00210 00211 #if FD_PASSING_BY_MSG_CONTROL 00212 struct { 00213 struct cmsghdr hdr; 00214 char pad[8+sizeof(int)+8]; 00215 } cmsg; 00216 #endif 00217 00218 if (rb_obj_is_kind_of(val, rb_cIO)) { 00219 rb_io_t *valfptr; 00220 GetOpenFile(val, valfptr); 00221 fd = valfptr->fd; 00222 } 00223 else if (FIXNUM_P(val)) { 00224 fd = FIX2INT(val); 00225 } 00226 else { 00227 rb_raise(rb_eTypeError, "neither IO nor file descriptor"); 00228 } 00229 00230 GetOpenFile(sock, fptr); 00231 00232 arg.msg.msg_name = NULL; 00233 arg.msg.msg_namelen = 0; 00234 00235 /* Linux and Solaris doesn't work if msg_iov is NULL. */ 00236 buf[0] = '\0'; 00237 vec[0].iov_base = buf; 00238 vec[0].iov_len = 1; 00239 arg.msg.msg_iov = vec; 00240 arg.msg.msg_iovlen = 1; 00241 00242 #if FD_PASSING_BY_MSG_CONTROL 00243 arg.msg.msg_control = (caddr_t)&cmsg; 00244 arg.msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof(int)); 00245 arg.msg.msg_flags = 0; 00246 MEMZERO((char*)&cmsg, char, sizeof(cmsg)); 00247 cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int)); 00248 cmsg.hdr.cmsg_level = SOL_SOCKET; 00249 cmsg.hdr.cmsg_type = SCM_RIGHTS; 00250 memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int)); 00251 #else 00252 arg.msg.msg_accrights = (caddr_t)&fd; 00253 arg.msg.msg_accrightslen = sizeof(fd); 00254 #endif 00255 00256 arg.fd = fptr->fd; 00257 while ((int)BLOCKING_REGION_FD(sendmsg_blocking, &arg) == -1) { 00258 if (!rb_io_wait_writable(arg.fd)) 00259 rb_sys_fail("sendmsg(2)"); 00260 } 00261 00262 return Qnil; 00263 } 00264 #else 00265 #define unix_send_io rb_f_notimplement 00266 #endif 00267 00268 #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS) 00269 static VALUE 00270 recvmsg_blocking(void *data) 00271 { 00272 struct iomsg_arg *arg = data; 00273 int flags = 0; 00274 return rsock_recvmsg(arg->fd, &arg->msg, flags); 00275 } 00276 00277 /* 00278 * call-seq: 00279 * unixsocket.recv_io([klass [, mode]]) => io 00280 * 00281 * UNIXServer.open("/tmp/sock") {|serv| 00282 * UNIXSocket.open("/tmp/sock") {|c| 00283 * s = serv.accept 00284 * 00285 * c.send_io STDOUT 00286 * stdout = s.recv_io 00287 * 00288 * p STDOUT.fileno #=> 1 00289 * p stdout.fileno #=> 7 00290 * 00291 * stdout.puts "hello" # outputs "hello\n" to standard output. 00292 * } 00293 * } 00294 * 00295 */ 00296 static VALUE 00297 unix_recv_io(int argc, VALUE *argv, VALUE sock) 00298 { 00299 VALUE klass, mode; 00300 rb_io_t *fptr; 00301 struct iomsg_arg arg; 00302 struct iovec vec[2]; 00303 char buf[1]; 00304 00305 int fd; 00306 #if FD_PASSING_BY_MSG_CONTROL 00307 struct { 00308 struct cmsghdr hdr; 00309 char pad[8+sizeof(int)+8]; 00310 } cmsg; 00311 #endif 00312 00313 rb_scan_args(argc, argv, "02", &klass, &mode); 00314 if (argc == 0) 00315 klass = rb_cIO; 00316 if (argc <= 1) 00317 mode = Qnil; 00318 00319 GetOpenFile(sock, fptr); 00320 00321 arg.msg.msg_name = NULL; 00322 arg.msg.msg_namelen = 0; 00323 00324 vec[0].iov_base = buf; 00325 vec[0].iov_len = sizeof(buf); 00326 arg.msg.msg_iov = vec; 00327 arg.msg.msg_iovlen = 1; 00328 00329 #if FD_PASSING_BY_MSG_CONTROL 00330 arg.msg.msg_control = (caddr_t)&cmsg; 00331 arg.msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof(int)); 00332 arg.msg.msg_flags = 0; 00333 cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int)); 00334 cmsg.hdr.cmsg_level = SOL_SOCKET; 00335 cmsg.hdr.cmsg_type = SCM_RIGHTS; 00336 fd = -1; 00337 memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int)); 00338 #else 00339 arg.msg.msg_accrights = (caddr_t)&fd; 00340 arg.msg.msg_accrightslen = sizeof(fd); 00341 fd = -1; 00342 #endif 00343 00344 arg.fd = fptr->fd; 00345 while ((int)BLOCKING_REGION_FD(recvmsg_blocking, &arg) == -1) { 00346 if (!rb_io_wait_readable(arg.fd)) 00347 rb_sys_fail("recvmsg(2)"); 00348 } 00349 00350 #if FD_PASSING_BY_MSG_CONTROL 00351 if (arg.msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr)) { 00352 rb_raise(rb_eSocket, 00353 "file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)", 00354 (int)arg.msg.msg_controllen, (int)sizeof(struct cmsghdr)); 00355 } 00356 if (cmsg.hdr.cmsg_level != SOL_SOCKET) { 00357 rb_raise(rb_eSocket, 00358 "file descriptor was not passed (cmsg_level=%d, %d expected)", 00359 cmsg.hdr.cmsg_level, SOL_SOCKET); 00360 } 00361 if (cmsg.hdr.cmsg_type != SCM_RIGHTS) { 00362 rb_raise(rb_eSocket, 00363 "file descriptor was not passed (cmsg_type=%d, %d expected)", 00364 cmsg.hdr.cmsg_type, SCM_RIGHTS); 00365 } 00366 if (arg.msg.msg_controllen < (socklen_t)CMSG_LEN(sizeof(int))) { 00367 rb_raise(rb_eSocket, 00368 "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)", 00369 (int)arg.msg.msg_controllen, (int)CMSG_LEN(sizeof(int))); 00370 } 00371 if ((socklen_t)CMSG_SPACE(sizeof(int)) < arg.msg.msg_controllen) { 00372 rb_raise(rb_eSocket, 00373 "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)", 00374 (int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int))); 00375 } 00376 if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) { 00377 rsock_discard_cmsg_resource(&arg.msg, 0); 00378 rb_raise(rb_eSocket, 00379 "file descriptor was not passed (cmsg_len=%d, %d expected)", 00380 (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int))); 00381 } 00382 #else 00383 if (arg.msg.msg_accrightslen != sizeof(fd)) { 00384 rb_raise(rb_eSocket, 00385 "file descriptor was not passed (accrightslen) : %d != %d", 00386 arg.msg.msg_accrightslen, (int)sizeof(fd)); 00387 } 00388 #endif 00389 00390 #if FD_PASSING_BY_MSG_CONTROL 00391 memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int)); 00392 #endif 00393 rb_fd_fix_cloexec(fd); 00394 00395 if (klass == Qnil) 00396 return INT2FIX(fd); 00397 else { 00398 ID for_fd; 00399 int ff_argc; 00400 VALUE ff_argv[2]; 00401 CONST_ID(for_fd, "for_fd"); 00402 ff_argc = mode == Qnil ? 1 : 2; 00403 ff_argv[0] = INT2FIX(fd); 00404 ff_argv[1] = mode; 00405 return rb_funcall2(klass, for_fd, ff_argc, ff_argv); 00406 } 00407 } 00408 #else 00409 #define unix_recv_io rb_f_notimplement 00410 #endif 00411 00412 /* 00413 * call-seq: 00414 * unixsocket.addr => [address_family, unix_path] 00415 * 00416 * Returns the local address as an array which contains 00417 * address_family and unix_path. 00418 * 00419 * Example 00420 * serv = UNIXServer.new("/tmp/sock") 00421 * p serv.addr #=> ["AF_UNIX", "/tmp/sock"] 00422 */ 00423 static VALUE 00424 unix_addr(VALUE sock) 00425 { 00426 rb_io_t *fptr; 00427 struct sockaddr_un addr; 00428 socklen_t len = (socklen_t)sizeof addr; 00429 socklen_t len0 = len; 00430 00431 GetOpenFile(sock, fptr); 00432 00433 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0) 00434 rb_sys_fail("getsockname(2)"); 00435 if (len0 < len) len = len0; 00436 return rsock_unixaddr(&addr, len); 00437 } 00438 00439 /* 00440 * call-seq: 00441 * unixsocket.peeraddr => [address_family, unix_path] 00442 * 00443 * Returns the remote address as an array which contains 00444 * address_family and unix_path. 00445 * 00446 * Example 00447 * serv = UNIXServer.new("/tmp/sock") 00448 * c = UNIXSocket.new("/tmp/sock") 00449 * p c.peeraddr #=> ["AF_UNIX", "/tmp/sock"] 00450 */ 00451 static VALUE 00452 unix_peeraddr(VALUE sock) 00453 { 00454 rb_io_t *fptr; 00455 struct sockaddr_un addr; 00456 socklen_t len = (socklen_t)sizeof addr; 00457 socklen_t len0 = len; 00458 00459 GetOpenFile(sock, fptr); 00460 00461 if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0) 00462 rb_sys_fail("getpeername(2)"); 00463 if (len0 < len) len = len0; 00464 return rsock_unixaddr(&addr, len); 00465 } 00466 00467 /* 00468 * call-seq: 00469 * UNIXSocket.pair([type [, protocol]]) => [unixsocket1, unixsocket2] 00470 * UNIXSocket.socketpair([type [, protocol]]) => [unixsocket1, unixsocket2] 00471 * 00472 * Creates a pair of sockets connected each other. 00473 * 00474 * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc. 00475 * 00476 * _protocol_ should be a protocol defined in the domain. 00477 * 0 is default protocol for the domain. 00478 * 00479 * s1, s2 = UNIXSocket.pair 00480 * s1.send "a", 0 00481 * s1.send "b", 0 00482 * p s2.recv(10) #=> "ab" 00483 * 00484 */ 00485 static VALUE 00486 unix_s_socketpair(int argc, VALUE *argv, VALUE klass) 00487 { 00488 VALUE domain, type, protocol; 00489 VALUE args[3]; 00490 00491 domain = INT2FIX(PF_UNIX); 00492 rb_scan_args(argc, argv, "02", &type, &protocol); 00493 if (argc == 0) 00494 type = INT2FIX(SOCK_STREAM); 00495 if (argc <= 1) 00496 protocol = INT2FIX(0); 00497 00498 args[0] = domain; 00499 args[1] = type; 00500 args[2] = protocol; 00501 00502 return rsock_sock_s_socketpair(3, args, klass); 00503 } 00504 #endif 00505 00506 void 00507 rsock_init_unixsocket(void) 00508 { 00509 #ifdef HAVE_SYS_UN_H 00510 /* 00511 * Document-class: UNIXSocket < BasicSocket 00512 * 00513 * UNIXSocket represents a UNIX domain stream client socket. 00514 */ 00515 rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket); 00516 rb_define_method(rb_cUNIXSocket, "initialize", unix_init, 1); 00517 rb_define_method(rb_cUNIXSocket, "path", unix_path, 0); 00518 rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0); 00519 rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0); 00520 rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1); 00521 rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1); 00522 rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1); 00523 rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1); 00524 rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1); 00525 #endif 00526 } 00527