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 rsock_sys_fail_path("socket(2)", path);
00040 }
00041
00042 INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
00043 if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
00044 rb_raise(rb_eArgError, "too long unix socket path (%ldbytes given but %dbytes max)",
00045 RSTRING_LEN(path), (int)sizeof(sockaddr.sun_path));
00046 }
00047 memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
00048 sockaddrlen = rsock_unix_sockaddr_len(path);
00049
00050 if (server) {
00051 status = bind(fd, (struct sockaddr*)&sockaddr, sockaddrlen);
00052 }
00053 else {
00054 int prot;
00055 struct unixsock_arg arg;
00056 arg.sockaddr = &sockaddr;
00057 arg.sockaddrlen = sockaddrlen;
00058 arg.fd = fd;
00059 status = (int)rb_protect(unixsock_connect_internal, (VALUE)&arg, &prot);
00060 if (prot) {
00061 close(fd);
00062 rb_jump_tag(prot);
00063 }
00064 }
00065
00066 if (status < 0) {
00067 close(fd);
00068 rsock_sys_fail_path("connect(2)", path);
00069 }
00070
00071 if (server) {
00072 if (listen(fd, SOMAXCONN) < 0) {
00073 close(fd);
00074 rsock_sys_fail_path("listen(2)", path);
00075 }
00076 }
00077
00078 rsock_init_sock(sock, fd);
00079 if (server) {
00080 GetOpenFile(sock, fptr);
00081 fptr->pathv = rb_str_new_frozen(path);
00082 }
00083
00084 return sock;
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 static VALUE
00098 unix_init(VALUE sock, VALUE path)
00099 {
00100 return rsock_init_unixsock(sock, path, 0);
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 static VALUE
00114 unix_path(VALUE sock)
00115 {
00116 rb_io_t *fptr;
00117
00118 GetOpenFile(sock, fptr);
00119 if (NIL_P(fptr->pathv)) {
00120 struct sockaddr_un addr;
00121 socklen_t len = (socklen_t)sizeof(addr);
00122 socklen_t len0 = len;
00123 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00124 rsock_sys_fail_path("getsockname(2)", fptr->pathv);
00125 if (len0 < len) len = len0;
00126 fptr->pathv = rb_obj_freeze(rsock_unixpath_str(&addr, len));
00127 }
00128 return rb_str_dup(fptr->pathv);
00129 }
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 static VALUE
00155 unix_recvfrom(int argc, VALUE *argv, VALUE sock)
00156 {
00157 return rsock_s_recvfrom(sock, argc, argv, RECV_UNIX);
00158 }
00159
00160 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) && defined(SCM_RIGHTS)
00161 #define FD_PASSING_BY_MSG_CONTROL 1
00162 #else
00163 #define FD_PASSING_BY_MSG_CONTROL 0
00164 #endif
00165
00166 #if defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS)
00167 #define FD_PASSING_BY_MSG_ACCRIGHTS 1
00168 #else
00169 #define FD_PASSING_BY_MSG_ACCRIGHTS 0
00170 #endif
00171
00172 struct iomsg_arg {
00173 int fd;
00174 struct msghdr msg;
00175 };
00176
00177 #if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
00178 static VALUE
00179 sendmsg_blocking(void *data)
00180 {
00181 struct iomsg_arg *arg = data;
00182 return sendmsg(arg->fd, &arg->msg, 0);
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 static VALUE
00202 unix_send_io(VALUE sock, VALUE val)
00203 {
00204 int fd;
00205 rb_io_t *fptr;
00206 struct iomsg_arg arg;
00207 struct iovec vec[1];
00208 char buf[1];
00209
00210 #if FD_PASSING_BY_MSG_CONTROL
00211 union {
00212 struct cmsghdr hdr;
00213 char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8];
00214 } cmsg;
00215 #endif
00216
00217 if (rb_obj_is_kind_of(val, rb_cIO)) {
00218 rb_io_t *valfptr;
00219 GetOpenFile(val, valfptr);
00220 fd = valfptr->fd;
00221 }
00222 else if (FIXNUM_P(val)) {
00223 fd = FIX2INT(val);
00224 }
00225 else {
00226 rb_raise(rb_eTypeError, "neither IO nor file descriptor");
00227 }
00228
00229 GetOpenFile(sock, fptr);
00230
00231 arg.msg.msg_name = NULL;
00232 arg.msg.msg_namelen = 0;
00233
00234
00235 buf[0] = '\0';
00236 vec[0].iov_base = buf;
00237 vec[0].iov_len = 1;
00238 arg.msg.msg_iov = vec;
00239 arg.msg.msg_iovlen = 1;
00240
00241 #if FD_PASSING_BY_MSG_CONTROL
00242 arg.msg.msg_control = (caddr_t)&cmsg;
00243 arg.msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof(int));
00244 arg.msg.msg_flags = 0;
00245 MEMZERO((char*)&cmsg, char, sizeof(cmsg));
00246 cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
00247 cmsg.hdr.cmsg_level = SOL_SOCKET;
00248 cmsg.hdr.cmsg_type = SCM_RIGHTS;
00249 memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
00250 #else
00251 arg.msg.msg_accrights = (caddr_t)&fd;
00252 arg.msg.msg_accrightslen = sizeof(fd);
00253 #endif
00254
00255 arg.fd = fptr->fd;
00256 while ((int)BLOCKING_REGION_FD(sendmsg_blocking, &arg) == -1) {
00257 if (!rb_io_wait_writable(arg.fd))
00258 rsock_sys_fail_path("sendmsg(2)", fptr->pathv);
00259 }
00260
00261 return Qnil;
00262 }
00263 #else
00264 #define unix_send_io rb_f_notimplement
00265 #endif
00266
00267 #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
00268 static VALUE
00269 recvmsg_blocking(void *data)
00270 {
00271 struct iomsg_arg *arg = data;
00272 int flags = 0;
00273 return rsock_recvmsg(arg->fd, &arg->msg, flags);
00274 }
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 static VALUE
00296 unix_recv_io(int argc, VALUE *argv, VALUE sock)
00297 {
00298 VALUE klass, mode;
00299 rb_io_t *fptr;
00300 struct iomsg_arg arg;
00301 struct iovec vec[2];
00302 char buf[1];
00303
00304 int fd;
00305 #if FD_PASSING_BY_MSG_CONTROL
00306 union {
00307 struct cmsghdr hdr;
00308 char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8];
00309 } cmsg;
00310 #endif
00311
00312 rb_scan_args(argc, argv, "02", &klass, &mode);
00313 if (argc == 0)
00314 klass = rb_cIO;
00315 if (argc <= 1)
00316 mode = Qnil;
00317
00318 GetOpenFile(sock, fptr);
00319
00320 arg.msg.msg_name = NULL;
00321 arg.msg.msg_namelen = 0;
00322
00323 vec[0].iov_base = buf;
00324 vec[0].iov_len = sizeof(buf);
00325 arg.msg.msg_iov = vec;
00326 arg.msg.msg_iovlen = 1;
00327
00328 #if FD_PASSING_BY_MSG_CONTROL
00329 arg.msg.msg_control = (caddr_t)&cmsg;
00330 arg.msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof(int));
00331 arg.msg.msg_flags = 0;
00332 cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int));
00333 cmsg.hdr.cmsg_level = SOL_SOCKET;
00334 cmsg.hdr.cmsg_type = SCM_RIGHTS;
00335 fd = -1;
00336 memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int));
00337 #else
00338 arg.msg.msg_accrights = (caddr_t)&fd;
00339 arg.msg.msg_accrightslen = sizeof(fd);
00340 fd = -1;
00341 #endif
00342
00343 arg.fd = fptr->fd;
00344 while ((int)BLOCKING_REGION_FD(recvmsg_blocking, &arg) == -1) {
00345 if (!rb_io_wait_readable(arg.fd))
00346 rsock_sys_fail_path("recvmsg(2)", fptr->pathv);
00347 }
00348
00349 #if FD_PASSING_BY_MSG_CONTROL
00350 if (arg.msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr)) {
00351 rb_raise(rb_eSocket,
00352 "file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)",
00353 (int)arg.msg.msg_controllen, (int)sizeof(struct cmsghdr));
00354 }
00355 if (cmsg.hdr.cmsg_level != SOL_SOCKET) {
00356 rb_raise(rb_eSocket,
00357 "file descriptor was not passed (cmsg_level=%d, %d expected)",
00358 cmsg.hdr.cmsg_level, SOL_SOCKET);
00359 }
00360 if (cmsg.hdr.cmsg_type != SCM_RIGHTS) {
00361 rb_raise(rb_eSocket,
00362 "file descriptor was not passed (cmsg_type=%d, %d expected)",
00363 cmsg.hdr.cmsg_type, SCM_RIGHTS);
00364 }
00365 if (arg.msg.msg_controllen < (socklen_t)CMSG_LEN(sizeof(int))) {
00366 rb_raise(rb_eSocket,
00367 "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)",
00368 (int)arg.msg.msg_controllen, (int)CMSG_LEN(sizeof(int)));
00369 }
00370 if ((socklen_t)CMSG_SPACE(sizeof(int)) < arg.msg.msg_controllen) {
00371 rb_raise(rb_eSocket,
00372 "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)",
00373 (int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int)));
00374 }
00375 if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) {
00376 rsock_discard_cmsg_resource(&arg.msg, 0);
00377 rb_raise(rb_eSocket,
00378 "file descriptor was not passed (cmsg_len=%d, %d expected)",
00379 (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int)));
00380 }
00381 #else
00382 if (arg.msg.msg_accrightslen != sizeof(fd)) {
00383 rb_raise(rb_eSocket,
00384 "file descriptor was not passed (accrightslen=%d, %d expected)",
00385 arg.msg.msg_accrightslen, (int)sizeof(fd));
00386 }
00387 #endif
00388
00389 #if FD_PASSING_BY_MSG_CONTROL
00390 memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
00391 #endif
00392 rb_fd_fix_cloexec(fd);
00393
00394 if (klass == Qnil)
00395 return INT2FIX(fd);
00396 else {
00397 ID for_fd;
00398 int ff_argc;
00399 VALUE ff_argv[2];
00400 CONST_ID(for_fd, "for_fd");
00401 ff_argc = mode == Qnil ? 1 : 2;
00402 ff_argv[0] = INT2FIX(fd);
00403 ff_argv[1] = mode;
00404 return rb_funcall2(klass, for_fd, ff_argc, ff_argv);
00405 }
00406 }
00407 #else
00408 #define unix_recv_io rb_f_notimplement
00409 #endif
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 static VALUE
00423 unix_addr(VALUE sock)
00424 {
00425 rb_io_t *fptr;
00426 struct sockaddr_un addr;
00427 socklen_t len = (socklen_t)sizeof addr;
00428 socklen_t len0 = len;
00429
00430 GetOpenFile(sock, fptr);
00431
00432 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00433 rsock_sys_fail_path("getsockname(2)", fptr->pathv);
00434 if (len0 < len) len = len0;
00435 return rsock_unixaddr(&addr, len);
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 static VALUE
00451 unix_peeraddr(VALUE sock)
00452 {
00453 rb_io_t *fptr;
00454 struct sockaddr_un addr;
00455 socklen_t len = (socklen_t)sizeof addr;
00456 socklen_t len0 = len;
00457
00458 GetOpenFile(sock, fptr);
00459
00460 if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00461 rsock_sys_fail_path("getpeername(2)", fptr->pathv);
00462 if (len0 < len) len = len0;
00463 return rsock_unixaddr(&addr, len);
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 static VALUE
00485 unix_s_socketpair(int argc, VALUE *argv, VALUE klass)
00486 {
00487 VALUE domain, type, protocol;
00488 VALUE args[3];
00489
00490 domain = INT2FIX(PF_UNIX);
00491 rb_scan_args(argc, argv, "02", &type, &protocol);
00492 if (argc == 0)
00493 type = INT2FIX(SOCK_STREAM);
00494 if (argc <= 1)
00495 protocol = INT2FIX(0);
00496
00497 args[0] = domain;
00498 args[1] = type;
00499 args[2] = protocol;
00500
00501 return rsock_sock_s_socketpair(3, args, klass);
00502 }
00503 #endif
00504
00505 void
00506 rsock_init_unixsocket(void)
00507 {
00508 #ifdef HAVE_SYS_UN_H
00509
00510
00511
00512
00513
00514 rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket);
00515 rb_define_method(rb_cUNIXSocket, "initialize", unix_init, 1);
00516 rb_define_method(rb_cUNIXSocket, "path", unix_path, 0);
00517 rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0);
00518 rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0);
00519 rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
00520 rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1);
00521 rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1);
00522 rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1);
00523 rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1);
00524 #endif
00525 }
00526