класс Addrinfo
Класс Addrinfo отображает struct
addrinfo в руби. Эта структура идентифицирует интернет-хост и службу.
Публичные методы класса
# File ext/socket/lib/socket.rb, line 231 def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, &block) Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags).each(&block) end
Итерируется по списку объектов Addrinfo, полученных с помощью ::getaddrinfo.
Addrinfo.foreach(nil, 80) {|x| p x }
#=> #<Addrinfo: 127.0.0.1:80 TCP (:80)>
# #<Addrinfo: 127.0.0.1:80 UDP (:80)>
# #<Addrinfo: [::1]:80 TCP (:80)>
# #<Addrinfo: [::1]:80 UDP (:80)>
static VALUE
addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self)
{
VALUE node, service, family, socktype, protocol, flags;
rb_scan_args(argc, argv, "24", &node, &service, &family, &socktype, &protocol, &flags);
return addrinfo_list_new(node, service, family, socktype, protocol, flags);
} Возвращает список объектов addrinfo в виде массива.
Этот метод преобразует имя узла (имя хоста) и службу (порт) в addrinfo. Поскольку преобразование не является уникальным, результатом является список объектов addrinfo.
Имя узла или служба могут быть nil, если преобразование не требуется.
family, socktype и protocol — подсказки для предпочтительного протокола. Если результат будет использован для сокета с SOCK_STREAM, то SOCK_STREAM должен быть указан как socktype. В этом случае ::getaddrinfo возвращает список addrinfo, соответствующий SOCK_STREAM. Если они опущены или задано nil, результат не ограничивается.
Аналогично, PF_INET6 как family ограничивает результат IPv6.
Флаги должны быть битовым ИЛИ констант Socket::AI_???, таких как указано ниже. Обратите внимание, что точный список констант зависит от операционной системы.
AI_PASSIVE Get address to use with bind() AI_CANONNAME Fill in the canonical name AI_NUMERICHOST Prevent host name resolution AI_NUMERICSERV Prevent service name resolution AI_V4MAPPED Accept IPv4-mapped IPv6 addresses AI_ALL Allow all addresses AI_ADDRCONFIG Accept only if any address is assigned
Обратите внимание, что socktype необходимо указывать, когда приложение знает способ использования адреса. Некоторые платформы вызывают ошибку, когда socktype опущен, а имя службы задано как целое число, потому что некоторые номера портов, например 512, неоднозначны без socktype.
Addrinfo.getaddrinfo("www.kame.net", 80, nil, :STREAM)
#=> [#<Addrinfo: 203.178.141.194:80 TCP (www.kame.net)>,
# #<Addrinfo: [2001:200:dff:fff1:216:3eff:feb1:44d7]:80 TCP (www.kame.net)>]
static VALUE
addrinfo_s_ip(VALUE self, VALUE host)
{
VALUE ret;
rb_addrinfo_t *rai;
ret = addrinfo_firstonly_new(host, Qnil,
INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0));
rai = get_addrinfo(ret);
rai->socktype = 0;
rai->protocol = 0;
return ret;
} Возвращает объект addrinfo для IP-адреса.
Порт, socktype, protocol результата заполняются нулями. Поэтому он не подходит для создания сокета.
Addrinfo.ip("localhost") #=> #<Addrinfo: 127.0.0.1 (localhost)>
static VALUE
addrinfo_initialize(int argc, VALUE *argv, VALUE self)
{
rb_addrinfo_t *rai;
VALUE sockaddr_arg, sockaddr_ary, pfamily, socktype, protocol;
int i_pfamily, i_socktype, i_protocol;
struct sockaddr *sockaddr_ptr;
socklen_t sockaddr_len;
VALUE canonname = Qnil, inspectname = Qnil;
if (check_addrinfo(self))
rb_raise(rb_eTypeError, "already initialized socket address");
DATA_PTR(self) = rai = alloc_addrinfo();
rb_scan_args(argc, argv, "13", &sockaddr_arg, &pfamily, &socktype, &protocol);
i_pfamily = NIL_P(pfamily) ? PF_UNSPEC : rsock_family_arg(pfamily);
i_socktype = NIL_P(socktype) ? 0 : rsock_socktype_arg(socktype);
i_protocol = NIL_P(protocol) ? 0 : NUM2INT(protocol);
sockaddr_ary = rb_check_array_type(sockaddr_arg);
if (!NIL_P(sockaddr_ary)) {
VALUE afamily = rb_ary_entry(sockaddr_ary, 0);
int af;
StringValue(afamily);
if (rsock_family_to_int(RSTRING_PTR(afamily), RSTRING_LEN(afamily), &af) == -1)
rb_raise(rb_eSocket, "unknown address family: %s", StringValueCStr(afamily));
switch (af) {
case AF_INET: /* ["AF_INET", 46102, "localhost.localdomain", "127.0.0.1"] */
#ifdef INET6
case AF_INET6: /* ["AF_INET6", 42304, "ip6-localhost", "::1"] */
#endif
{
VALUE service = rb_ary_entry(sockaddr_ary, 1);
VALUE nodename = rb_ary_entry(sockaddr_ary, 2);
VALUE numericnode = rb_ary_entry(sockaddr_ary, 3);
int flags;
service = INT2NUM(NUM2INT(service));
if (!NIL_P(nodename))
StringValue(nodename);
StringValue(numericnode);
flags = AI_NUMERICHOST;
#ifdef AI_NUMERICSERV
flags |= AI_NUMERICSERV;
#endif
init_addrinfo_getaddrinfo(rai, numericnode, service,
INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
INT2NUM(flags),
nodename, service);
break;
}
#ifdef HAVE_SYS_UN_H
case AF_UNIX: /* ["AF_UNIX", "/tmp/sock"] */
{
VALUE path = rb_ary_entry(sockaddr_ary, 1);
StringValue(path);
init_unix_addrinfo(rai, path, SOCK_STREAM);
break;
}
#endif
default:
rb_raise(rb_eSocket, "unexpected address family");
}
}
else {
StringValue(sockaddr_arg);
sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
i_pfamily, i_socktype, i_protocol,
canonname, inspectname);
}
return self;
} Возвращает новый экземпляр Addrinfo. Экземпляр содержит sockaddr, family, socktype, protocol. sockaddr означает структуру sockaddr, которая может использоваться для connect(2) и т.д. family, socktype и protocol — целые числа, используемые в качестве аргументов socket(2).
sockaddr задаётся в виде массива или строки. Массив должен быть совместим со значением IPSocket#addr или UNIXSocket#addr. Строка должна быть структурой sockaddr, сгенерированной Socket.sockaddr_in или Socket.unpack_sockaddr_un.
Примеры sockaddr:
-
- “AF_INET”, 46102, “localhost.localdomain”, “127.0.0.1”
-
- “AF_INET6”, 42304, “ip6-localhost”, “::1”
-
- “AF_UNIX”, “/tmp/sock”
-
Socket.sockaddr_in(“smtp”, “2001:DB8::1”)
-
Socket.sockaddr_in(80, “172.18.22.42”)
-
Socket.sockaddr_in(80, “www.ruby-lang.org”)
-
Socket.sockaddr_un(“/tmp/sock”)
В массиве sockaddr AF_INET/AF_INET6 используется 4-й элемент, числовой IP-адрес, для построения адреса сокета в экземпляре Addrinfo. Если 3-й элемент, текстовое имя хоста, не равен nil, он также записывается, но используется только для #inspect.
family задаётся целым числом для указания семейства протоколов, например, Socket::PF_INET. Это может быть символ или строка, имя константы с префиксом PF_ или без него, например :INET, :INET6, :UNIX, “PF_INET” и т.д. Если опущено, предполагается PF_UNSPEC.
socktype задаётся целым числом для указания типа сокета, например, Socket::SOCK_STREAM. Это может быть символ или строка, имя константы с префиксом SOCK_ или без него, например :STREAM, :DGRAM, :RAW, “SOCK_STREAM” и т.д. Если опущено, предполагается 0.
protocol задаётся целым числом для указания протокола, например, Socket::IPPROTO_TCP. Он должен быть целым числом, в отличие от family и socktype. Если опущено, предполагается 0. Обратите внимание, что 0 является разумным значением для большинства протоколов, за исключением raw-сокетов.
static VALUE
addrinfo_s_tcp(VALUE self, VALUE host, VALUE port)
{
return addrinfo_firstonly_new(host, port,
INT2NUM(PF_UNSPEC), INT2NUM(SOCK_STREAM), INT2NUM(IPPROTO_TCP), INT2FIX(0));
} Возвращает объект addrinfo для TCP-адреса.
Addrinfo.tcp("localhost", "smtp") #=> #<Addrinfo: 127.0.0.1:25 TCP (localhost:smtp)>
static VALUE
addrinfo_s_udp(VALUE self, VALUE host, VALUE port)
{
return addrinfo_firstonly_new(host, port,
INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0));
} Возвращает объект addrinfo для UDP-адреса.
Addrinfo.udp("localhost", "daytime") #=> #<Addrinfo: 127.0.0.1:13 UDP (localhost:daytime)>
static VALUE
addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
{
VALUE path, vsocktype, addr;
int socktype;
rb_addrinfo_t *rai;
rb_scan_args(argc, argv, "11", &path, &vsocktype);
if (NIL_P(vsocktype))
socktype = SOCK_STREAM;
else
socktype = rsock_socktype_arg(vsocktype);
addr = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(addr) = rai = alloc_addrinfo();
init_unix_addrinfo(rai, path, socktype);
OBJ_INFECT(addr, path);
return addr;
} Возвращает объект addrinfo для адреса сокета UNIX.
socktype указывает тип сокета. Если он опущен, используется :STREAM.
Addrinfo.unix("/tmp/sock") #=> #<Addrinfo: /tmp/sock SOCK_STREAM>
Addrinfo.unix("/tmp/sock", :DGRAM) #=> #<Addrinfo: /tmp/sock SOCK_DGRAM>
Методы публичного экземпляра
static VALUE
addrinfo_afamily(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
return INT2NUM(ai_get_afamily(rai));
} возвращает семейство адресов в виде целого числа.
Addrinfo.tcp("localhost", 80).afamily == Socket::AF_INET #=> true
# File ext/socket/lib/socket.rb, line 179
def bind
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
begin
sock.ipv6only! if self.ipv6?
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
sock.bind(self)
rescue Exception
sock.close
raise
end
if block_given?
begin
yield sock
ensure
sock.close if !sock.closed?
end
else
sock
end
end создаёт сокет, привязанный к себе.
Если задан блок, он вызывается с сокетом, и возвращается значение блока. В противном случае возвращается сокет.
Addrinfo.udp("0.0.0.0", 9981).bind {|s|
s.local_address.connect {|s| s.send "hello", 0 }
p s.recv(10) #=> "hello"
}
static VALUE
addrinfo_canonname(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
return rai->canonname;
} возвращает каноническое имя в виде строки.
Возвращает nil, если каноническое имя отсутствует.
Каноническое имя устанавливается ::getaddrinfo при указании AI_CANONNAME.
list = Addrinfo.getaddrinfo("www.ruby-lang.org", 80, :INET, :STREAM, nil, Socket::AI_CANONNAME)
p list[0] #=> #<Addrinfo: 221.186.184.68:80 TCP carbon.ruby-lang.org (www.ruby-lang.org)>
p list[0].canonname #=> "carbon.ruby-lang.org"
# File ext/socket/lib/socket.rb, line 139
def connect(opts={}, &block)
connect_internal(nil, opts[:timeout], &block)
end создаёт сокет, подключённый к адресу self.
Необязательный параметр opts представляет собой опции в виде хэша. opts может содержать следующие опции:
- :timeout
-
указывает тайм-аут в секундах.
Если задан блок, он вызывается с сокетом, и возвращается значение блока. В противном случае возвращается сокет.
Addrinfo.tcp("www.ruby-lang.org", 80).connect {|s|
s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
puts s.read
}
# File ext/socket/lib/socket.rb, line 114
def connect_from(*args, &block)
opts = Hash === args.last ? args.pop : {}
local_addr_args = args
connect_internal(family_addrinfo(*local_addr_args), opts[:timeout], &block)
end создаёт сокет, подключённый к адресу self.
Если один или более аргументов заданы как local_addr_args, они используются в качестве локального адреса сокета. local_addr_args используется для #family_addrinfo для получения фактического адреса.
Если local_addr_args не заданы, локальный адрес сокета не привязывается.
Необязательный последний параметр opts представляет собой опции в виде хэша. opts может содержать следующие опции:
- :timeout
-
указывает тайм-аут в секундах.
Если задан блок, он вызывается с сокетом, и возвращается значение блока. В противном случае возвращается сокет.
Addrinfo.tcp("www.ruby-lang.org", 80).connect_from("0.0.0.0", 4649) {|s|
s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
puts s.read
}
# Addrinfo object can be taken for the argument.
Addrinfo.tcp("www.ruby-lang.org", 80).connect_from(Addrinfo.tcp("0.0.0.0", 4649)) {|s|
s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
puts s.read
}
# File ext/socket/lib/socket.rb, line 162
def connect_to(*args, &block)
opts = Hash === args.last ? args.pop : {}
remote_addr_args = args
remote_addrinfo = family_addrinfo(*remote_addr_args)
remote_addrinfo.send(:connect_internal, self, opts[:timeout], &block)
end создаёт сокет, подключённый к remote_addr_args и привязанный к self.
Необязательный последний параметр opts представляет собой опции в виде хэша. opts может содержать следующие опции:
- :timeout
-
указывает тайм-аут в секундах.
Если задан блок, он вызывается с сокетом, и возвращается значение блока. В противном случае возвращается сокет.
Addrinfo.tcp("0.0.0.0", 4649).connect_to("www.ruby-lang.org", 80) {|s|
s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
puts s.read
}
# File ext/socket/lib/socket.rb, line 14
def family_addrinfo(*args)
if args.empty?
raise ArgumentError, "no address specified"
elsif Addrinfo === args.first
raise ArgumentError, "too many arguments" if args.length != 1
addrinfo = args.first
if (self.pfamily != addrinfo.pfamily) ||
(self.socktype != addrinfo.socktype)
raise ArgumentError, "Addrinfo type mismatch"
end
addrinfo
elsif self.ip?
raise ArgumentError, "IP address needs host and port but #{args.length} arguments given" if args.length != 2
host, port = args
Addrinfo.getaddrinfo(host, port, self.pfamily, self.socktype, self.protocol)[0]
elsif self.unix?
raise ArgumentError, "UNIX socket needs single path argument but #{args.length} arguments given" if args.length != 1
path, = args
Addrinfo.unix(path)
else
raise ArgumentError, "unexpected family"
end
end создаёт объект Addrinfo из аргументов.
Аргументы интерпретируются аналогично self.
Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("www.ruby-lang.org", 80)
#=> #<Addrinfo: 221.186.184.68:80 TCP (www.ruby-lang.org:80)>
Addrinfo.unix("/tmp/sock").family_addrinfo("/tmp/sock2")
#=> #<Addrinfo: /tmp/sock2 SOCK_STREAM>
static VALUE
addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
VALUE vflags;
char hbuf[1024], pbuf[1024];
int flags, error;
rb_scan_args(argc, argv, "01", &vflags);
flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
if (rai->socktype == SOCK_DGRAM)
flags |= NI_DGRAM;
error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
flags);
if (error) {
rsock_raise_socket_error("getnameinfo", error);
}
return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
} возвращает nodename и service в виде пары строк. Это преобразует struct sockaddr в addrinfo в текстовое представление.
flags должны быть битовым ИЛИ констант Socket::NI_???.
Addrinfo.tcp("127.0.0.1", 80).getnameinfo #=> ["localhost", "www"]
Addrinfo.tcp("127.0.0.1", 80).getnameinfo(Socket::NI_NUMERICSERV)
#=> ["localhost", "80"]
static VALUE
addrinfo_inspect(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
int internet_p;
VALUE ret;
ret = rb_sprintf("#<%s: ", rb_obj_classname(self));
inspect_sockaddr(self, ret);
if (rai->pfamily && ai_get_afamily(rai) != rai->pfamily) {
ID id = rsock_intern_protocol_family(rai->pfamily);
if (id)
rb_str_catf(ret, " %s", rb_id2name(id));
else
rb_str_catf(ret, " PF_\?\?\?(%d)", rai->pfamily);
}
internet_p = rai->pfamily == PF_INET;
#ifdef INET6
internet_p = internet_p || rai->pfamily == PF_INET6;
#endif
if (internet_p && rai->socktype == SOCK_STREAM &&
(rai->protocol == 0 || rai->protocol == IPPROTO_TCP)) {
rb_str_cat2(ret, " TCP");
}
else if (internet_p && rai->socktype == SOCK_DGRAM &&
(rai->protocol == 0 || rai->protocol == IPPROTO_UDP)) {
rb_str_cat2(ret, " UDP");
}
else {
if (rai->socktype) {
ID id = rsock_intern_socktype(rai->socktype);
if (id)
rb_str_catf(ret, " %s", rb_id2name(id));
else
rb_str_catf(ret, " SOCK_\?\?\?(%d)", rai->socktype);
}
if (rai->protocol) {
if (internet_p) {
ID id = rsock_intern_ipproto(rai->protocol);
if (id)
rb_str_catf(ret, " %s", rb_id2name(id));
else
goto unknown_protocol;
}
else {
unknown_protocol:
rb_str_catf(ret, " UNKNOWN_PROTOCOL(%d)", rai->protocol);
}
}
}
if (!NIL_P(rai->canonname)) {
VALUE name = rai->canonname;
rb_str_catf(ret, " %s", StringValueCStr(name));
}
if (!NIL_P(rai->inspectname)) {
VALUE name = rai->inspectname;
rb_str_catf(ret, " (%s)", StringValueCStr(name));
}
rb_str_buf_cat2(ret, ">");
return ret;
} возвращает строку, которая отображает addrinfo в удобочитаемой форме.
Addrinfo.tcp("localhost", 80).inspect #=> "#<Addrinfo: 127.0.0.1:80 TCP (localhost)>"
Addrinfo.unix("/tmp/sock").inspect #=> "#<Addrinfo: /tmp/sock SOCK_STREAM>"
VALUE
rsock_addrinfo_inspect_sockaddr(VALUE self)
{
return inspect_sockaddr(self, rb_str_new("", 0));
} возвращает строку, которая отображает sockaddr в addrinfo в удобочитаемой форме.
Addrinfo.tcp("localhost", 80).inspect_sockaddr #=> "127.0.0.1:80"
Addrinfo.tcp("ip6-localhost", 80).inspect_sockaddr #=> "[::1]:80"
Addrinfo.unix("/tmp/sock").inspect_sockaddr #=> "/tmp/sock"
static VALUE
addrinfo_ip_p(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
return IS_IP_FAMILY(family) ? Qtrue : Qfalse;
} возвращает true, если addrinfo — интернет-адрес (IPv4/IPv6); в противном случае — false.
Addrinfo.tcp("127.0.0.1", 80).ip? #=> true
Addrinfo.tcp("::1", 80).ip? #=> true
Addrinfo.unix("/tmp/sock").ip? #=> false
static VALUE
addrinfo_ip_address(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
VALUE vflags;
VALUE ret;
if (!IS_IP_FAMILY(family))
rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
ret = addrinfo_getnameinfo(1, &vflags, self);
return rb_ary_entry(ret, 0);
} Возвращает IP-адрес в виде строки.
Addrinfo.tcp("127.0.0.1", 80).ip_address #=> "127.0.0.1"
Addrinfo.tcp("::1", 80).ip_address #=> "::1"
static VALUE
addrinfo_ip_port(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
int port;
if (!IS_IP_FAMILY(family)) {
bad_family:
#ifdef AF_INET6
rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
#else
rb_raise(rb_eSocket, "need IPv4 address");
#endif
}
switch (family) {
case AF_INET:
if (rai->sockaddr_len != sizeof(struct sockaddr_in))
rb_raise(rb_eSocket, "unexpected sockaddr size for IPv4");
port = ntohs(rai->addr.in.sin_port);
break;
#ifdef AF_INET6
case AF_INET6:
if (rai->sockaddr_len != sizeof(struct sockaddr_in6))
rb_raise(rb_eSocket, "unexpected sockaddr size for IPv6");
port = ntohs(rai->addr.in6.sin6_port);
break;
#endif
default:
goto bad_family;
}
return INT2NUM(port);
} Возвращает номер порта в виде целого числа.
Addrinfo.tcp("127.0.0.1", 80).ip_port #=> 80
Addrinfo.tcp("::1", 80).ip_port #=> 80
static VALUE
addrinfo_ip_unpack(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
VALUE vflags;
VALUE ret, portstr;
if (!IS_IP_FAMILY(family))
rb_raise(rb_eSocket, "need IPv4 or IPv6 address");
vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV);
ret = addrinfo_getnameinfo(1, &vflags, self);
portstr = rb_ary_entry(ret, 1);
rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))));
return ret;
} Возвращает IP-адрес и номер порта в виде массива из 2 элементов.
Addrinfo.tcp("127.0.0.1", 80).ip_unpack #=> ["127.0.0.1", 80]
Addrinfo.tcp("::1", 80).ip_unpack #=> ["::1", 80]
static VALUE
addrinfo_ipv4_p(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
return ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse;
} возвращает true, если addrinfo — IPv4-адрес, иначе — false.
Addrinfo.tcp("127.0.0.1", 80).ipv4? #=> true
Addrinfo.tcp("::1", 80).ipv4? #=> false
Addrinfo.unix("/tmp/sock").ipv4? #=> false
static VALUE
addrinfo_ipv4_loopback_p(VALUE self)
{
uint32_t a;
if (!extract_in_addr(self, &a)) return Qfalse;
if ((a & 0xff000000) == 0x7f000000) /* 127.0.0.0/8 */
return Qtrue;
return Qfalse;
} Возвращает true для IPv4-адреса обратной петли (127.0.0.0/8), иначе — false.
static VALUE
addrinfo_ipv4_multicast_p(VALUE self)
{
uint32_t a;
if (!extract_in_addr(self, &a)) return Qfalse;
if ((a & 0xf0000000) == 0xe0000000) /* 224.0.0.0/4 */
return Qtrue;
return Qfalse;
} Возвращает true для IPv4-адреса мультикаста (224.0.0.0/4), иначе — false.
static VALUE
addrinfo_ipv4_private_p(VALUE self)
{
uint32_t a;
if (!extract_in_addr(self, &a)) return Qfalse;
if ((a & 0xff000000) == 0x0a000000 || /* 10.0.0.0/8 */
(a & 0xfff00000) == 0xac100000 || /* 172.16.0.0/12 */
(a & 0xffff0000) == 0xc0a80000) /* 192.168.0.0/16 */
return Qtrue;
return Qfalse;
} Возвращает true для приватного IPv4-адреса (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), иначе — false.
static VALUE
addrinfo_ipv6_p(VALUE self)
{
#ifdef AF_INET6
rb_addrinfo_t *rai = get_addrinfo(self);
return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse;
#else
return Qfalse;
#endif
} возвращает true, если addrinfo — IPv6-адрес, иначе — false.
Addrinfo.tcp("127.0.0.1", 80).ipv6? #=> false
Addrinfo.tcp("::1", 80).ipv6? #=> true
Addrinfo.unix("/tmp/sock").ipv6? #=> false
static VALUE
addrinfo_ipv6_linklocal_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_LINKLOCAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для IPv6-адреса локальной связи (ff80::/10), иначе — false.
static VALUE
addrinfo_ipv6_loopback_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_LOOPBACK(addr)) return Qtrue;
return Qfalse;
} Возвращает true для IPv6-адреса обратной петли (::1), иначе — false.
static VALUE
addrinfo_ipv6_mc_global_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_MC_GLOBAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для адреса IPv6 с глобальной областью действия для мультикаста. В противном случае возвращает false.
static VALUE
addrinfo_ipv6_mc_linklocal_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_MC_LINKLOCAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для адреса IPv6 с областью действия локальной сети для мультикаста. В противном случае возвращает false.
static VALUE
addrinfo_ipv6_mc_nodelocal_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_MC_NODELOCAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для адреса IPv6 с областью действия узла для мультикаста. В противном случае возвращает false.
static VALUE
addrinfo_ipv6_mc_orglocal_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_MC_ORGLOCAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для адреса IPv6 с областью действия локальной организации для мультикаста. В противном случае возвращает false.
static VALUE
addrinfo_ipv6_mc_sitelocal_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_MC_SITELOCAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для адреса IPv6 с областью действия локального сайта для мультикаста. В противном случае возвращает false.
static VALUE
addrinfo_ipv6_multicast_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_MULTICAST(addr)) return Qtrue;
return Qfalse;
} Возвращает true для адреса IPv6 мультикаста (ff00::/8). В противном случае возвращает false.
static VALUE
addrinfo_ipv6_sitelocal_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_SITELOCAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для адреса IPv6 локального сайта (ffc0::/10). В противном случае возвращает false.
static VALUE
addrinfo_ipv6_to_ipv4(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
struct in6_addr *addr;
int family = ai_get_afamily(rai);
if (family != AF_INET6) return Qnil;
addr = &rai->addr.in6.sin6_addr;
if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) {
struct sockaddr_in sin4;
INIT_SOCKADDR_IN(&sin4, sizeof(sin4));
memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr));
return rsock_addrinfo_new((struct sockaddr *)&sin4, (socklen_t)sizeof(sin4),
PF_INET, rai->socktype, rai->protocol,
rai->canonname, rai->inspectname);
}
else {
return Qnil;
}
} Возвращает IPv4-адрес IPv4-сопоставленного/совместимого IPv6-адреса. Возвращает nil, если self не является IPv4-сопоставленным/совместимым IPv6-адресом.
Addrinfo.ip("::192.0.2.3").ipv6_to_ipv4 #=> #<Addrinfo: 192.0.2.3>
Addrinfo.ip("::ffff:192.0.2.3").ipv6_to_ipv4 #=> #<Addrinfo: 192.0.2.3>
Addrinfo.ip("::1").ipv6_to_ipv4 #=> nil
Addrinfo.ip("192.0.2.3").ipv6_to_ipv4 #=> nil
Addrinfo.unix("/tmp/sock").ipv6_to_ipv4 #=> nil
static VALUE
addrinfo_ipv6_unique_local_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_UNIQUE_LOCAL(addr)) return Qtrue;
return Qfalse;
} Возвращает true для уникального локального адреса IPv6 (fc00::/7, RFC4193). В противном случае возвращает false.
static VALUE
addrinfo_ipv6_unspecified_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_UNSPECIFIED(addr)) return Qtrue;
return Qfalse;
} Возвращает true для неопределенного IPv6-адреса (::). В противном случае возвращает false.
static VALUE
addrinfo_ipv6_v4compat_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_V4COMPAT(addr)) return Qtrue;
return Qfalse;
} Возвращает true для IPv4-совместимого IPv6-адреса (::/80). В противном случае возвращает false.
static VALUE
addrinfo_ipv6_v4mapped_p(VALUE self)
{
struct in6_addr *addr = extract_in6_addr(self);
if (addr && IN6_IS_ADDR_V4MAPPED(addr)) return Qtrue;
return Qfalse;
} Возвращает true для IPv4-отображённого IPv6-адреса (::ffff:0:0/80). В противном случае возвращает false.
# File ext/socket/lib/socket.rb, line 201
def listen(backlog=Socket::SOMAXCONN)
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
begin
sock.ipv6only! if self.ipv6?
sock.setsockopt(:SOCKET, :REUSEADDR, 1)
sock.bind(self)
sock.listen(backlog)
rescue Exception
sock.close
raise
end
if block_given?
begin
yield sock
ensure
sock.close if !sock.closed?
end
else
sock
end
end создаёт сокет, который ожидает подключений, привязанный к самому себе.
static VALUE
addrinfo_pfamily(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
return INT2NUM(rai->pfamily);
} возвращает семейство протокола как целое число.
Addrinfo.tcp("localhost", 80).pfamily == Socket::PF_INET #=> true
static VALUE
addrinfo_protocol(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
return INT2NUM(rai->protocol);
} возвращает тип сокета как целое число.
Addrinfo.tcp("localhost", 80).protocol == Socket::IPPROTO_TCP #=> true
static VALUE
addrinfo_socktype(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
return INT2NUM(rai->socktype);
} возвращает тип сокета как целое число.
Addrinfo.tcp("localhost", 80).socktype == Socket::SOCK_STREAM #=> true
static VALUE
addrinfo_to_sockaddr(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
VALUE ret;
ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len);
OBJ_INFECT(ret, self);
return ret;
} возвращает адрес сокета как упакованную строку struct sockaddr.
Addrinfo.tcp("localhost", 80).to_sockaddr
#=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
static VALUE
addrinfo_to_sockaddr(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
VALUE ret;
ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len);
OBJ_INFECT(ret, self);
return ret;
} возвращает адрес сокета как упакованную строку struct sockaddr.
Addrinfo.tcp("localhost", 80).to_sockaddr
#=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
static VALUE
addrinfo_unix_p(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
#ifdef AF_UNIX
return ai_get_afamily(rai) == AF_UNIX ? Qtrue : Qfalse;
#else
return Qfalse;
#endif
} возвращает true, если addrinfo — адрес UNIX. В противном случае возвращает false.
Addrinfo.tcp("127.0.0.1", 80).unix? #=> false
Addrinfo.tcp("::1", 80).unix? #=> false
Addrinfo.unix("/tmp/sock").unix? #=> true
static VALUE
addrinfo_unix_path(VALUE self)
{
rb_addrinfo_t *rai = get_addrinfo(self);
int family = ai_get_afamily(rai);
struct sockaddr_un *addr;
char *s, *e;
if (family != AF_UNIX)
rb_raise(rb_eSocket, "need AF_UNIX address");
addr = &rai->addr.un;
s = addr->sun_path;
e = (char*)addr + rai->sockaddr_len;
if (e < s)
rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.",
(size_t)rai->sockaddr_len, (size_t)(s - (char *)addr));
if (addr->sun_path + sizeof(addr->sun_path) < e)
rb_raise(rb_eSocket,
"too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
(size_t)(e - addr->sun_path), sizeof(addr->sun_path));
while (s < e && *(e-1) == '\0')
e--;
return rb_str_new(s, e-s);
} Возвращает путь к сокету как строку.
Addrinfo.unix("/tmp/sock").unix_path #=> "/tmp/sock"
Приватные методы экземпляра
# File ext/socket/lib/socket.rb, line 47
def connect_internal(local_addrinfo, timeout=nil) # :yields: socket
sock = Socket.new(self.pfamily, self.socktype, self.protocol)
begin
sock.ipv6only! if self.ipv6?
sock.bind local_addrinfo if local_addrinfo
if timeout
begin
sock.connect_nonblock(self)
rescue IO::WaitWritable
if !IO.select(nil, [sock], nil, timeout)
raise Errno::ETIMEDOUT, 'user specified timeout'
end
begin
sock.connect_nonblock(self) # check connection failure
rescue Errno::EISCONN
end
end
else
sock.connect(self)
end
rescue Exception
sock.close
raise
end
if block_given?
begin
yield sock
ensure
sock.close if !sock.closed?
end
else
sock
end
end создаёт новый Socket, подключенный к адресу local_addrinfo.
Если local_addrinfo равно nil, адрес сокета не привязывается.
timeout задаёт время ожидания в секундах. При превышении времени ожидания генерируется исключение Errno::ETIMEDOUT.
Если задан блок, созданный сокет передаётся в блок для каждого адреса.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.