/* * call-seq: * TCPSocket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list] * * Use Addrinfo.getaddrinfo instead. * This method is deprecated for the following reasons: * * - The 3rd element of the result is the address family of the first address. * The address families of the rest of the addresses are not returned. * - gethostbyname() may take a long time and it may block other threads. * (GVL cannot be released since gethostbyname() is not thread safe.) * - This method uses gethostbyname() function already removed from POSIX. * * This method lookups host information by _hostname_. * * TCPSocket.gethostbyname("localhost") * #=> ["localhost", ["hal"], 2, "127.0.0.1"] * */ static VALUE tcp_s_gethostbyname(VALUE obj, VALUE host) { struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME); return rsock_make_hostent(host, res, tcp_sockaddr); }
/* * call-seq: * TCPSocket.gethostbyname(hostname) => [official_hostname, alias_hostnames, address_family, *address_list] * * Lookups host information by _hostname_. * * TCPSocket.gethostbyname("localhost") * #=> ["localhost", ["hal"], 2, "127.0.0.1"] * */ static VALUE tcp_s_gethostbyname(VALUE obj, VALUE host) { rb_secure(3); return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), tcp_sockaddr); }
/* * call-seq: * IPSocket.getaddress(host) => ipaddress * * Lookups the IP address of _host_. * * IPSocket.getaddress("localhost") #=> "127.0.0.1" * IPSocket.getaddress("ip6-localhost") #=> "::1" * */ static VALUE ip_s_getaddress(VALUE obj, VALUE host) { struct sockaddr_storage addr; struct addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0); /* just take the first one */ memcpy(&addr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); return rsock_make_ipaddr((struct sockaddr*)&addr); }
/* * call-seq: * IPSocket.getaddress(host) => ipaddress * * Lookups the IP address of _host_. * * IPSocket.getaddress("localhost") #=> "127.0.0.1" * IPSocket.getaddress("ip6-localhost") #=> "::1" * */ static VALUE ip_s_getaddress(VALUE obj, VALUE host) { union_sockaddr addr; struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, SOCK_STREAM, 0); socklen_t len = res->ai->ai_addrlen; /* just take the first one */ memcpy(&addr, res->ai->ai_addr, len); rb_freeaddrinfo(res); return rsock_make_ipaddr(&addr.addr, len); }
/* * call-seq: * udpsocket.connect(host, port) => 0 * * Connects _udpsocket_ to _host_:_port_. * * This makes possible to send without destination address. * * u1 = UDPSocket.new * u1.bind("127.0.0.1", 4913) * u2 = UDPSocket.new * u2.connect("127.0.0.1", 4913) * u2.send "uuuu", 0 * p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]] * */ static VALUE udp_connect(VALUE sock, VALUE host, VALUE port) { rb_io_t *fptr; struct udp_arg arg; VALUE ret; rb_secure(3); arg.res = rsock_addrinfo(host, port, SOCK_DGRAM, 0); GetOpenFile(sock, fptr); arg.fd = fptr->fd; ret = rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res); if (!ret) rsock_sys_fail_host_port("connect(2)", host, port); return INT2FIX(0); }
/* * call-seq: * udpsocket.bind(host, port) #=> 0 * * Binds _udpsocket_ to _host_:_port_. * * u1 = UDPSocket.new * u1.bind("127.0.0.1", 4913) * u1.send "message-to-self", 0, "127.0.0.1", 4913 * p u1.recvfrom(10) #=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]] * */ static VALUE udp_bind(VALUE sock, VALUE host, VALUE port) { rb_io_t *fptr; struct addrinfo *res0, *res; rb_secure(3); res0 = rsock_addrinfo(host, port, SOCK_DGRAM, 0); GetOpenFile(sock, fptr); for (res = res0; res; res = res->ai_next) { if (bind(fptr->fd, res->ai_addr, res->ai_addrlen) < 0) { continue; } freeaddrinfo(res0); return INT2FIX(0); } freeaddrinfo(res0); rsock_sys_fail_host_port("bind(2)", host, port); return INT2FIX(0); }
/* * call-seq: * udpsocket.send(mesg, flags, host, port) => numbytes_sent * udpsocket.send(mesg, flags, sockaddr_to) => numbytes_sent * udpsocket.send(mesg, flags) => numbytes_sent * * Sends _mesg_ via _udpsocket_. * * _flags_ should be a bitwise OR of Socket::MSG_* constants. * * u1 = UDPSocket.new * u1.bind("127.0.0.1", 4913) * * u2 = UDPSocket.new * u2.send "hi", 0, "127.0.0.1", 4913 * * mesg, addr = u1.recvfrom(10) * u1.send mesg, 0, addr[3], addr[1] * * p u2.recv(100) #=> "hi" * */ static VALUE udp_send(int argc, VALUE *argv, VALUE sock) { VALUE flags, host, port; rb_io_t *fptr; int n; struct addrinfo *res0, *res; struct rsock_send_arg arg; if (argc == 2 || argc == 3) { return rsock_bsock_send(argc, argv, sock); } rb_scan_args(argc, argv, "4", &arg.mesg, &flags, &host, &port); StringValue(arg.mesg); res0 = rsock_addrinfo(host, port, SOCK_DGRAM, 0); GetOpenFile(sock, fptr); arg.fd = fptr->fd; arg.flags = NUM2INT(flags); for (res = res0; res; res = res->ai_next) { retry: arg.to = res->ai_addr; arg.tolen = res->ai_addrlen; rb_thread_fd_writable(arg.fd); n = (int)BLOCKING_REGION_FD(rsock_sendto_blocking, &arg); if (n >= 0) { freeaddrinfo(res0); return INT2FIX(n); } if (rb_io_wait_writable(fptr->fd)) { goto retry; } } freeaddrinfo(res0); rsock_sys_fail_host_port("sendto(2)", host, port); return INT2FIX(n); }
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); }