00001
00002
00003
00004
00005
00006
00007
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
00090
00091
00092
00093
00094
00095
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
00106
00107
00108
00109
00110
00111
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
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
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
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
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
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
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
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
00414
00415
00416
00417
00418
00419
00420
00421
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
00441
00442
00443
00444
00445
00446
00447
00448
00449
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
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
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
00512
00513
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