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 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
00086
00087
00088
00089
00090
00091
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
00102
00103
00104
00105
00106
00107
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
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
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
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
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
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(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
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
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(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 < 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 < 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 (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);
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
00387 if (klass == Qnil)
00388 return INT2FIX(fd);
00389 else {
00390 ID for_fd;
00391 int ff_argc;
00392 VALUE ff_argv[2];
00393 CONST_ID(for_fd, "for_fd");
00394 ff_argc = mode == Qnil ? 1 : 2;
00395 ff_argv[0] = INT2FIX(fd);
00396 ff_argv[1] = mode;
00397 return rb_funcall2(klass, for_fd, ff_argc, ff_argv);
00398 }
00399 }
00400 #else
00401 #define unix_recv_io rb_f_notimplement
00402 #endif
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 static VALUE
00416 unix_addr(VALUE sock)
00417 {
00418 rb_io_t *fptr;
00419 struct sockaddr_un addr;
00420 socklen_t len = (socklen_t)sizeof addr;
00421
00422 GetOpenFile(sock, fptr);
00423
00424 if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00425 rb_sys_fail("getsockname(2)");
00426 return rsock_unixaddr(&addr, len);
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 static VALUE
00442 unix_peeraddr(VALUE sock)
00443 {
00444 rb_io_t *fptr;
00445 struct sockaddr_un addr;
00446 socklen_t len = (socklen_t)sizeof addr;
00447
00448 GetOpenFile(sock, fptr);
00449
00450 if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0)
00451 rb_sys_fail("getpeername(2)");
00452 return rsock_unixaddr(&addr, len);
00453 }
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 static VALUE
00474 unix_s_socketpair(int argc, VALUE *argv, VALUE klass)
00475 {
00476 VALUE domain, type, protocol;
00477 VALUE args[3];
00478
00479 domain = INT2FIX(PF_UNIX);
00480 rb_scan_args(argc, argv, "02", &type, &protocol);
00481 if (argc == 0)
00482 type = INT2FIX(SOCK_STREAM);
00483 if (argc <= 1)
00484 protocol = INT2FIX(0);
00485
00486 args[0] = domain;
00487 args[1] = type;
00488 args[2] = protocol;
00489
00490 return rsock_sock_s_socketpair(3, args, klass);
00491 }
00492 #endif
00493
00494
00495
00496
00497
00498
00499 void
00500 rsock_init_unixsocket(void)
00501 {
00502 #ifdef HAVE_SYS_UN_H
00503 rb_cUNIXSocket = rb_define_class("UNIXSocket", rb_cBasicSocket);
00504 rb_define_method(rb_cUNIXSocket, "initialize", unix_init, 1);
00505 rb_define_method(rb_cUNIXSocket, "path", unix_path, 0);
00506 rb_define_method(rb_cUNIXSocket, "addr", unix_addr, 0);
00507 rb_define_method(rb_cUNIXSocket, "peeraddr", unix_peeraddr, 0);
00508 rb_define_method(rb_cUNIXSocket, "recvfrom", unix_recvfrom, -1);
00509 rb_define_method(rb_cUNIXSocket, "send_io", unix_send_io, 1);
00510 rb_define_method(rb_cUNIXSocket, "recv_io", unix_recv_io, -1);
00511 rb_define_singleton_method(rb_cUNIXSocket, "socketpair", unix_s_socketpair, -1);
00512 rb_define_singleton_method(rb_cUNIXSocket, "pair", unix_s_socketpair, -1);
00513 #endif
00514 }
00515