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