summaryrefslogtreecommitdiff
path: root/ruby_2_2/ext/socket/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'ruby_2_2/ext/socket/init.c')
-rw-r--r--ruby_2_2/ext/socket/init.c622
1 files changed, 0 insertions, 622 deletions
diff --git a/ruby_2_2/ext/socket/init.c b/ruby_2_2/ext/socket/init.c
deleted file mode 100644
index 4d7cf29ea3..0000000000
--- a/ruby_2_2/ext/socket/init.c
+++ /dev/null
@@ -1,622 +0,0 @@
-/************************************************
-
- init.c -
-
- created at: Thu Mar 31 12:21:29 JST 1994
-
- Copyright (C) 1993-2007 Yukihiro Matsumoto
-
-************************************************/
-
-#include "rubysocket.h"
-
-VALUE rb_cBasicSocket;
-VALUE rb_cIPSocket;
-VALUE rb_cTCPSocket;
-VALUE rb_cTCPServer;
-VALUE rb_cUDPSocket;
-#ifdef AF_UNIX
-VALUE rb_cUNIXSocket;
-VALUE rb_cUNIXServer;
-#endif
-VALUE rb_cSocket;
-VALUE rb_cAddrinfo;
-
-VALUE rb_eSocket;
-
-#ifdef SOCKS
-VALUE rb_cSOCKSSocket;
-#endif
-
-int rsock_do_not_reverse_lookup = 1;
-
-void
-rsock_raise_socket_error(const char *reason, int error)
-{
-#ifdef EAI_SYSTEM
- if (error == EAI_SYSTEM) rb_sys_fail(reason);
-#endif
- rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
-}
-
-#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
-
-VALUE
-rsock_init_sock(VALUE sock, int fd)
-{
- rb_io_t *fp;
-
- if (!is_socket(fd) || rb_reserved_fd_p(fd)) {
- errno = EBADF;
- rb_sys_fail("not a socket file descriptor");
- }
-
- rb_update_max_fd(fd);
- MakeOpenFile(sock, fp);
- fp->fd = fd;
- fp->mode = FMODE_READWRITE|FMODE_DUPLEX;
- rb_io_ascii8bit_binmode(sock);
- if (rsock_do_not_reverse_lookup) {
- fp->mode |= FMODE_NOREVLOOKUP;
- }
- rb_io_synchronized(fp);
-
- return sock;
-}
-
-VALUE
-rsock_sendto_blocking(void *data)
-{
- struct rsock_send_arg *arg = data;
- VALUE mesg = arg->mesg;
- return (VALUE)sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
- arg->flags, arg->to, arg->tolen);
-}
-
-VALUE
-rsock_send_blocking(void *data)
-{
- struct rsock_send_arg *arg = data;
- VALUE mesg = arg->mesg;
- return (VALUE)send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
- arg->flags);
-}
-
-struct recvfrom_arg {
- int fd, flags;
- VALUE str;
- socklen_t alen;
- union_sockaddr buf;
-};
-
-static VALUE
-recvfrom_blocking(void *data)
-{
- struct recvfrom_arg *arg = data;
- socklen_t len0 = arg->alen;
- ssize_t ret;
- ret = recvfrom(arg->fd, RSTRING_PTR(arg->str), RSTRING_LEN(arg->str),
- arg->flags, &arg->buf.addr, &arg->alen);
- if (ret != -1 && len0 < arg->alen)
- arg->alen = len0;
- return (VALUE)ret;
-}
-
-VALUE
-rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
-{
- rb_io_t *fptr;
- VALUE str, klass;
- struct recvfrom_arg arg;
- VALUE len, flg;
- long buflen;
- long slen;
-
- rb_scan_args(argc, argv, "11", &len, &flg);
-
- if (flg == Qnil) arg.flags = 0;
- else arg.flags = NUM2INT(flg);
- buflen = NUM2INT(len);
-
- GetOpenFile(sock, fptr);
- if (rb_io_read_pending(fptr)) {
- rb_raise(rb_eIOError, "recv for buffered IO");
- }
- arg.fd = fptr->fd;
- arg.alen = (socklen_t)sizeof(arg.buf);
-
- arg.str = str = rb_tainted_str_new(0, buflen);
- klass = RBASIC(str)->klass;
- rb_obj_hide(str);
-
- while (rb_io_check_closed(fptr),
- rsock_maybe_wait_fd(arg.fd),
- (slen = BLOCKING_REGION_FD(recvfrom_blocking, &arg)) < 0) {
- if (!rb_io_wait_readable(fptr->fd)) {
- rb_sys_fail("recvfrom(2)");
- }
- if (RBASIC(str)->klass || RSTRING_LEN(str) != buflen) {
- rb_raise(rb_eRuntimeError, "buffer string modified");
- }
- }
-
- rb_obj_reveal(str, klass);
- if (slen < RSTRING_LEN(str)) {
- rb_str_set_len(str, slen);
- }
- rb_obj_taint(str);
- switch (from) {
- case RECV_RECV:
- return str;
- case RECV_IP:
-#if 0
- if (arg.alen != sizeof(struct sockaddr_in)) {
- rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
- }
-#endif
- if (arg.alen && arg.alen != sizeof(arg.buf)) /* OSX doesn't return a from result for connection-oriented sockets */
- return rb_assoc_new(str, rsock_ipaddr(&arg.buf.addr, arg.alen, fptr->mode & FMODE_NOREVLOOKUP));
- else
- return rb_assoc_new(str, Qnil);
-
-#ifdef HAVE_SYS_UN_H
- case RECV_UNIX:
- return rb_assoc_new(str, rsock_unixaddr(&arg.buf.un, arg.alen));
-#endif
- case RECV_SOCKET:
- return rb_assoc_new(str, rsock_io_socket_addrinfo(sock, &arg.buf.addr, arg.alen));
- default:
- rb_bug("rsock_s_recvfrom called with bad value");
- }
-}
-
-VALUE
-rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
-{
- rb_io_t *fptr;
- VALUE str;
- union_sockaddr buf;
- socklen_t alen = (socklen_t)sizeof buf;
- VALUE len, flg;
- long buflen;
- long slen;
- int fd, flags;
- VALUE addr = Qnil;
- socklen_t len0;
-
- rb_scan_args(argc, argv, "11", &len, &flg);
-
- if (flg == Qnil) flags = 0;
- else flags = NUM2INT(flg);
- buflen = NUM2INT(len);
-
-#ifdef MSG_DONTWAIT
- /* MSG_DONTWAIT avoids the race condition between fcntl and recvfrom.
- It is not portable, though. */
- flags |= MSG_DONTWAIT;
-#endif
-
- GetOpenFile(sock, fptr);
- if (rb_io_read_pending(fptr)) {
- rb_raise(rb_eIOError, "recvfrom for buffered IO");
- }
- fd = fptr->fd;
-
- str = rb_tainted_str_new(0, buflen);
-
- rb_io_check_closed(fptr);
- rb_io_set_nonblock(fptr);
- len0 = alen;
- slen = recvfrom(fd, RSTRING_PTR(str), buflen, flags, &buf.addr, &alen);
- if (slen != -1 && len0 < alen)
- alen = len0;
-
- if (slen < 0) {
- switch (errno) {
- case EAGAIN:
-#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
-#endif
- rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
- }
- rb_sys_fail("recvfrom(2)");
- }
- if (slen < RSTRING_LEN(str)) {
- rb_str_set_len(str, slen);
- }
- rb_obj_taint(str);
- switch (from) {
- case RECV_RECV:
- return str;
-
- case RECV_IP:
- if (alen && alen != sizeof(buf)) /* connection-oriented socket may not return a from result */
- addr = rsock_ipaddr(&buf.addr, alen, fptr->mode & FMODE_NOREVLOOKUP);
- break;
-
- case RECV_SOCKET:
- addr = rsock_io_socket_addrinfo(sock, &buf.addr, alen);
- break;
-
- default:
- rb_bug("rsock_s_recvfrom_nonblock called with bad value");
- }
- return rb_assoc_new(str, addr);
-}
-
-/* returns true if SOCK_CLOEXEC is supported */
-int rsock_detect_cloexec(int fd)
-{
-#ifdef SOCK_CLOEXEC
- int flags = fcntl(fd, F_GETFD);
-
- if (flags == -1)
- rb_bug("rsock_detect_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
-
- if (flags & FD_CLOEXEC)
- return 1;
-#endif
- return 0;
-}
-
-#ifdef SOCK_CLOEXEC
-static int
-rsock_socket0(int domain, int type, int proto)
-{
- int ret;
- static int cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
-
- if (cloexec_state > 0) { /* common path, if SOCK_CLOEXEC is defined */
- ret = socket(domain, type|SOCK_CLOEXEC, proto);
- if (ret >= 0) {
- if (ret <= 2)
- goto fix_cloexec;
- goto update_max_fd;
- }
- }
- else if (cloexec_state < 0) { /* usually runs once only for detection */
- ret = socket(domain, type|SOCK_CLOEXEC, proto);
- if (ret >= 0) {
- cloexec_state = rsock_detect_cloexec(ret);
- if (cloexec_state == 0 || ret <= 2)
- goto fix_cloexec;
- goto update_max_fd;
- }
- else if (ret == -1 && errno == EINVAL) {
- /* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
- ret = socket(domain, type, proto);
- if (ret != -1) {
- cloexec_state = 0;
- /* fall through to fix_cloexec */
- }
- }
- }
- else { /* cloexec_state == 0 */
- ret = socket(domain, type, proto);
- }
- if (ret == -1)
- return -1;
-fix_cloexec:
- rb_maygvl_fd_fix_cloexec(ret);
-update_max_fd:
- rb_update_max_fd(ret);
-
- return ret;
-}
-#else /* !SOCK_CLOEXEC */
-static int
-rsock_socket0(int domain, int type, int proto)
-{
- int ret = socket(domain, type, proto);
-
- if (ret == -1)
- return -1;
- rb_fd_fix_cloexec(ret);
-
- return ret;
-}
-#endif /* !SOCK_CLOEXEC */
-
-int
-rsock_socket(int domain, int type, int proto)
-{
- int fd;
-
- fd = rsock_socket0(domain, type, proto);
- if (fd < 0) {
- if (errno == EMFILE || errno == ENFILE) {
- rb_gc();
- fd = rsock_socket0(domain, type, proto);
- }
- }
- if (0 <= fd)
- rb_update_max_fd(fd);
- return fd;
-}
-
-/* emulate blocking connect behavior on EINTR or non-blocking socket */
-static int
-wait_connectable(int fd)
-{
- int sockerr, revents;
- socklen_t sockerrlen;
-
- /* only to clear pending error */
- sockerrlen = (socklen_t)sizeof(sockerr);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) < 0)
- return -1;
-
- /*
- * Stevens book says, successful finish turn on RB_WAITFD_OUT and
- * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT.
- * So it's enough to wait only RB_WAITFD_OUT and check the pending error
- * by getsockopt().
- *
- * Note: rb_wait_for_single_fd already retries on EINTR/ERESTART
- */
- revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL);
-
- if (revents < 0)
- return -1;
-
- sockerrlen = (socklen_t)sizeof(sockerr);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) < 0)
- return -1;
-
- switch (sockerr) {
- case 0:
- /*
- * be defensive in case some platforms set SO_ERROR on the original,
- * interrupted connect()
- */
- case EINTR:
-#ifdef ERESTART
- case ERESTART:
-#endif
- case EAGAIN:
-#ifdef EINPROGRESS
- case EINPROGRESS:
-#endif
-#ifdef EALREADY
- case EALREADY:
-#endif
-#ifdef EISCONN
- case EISCONN:
-#endif
- return 0; /* success */
- default:
- /* likely (but not limited to): ECONNREFUSED, ETIMEDOUT, EHOSTUNREACH */
- errno = sockerr;
- return -1;
- }
-
- return 0;
-}
-
-struct connect_arg {
- int fd;
- socklen_t len;
- const struct sockaddr *sockaddr;
-};
-
-static VALUE
-connect_blocking(void *data)
-{
- struct connect_arg *arg = data;
- return (VALUE)connect(arg->fd, arg->sockaddr, arg->len);
-}
-
-#if defined(SOCKS) && !defined(SOCKS5)
-static VALUE
-socks_connect_blocking(void *data)
-{
- struct connect_arg *arg = data;
- return (VALUE)Rconnect(arg->fd, arg->sockaddr, arg->len);
-}
-#endif
-
-int
-rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
-{
- int status;
- rb_blocking_function_t *func = connect_blocking;
- struct connect_arg arg;
-
- arg.fd = fd;
- arg.sockaddr = sockaddr;
- arg.len = len;
-#if defined(SOCKS) && !defined(SOCKS5)
- if (socks) func = socks_connect_blocking;
-#endif
- status = (int)BLOCKING_REGION_FD(func, &arg);
-
- if (status < 0) {
- switch (errno) {
- case EINTR:
-#ifdef ERESTART
- case ERESTART:
-#endif
- case EAGAIN:
-#ifdef EINPROGRESS
- case EINPROGRESS:
-#endif
- return wait_connectable(fd);
- }
- }
- return status;
-}
-
-static void
-make_fd_nonblock(int fd)
-{
- int flags;
-#ifdef F_GETFL
- flags = fcntl(fd, F_GETFL);
- if (flags == -1) {
- rb_sys_fail("fnctl(2)");
- }
-#else
- flags = 0;
-#endif
- flags |= O_NONBLOCK;
- if (fcntl(fd, F_SETFL, flags) == -1) {
- rb_sys_fail("fnctl(2)");
- }
-}
-
-static int
-cloexec_accept(int socket, struct sockaddr *address, socklen_t *address_len)
-{
- int ret;
- socklen_t len0 = 0;
-#ifdef HAVE_ACCEPT4
- static int try_accept4 = 1;
-#endif
- if (address_len) len0 = *address_len;
-#ifdef HAVE_ACCEPT4
- if (try_accept4) {
- int flags = 0;
-#ifdef SOCK_CLOEXEC
- flags |= SOCK_CLOEXEC;
-#endif
- ret = accept4(socket, address, address_len, flags);
- /* accept4 is available since Linux 2.6.28, glibc 2.10. */
- if (ret != -1) {
- if (ret <= 2)
- rb_maygvl_fd_fix_cloexec(ret);
- if (address_len && len0 < *address_len) *address_len = len0;
- return ret;
- }
- if (errno != ENOSYS) {
- return -1;
- }
- try_accept4 = 0;
- }
-#endif
- ret = accept(socket, address, address_len);
- if (ret == -1) return -1;
- if (address_len && len0 < *address_len) *address_len = len0;
- rb_maygvl_fd_fix_cloexec(ret);
- return ret;
-}
-
-
-VALUE
-rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
-{
- int fd2;
-
- rb_secure(3);
- rb_io_set_nonblock(fptr);
- fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len);
- if (fd2 < 0) {
- switch (errno) {
- case EAGAIN:
-#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
-#endif
- case ECONNABORTED:
-#if defined EPROTO
- case EPROTO:
-#endif
- rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "accept(2) would block");
- }
- rb_sys_fail("accept(2)");
- }
- rb_update_max_fd(fd2);
- make_fd_nonblock(fd2);
- return rsock_init_sock(rb_obj_alloc(klass), fd2);
-}
-
-struct accept_arg {
- int fd;
- struct sockaddr *sockaddr;
- socklen_t *len;
-};
-
-static VALUE
-accept_blocking(void *data)
-{
- struct accept_arg *arg = data;
- return (VALUE)cloexec_accept(arg->fd, arg->sockaddr, arg->len);
-}
-
-VALUE
-rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len)
-{
- int fd2;
- int retry = 0;
- struct accept_arg arg;
-
- rb_secure(3);
- arg.fd = fd;
- arg.sockaddr = sockaddr;
- arg.len = len;
- retry:
- rsock_maybe_wait_fd(fd);
- fd2 = (int)BLOCKING_REGION_FD(accept_blocking, &arg);
- if (fd2 < 0) {
- switch (errno) {
- case EMFILE:
- case ENFILE:
- if (retry) break;
- rb_gc();
- retry = 1;
- goto retry;
- default:
- if (!rb_io_wait_readable(fd)) break;
- retry = 0;
- goto retry;
- }
- rb_sys_fail("accept(2)");
- }
- rb_update_max_fd(fd2);
- if (!klass) return INT2NUM(fd2);
- return rsock_init_sock(rb_obj_alloc(klass), fd2);
-}
-
-int
-rsock_getfamily(int sockfd)
-{
- union_sockaddr ss;
- socklen_t sslen = (socklen_t)sizeof(ss);
-
- ss.addr.sa_family = AF_UNSPEC;
- if (getsockname(sockfd, &ss.addr, &sslen) < 0)
- return AF_UNSPEC;
-
- return ss.addr.sa_family;
-}
-
-void
-rsock_init_socket_init(void)
-{
- /*
- * SocketError is the error class for socket.
- */
- rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
- rsock_init_ipsocket();
- rsock_init_tcpsocket();
- rsock_init_tcpserver();
- rsock_init_sockssocket();
- rsock_init_udpsocket();
- rsock_init_unixsocket();
- rsock_init_unixserver();
- rsock_init_sockopt();
- rsock_init_ancdata();
- rsock_init_addrinfo();
- rsock_init_sockifaddr();
- rsock_init_socket_constants();
-}