VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server) { struct sockaddr_un sockaddr; socklen_t sockaddrlen; int fd, status; rb_io_t *fptr; SafeStringValue(path); fd = rsock_socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { rsock_sys_fail_path("socket(2)", path); } INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un)); if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) { rb_raise(rb_eArgError, "too long unix socket path (%ldbytes given but %dbytes max)", RSTRING_LEN(path), (int)sizeof(sockaddr.sun_path)); } memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); sockaddrlen = rsock_unix_sockaddr_len(path); if (server) { status = bind(fd, (struct sockaddr*)&sockaddr, sockaddrlen); } else { int prot; struct unixsock_arg arg; arg.sockaddr = &sockaddr; arg.sockaddrlen = sockaddrlen; arg.fd = fd; status = (int)rb_protect(unixsock_connect_internal, (VALUE)&arg, &prot); if (prot) { close(fd); rb_jump_tag(prot); } } if (status < 0) { close(fd); rsock_sys_fail_path("connect(2)", path); } if (server) { if (listen(fd, SOMAXCONN) < 0) { close(fd); rsock_sys_fail_path("listen(2)", path); } } rsock_init_sock(sock, fd); if (server) { GetOpenFile(sock, fptr); fptr->pathv = rb_str_new_frozen(path); } return sock; }
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server) { struct sockaddr_un sockaddr; int fd, status; rb_io_t *fptr; SafeStringValue(path); fd = rsock_socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { rb_sys_fail("socket(2)"); } MEMZERO(&sockaddr, struct sockaddr_un, 1); sockaddr.sun_family = AF_UNIX; if (sizeof(sockaddr.sun_path) <= (size_t)RSTRING_LEN(path)) { rb_raise(rb_eArgError, "too long unix socket path (max: %dbytes)", (int)sizeof(sockaddr.sun_path)-1); } memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path)); if (server) { status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); } else { int prot; struct unixsock_arg arg; arg.sockaddr = &sockaddr; arg.fd = fd; status = rb_protect((VALUE(*)(VALUE))unixsock_connect_internal, (VALUE)&arg, &prot); if (prot) { close(fd); rb_jump_tag(prot); } } if (status < 0) { close(fd); rb_sys_fail(sockaddr.sun_path); } if (server) listen(fd, 5); rsock_init_sock(sock, fd); if (server) { GetOpenFile(sock, fptr); fptr->pathv = rb_str_new_frozen(path); } return sock; }
/* * call-seq: * UDPSocket.new([address_family]) => socket * * Creates a new UDPSocket object. * * _address_family_ should be an integer, a string or a symbol: * Socket::AF_INET, "AF_INET", :INET, etc. * * UDPSocket.new #=> #<UDPSocket:fd 3> * UDPSocket.new(Socket::AF_INET6) #=> #<UDPSocket:fd 4> * */ static VALUE udp_init(int argc, VALUE *argv, VALUE sock) { VALUE arg; int family = AF_INET; int fd; rb_secure(3); if (rb_scan_args(argc, argv, "01", &arg) == 1) { family = rsock_family_arg(arg); } fd = rsock_socket(family, SOCK_DGRAM, 0); if (fd < 0) { rb_sys_fail("socket(2) - udp"); } return rsock_init_sock(sock, fd); }
static VALUE init_inetsock_internal(struct inetsock_arg *arg) { int type = arg->type; struct addrinfo *res; int fd, status = 0; const char *syscall = 0; arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM, (type == INET_SERVER) ? AI_PASSIVE : 0); /* * Maybe also accept a local address */ if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) { arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0); } arg->fd = fd = -1; for (res = arg->remote.res; res; res = res->ai_next) { #if !defined(INET6) && defined(AF_INET6) if (res->ai_family == AF_INET6) continue; #endif status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol); syscall = "socket(2)"; fd = status; if (fd < 0) { continue; } arg->fd = fd; if (type == INET_SERVER) { #if !defined(_WIN32) && !defined(__CYGWIN__) status = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&status, (socklen_t)sizeof(status)); #endif status = bind(fd, res->ai_addr, res->ai_addrlen); syscall = "bind(2)"; } else { if (arg->local.res) { status = bind(fd, arg->local.res->ai_addr, arg->local.res->ai_addrlen); syscall = "bind(2)"; } if (status >= 0) { status = rsock_connect(fd, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS)); syscall = "connect(2)"; } } if (status < 0) { close(fd); arg->fd = fd = -1; continue; } else break; } if (status < 0) { rb_sys_fail(syscall); } arg->fd = -1; if (type == INET_SERVER) { status = listen(fd, SOMAXCONN); if (status < 0) { close(fd); rb_sys_fail("listen(2)"); } } /* create new instance */ return rsock_init_sock(arg->sock, fd); }
static VALUE init_inetsock_internal(struct inetsock_arg *arg) { int error = 0; int type = arg->type; struct addrinfo *res, *lres; int fd, status = 0, local = 0; const char *syscall = 0; arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM, (type == INET_SERVER) ? AI_PASSIVE : 0); /* * Maybe also accept a local address */ if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) { arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv, SOCK_STREAM, 0); } arg->fd = fd = -1; for (res = arg->remote.res->ai; res; res = res->ai_next) { #if !defined(INET6) && defined(AF_INET6) if (res->ai_family == AF_INET6) continue; #endif lres = NULL; if (arg->local.res) { for (lres = arg->local.res->ai; lres; lres = lres->ai_next) { if (lres->ai_family == res->ai_family) break; } if (!lres) { if (res->ai_next || status < 0) continue; /* Use a different family local address if no choice, this * will cause EAFNOSUPPORT. */ lres = arg->local.res->ai; } } status = rsock_socket(res->ai_family,res->ai_socktype,res->ai_protocol); syscall = "socket(2)"; fd = status; if (fd < 0) { error = errno; continue; } arg->fd = fd; if (type == INET_SERVER) { #if !defined(_WIN32) && !defined(__CYGWIN__) status = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&status, (socklen_t)sizeof(status)); #endif status = bind(fd, res->ai_addr, res->ai_addrlen); syscall = "bind(2)"; } else { if (lres) { status = bind(fd, lres->ai_addr, lres->ai_addrlen); local = status; syscall = "bind(2)"; } if (status >= 0) { status = rsock_connect(fd, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS)); syscall = "connect(2)"; } } if (status < 0) { error = errno; close(fd); arg->fd = fd = -1; continue; } else break; } if (status < 0) { VALUE host, port; if (local < 0) { host = arg->local.host; port = arg->local.serv; } else { host = arg->remote.host; port = arg->remote.serv; } rsock_syserr_fail_host_port(error, syscall, host, port); } arg->fd = -1; if (type == INET_SERVER) { status = listen(fd, SOMAXCONN); if (status < 0) { error = errno; close(fd); rb_syserr_fail(error, "listen(2)"); } } /* create new instance */ return rsock_init_sock(arg->sock, fd); }