diff options
Diffstat (limited to 'ext/socket/basicsocket.c')
-rw-r--r-- | ext/socket/basicsocket.c | 155 |
1 files changed, 95 insertions, 60 deletions
diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c index fb5beed81a..8af8374ecf 100644 --- a/ext/socket/basicsocket.c +++ b/ext/socket/basicsocket.c @@ -10,6 +10,28 @@ #include "rubysocket.h" +#ifdef _WIN32 +#define is_socket(fd) rb_w32_is_socket(fd) +#else +static int +is_socket(int fd) +{ + struct stat sbuf; + + if (fstat(fd, &sbuf) < 0) + rb_sys_fail("fstat(2)"); + return S_ISSOCK(sbuf.st_mode); +} +#endif + +static void +rsock_validate_descriptor(int descriptor) +{ + if (!is_socket(descriptor) || rb_reserved_fd_p(descriptor)) { + rb_syserr_fail(EBADF, "not a socket file descriptor"); + } +} + /* * call-seq: * BasicSocket.for_fd(fd) => basicsocket @@ -22,10 +44,14 @@ * */ static VALUE -bsock_s_for_fd(VALUE klass, VALUE fd) +bsock_s_for_fd(VALUE klass, VALUE _descriptor) { rb_io_t *fptr; - VALUE sock = rsock_init_sock(rb_obj_alloc(klass), NUM2INT(fd)); + + int descriptor = RB_NUM2INT(_descriptor); + rsock_validate_descriptor(descriptor); + + VALUE sock = rsock_init_sock(rb_obj_alloc(klass), descriptor); GetOpenFile(sock, fptr); @@ -68,16 +94,16 @@ bsock_shutdown(int argc, VALUE *argv, VALUE sock) rb_scan_args(argc, argv, "01", &howto); if (howto == Qnil) - how = SHUT_RDWR; + how = SHUT_RDWR; else { - how = rsock_shutdown_how_arg(howto); + how = rsock_shutdown_how_arg(howto); if (how != SHUT_WR && how != SHUT_RD && how != SHUT_RDWR) { - rb_raise(rb_eArgError, "`how' should be either :SHUT_RD, :SHUT_WR, :SHUT_RDWR"); - } + rb_raise(rb_eArgError, "`how' should be either :SHUT_RD, :SHUT_WR, :SHUT_RDWR"); + } } GetOpenFile(sock, fptr); if (shutdown(fptr->fd, how) == -1) - rb_sys_fail("shutdown(2)"); + rb_sys_fail("shutdown(2)"); return INT2FIX(0); } @@ -98,9 +124,9 @@ bsock_close_read(VALUE sock) rb_io_t *fptr; GetOpenFile(sock, fptr); - shutdown(fptr->fd, 0); + shutdown(fptr->fd, SHUT_RD); if (!(fptr->mode & FMODE_WRITABLE)) { - return rb_io_close(sock); + return rb_io_close(sock); } fptr->mode &= ~FMODE_READABLE; @@ -129,9 +155,9 @@ bsock_close_write(VALUE sock) GetOpenFile(sock, fptr); if (!(fptr->mode & FMODE_READABLE)) { - return rb_io_close(sock); + return rb_io_close(sock); } - shutdown(fptr->fd, 1); + shutdown(fptr->fd, SHUT_WR); fptr->mode &= ~FMODE_WRITABLE; return Qnil; @@ -220,21 +246,21 @@ bsock_setsockopt(int argc, VALUE *argv, VALUE sock) switch (TYPE(val)) { case T_FIXNUM: - i = FIX2INT(val); - goto numval; + i = FIX2INT(val); + goto numval; case T_FALSE: - i = 0; - goto numval; + i = 0; + goto numval; case T_TRUE: - i = 1; + i = 1; numval: - v = (char*)&i; vlen = (int)sizeof(i); - break; + v = (char*)&i; vlen = (int)sizeof(i); + break; default: - StringValue(val); - v = RSTRING_PTR(val); - vlen = RSTRING_SOCKLEN(val); - break; + StringValue(val); + v = RSTRING_PTR(val); + vlen = RSTRING_SOCKLEN(val); + break; } rb_io_check_closed(fptr); @@ -280,7 +306,7 @@ bsock_setsockopt(int argc, VALUE *argv, VALUE sock) * ipttl = sock.getsockopt(:IP, :TTL).int * * optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL) - * ipttl = optval.unpack("i")[0] + * ipttl = optval.unpack1("i") * * Option values may be structs. Decoding them can be complex as it involves * examining your system headers to determine the correct definition. An @@ -331,7 +357,7 @@ bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname) rb_io_check_closed(fptr); if (getsockopt(fptr->fd, level, option, buf, &len) < 0) - rsock_sys_fail_path("getsockopt(2)", fptr->pathv); + rsock_sys_fail_path("getsockopt(2)", fptr->pathv); return rsock_sockopt_new(family, level, option, rb_str_new(buf, len)); } @@ -359,7 +385,7 @@ bsock_getsockname(VALUE sock) GetOpenFile(sock, fptr); if (getsockname(fptr->fd, &buf.addr, &len) < 0) - rb_sys_fail("getsockname(2)"); + rb_sys_fail("getsockname(2)"); if (len0 < len) len = len0; return rb_str_new((char*)&buf, len); } @@ -390,7 +416,7 @@ bsock_getpeername(VALUE sock) GetOpenFile(sock, fptr); if (getpeername(fptr->fd, &buf.addr, &len) < 0) - rb_sys_fail("getpeername(2)"); + rb_sys_fail("getpeername(2)"); if (len0 < len) len = len0; return rb_str_new((char*)&buf, len); } @@ -427,7 +453,7 @@ bsock_getpeereid(VALUE self) gid_t egid; GetOpenFile(self, fptr); if (getpeereid(fptr->fd, &euid, &egid) == -1) - rb_sys_fail("getpeereid(3)"); + rb_sys_fail("getpeereid(3)"); return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid)); #elif defined(SO_PEERCRED) /* GNU/Linux */ rb_io_t *fptr; @@ -435,7 +461,7 @@ bsock_getpeereid(VALUE self) socklen_t len = sizeof(cred); GetOpenFile(self, fptr); if (getsockopt(fptr->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1) - rb_sys_fail("getsockopt(SO_PEERCRED)"); + rb_sys_fail("getsockopt(SO_PEERCRED)"); return rb_assoc_new(UIDT2NUM(cred.uid), GIDT2NUM(cred.gid)); #elif defined(HAVE_GETPEERUCRED) /* Solaris */ rb_io_t *fptr; @@ -443,7 +469,7 @@ bsock_getpeereid(VALUE self) VALUE ret; GetOpenFile(self, fptr); if (getpeerucred(fptr->fd, &uc) == -1) - rb_sys_fail("getpeerucred(3C)"); + rb_sys_fail("getpeerucred(3C)"); ret = rb_assoc_new(UIDT2NUM(ucred_geteuid(uc)), GIDT2NUM(ucred_getegid(uc))); ucred_free(uc); return ret; @@ -480,7 +506,7 @@ bsock_local_address(VALUE sock) GetOpenFile(sock, fptr); if (getsockname(fptr->fd, &buf.addr, &len) < 0) - rb_sys_fail("getsockname(2)"); + rb_sys_fail("getsockname(2)"); if (len0 < len) len = len0; return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len); } @@ -514,7 +540,7 @@ bsock_remote_address(VALUE sock) GetOpenFile(sock, fptr); if (getpeername(fptr->fd, &buf.addr, &len) < 0) - rb_sys_fail("getpeername(2)"); + rb_sys_fail("getpeername(2)"); if (len0 < len) len = len0; return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len); } @@ -537,12 +563,11 @@ bsock_remote_address(VALUE sock) * } */ VALUE -rsock_bsock_send(int argc, VALUE *argv, VALUE sock) +rsock_bsock_send(int argc, VALUE *argv, VALUE socket) { struct rsock_send_arg arg; VALUE flags, to; rb_io_t *fptr; - ssize_t n; rb_blocking_function_t *func; const char *funcname; @@ -550,28 +575,38 @@ rsock_bsock_send(int argc, VALUE *argv, VALUE sock) StringValue(arg.mesg); if (!NIL_P(to)) { - SockAddrStringValue(to); - to = rb_str_new4(to); - arg.to = (struct sockaddr *)RSTRING_PTR(to); - arg.tolen = RSTRING_SOCKLEN(to); - func = rsock_sendto_blocking; - funcname = "sendto(2)"; + SockAddrStringValue(to); + to = rb_str_new4(to); + arg.to = (struct sockaddr *)RSTRING_PTR(to); + arg.tolen = RSTRING_SOCKLEN(to); + func = rsock_sendto_blocking; + funcname = "sendto(2)"; } else { - func = rsock_send_blocking; - funcname = "send(2)"; + func = rsock_send_blocking; + funcname = "send(2)"; } - GetOpenFile(sock, fptr); + + RB_IO_POINTER(socket, fptr); + arg.fd = fptr->fd; arg.flags = NUM2INT(flags); - while (rsock_maybe_fd_writable(arg.fd), - (n = (ssize_t)BLOCKING_REGION_FD(func, &arg)) < 0) { - if (rb_io_wait_writable(arg.fd)) { - continue; - } - rb_sys_fail(funcname); + + while (true) { +#ifdef RSOCK_WAIT_BEFORE_BLOCKING + rb_io_wait(socket, RB_INT2NUM(RUBY_IO_WRITABLE), Qnil); +#endif + + ssize_t n = (ssize_t)BLOCKING_REGION_FD(func, &arg); + + if (n >= 0) return SSIZET2NUM(n); + + if (rb_io_maybe_wait_writable(errno, socket, RUBY_IO_TIMEOUT_DEFAULT)) { + continue; + } + + rb_sys_fail(funcname); } - return SSIZET2NUM(n); } /* @@ -621,10 +656,10 @@ bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state) GetOpenFile(sock, fptr); if (RTEST(state)) { - fptr->mode |= FMODE_NOREVLOOKUP; + fptr->mode |= FMODE_NOREVLOOKUP; } else { - fptr->mode &= ~FMODE_NOREVLOOKUP; + fptr->mode &= ~FMODE_NOREVLOOKUP; } return sock; } @@ -712,9 +747,9 @@ rsock_init_basicsocket(void) rb_undef_method(rb_cBasicSocket, "initialize"); rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup", - bsock_do_not_rev_lookup, 0); + bsock_do_not_rev_lookup, 0); rb_define_singleton_method(rb_cBasicSocket, "do_not_reverse_lookup=", - bsock_do_not_rev_lookup_set, 1); + bsock_do_not_rev_lookup_set, 1); rb_define_singleton_method(rb_cBasicSocket, "for_fd", bsock_s_for_fd, 1); rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0); @@ -735,23 +770,23 @@ rsock_init_basicsocket(void) /* for ext/socket/lib/socket.rb use only: */ rb_define_private_method(rb_cBasicSocket, - "__recv_nonblock", bsock_recv_nonblock, 4); + "__recv_nonblock", bsock_recv_nonblock, 4); #if MSG_DONTWAIT_RELIABLE rb_define_private_method(rb_cBasicSocket, - "__read_nonblock", rsock_read_nonblock, 3); + "__read_nonblock", rsock_read_nonblock, 3); rb_define_private_method(rb_cBasicSocket, - "__write_nonblock", rsock_write_nonblock, 2); + "__write_nonblock", rsock_write_nonblock, 2); #endif /* in ancdata.c */ rb_define_private_method(rb_cBasicSocket, "__sendmsg", - rsock_bsock_sendmsg, 4); + rsock_bsock_sendmsg, 4); rb_define_private_method(rb_cBasicSocket, "__sendmsg_nonblock", - rsock_bsock_sendmsg_nonblock, 5); + rsock_bsock_sendmsg_nonblock, 5); rb_define_private_method(rb_cBasicSocket, "__recvmsg", - rsock_bsock_recvmsg, 4); + rsock_bsock_recvmsg, 4); rb_define_private_method(rb_cBasicSocket, "__recvmsg_nonblock", - rsock_bsock_recvmsg_nonblock, 5); + rsock_bsock_recvmsg_nonblock, 5); } |