класс Addrinfo
Методы класса
# File ext/socket/lib/socket.rb, line 226 def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, timeout: nil, &block) Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags, timeout: timeout).each(&block) end
итерирует по списку объектов Addrinfo, полученных методом 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, opts, timeout;
rb_scan_args(argc, argv, "24:", &node, &service, &family, &socktype,
&protocol, &flags, &opts);
rb_get_kwargs(opts, &id_timeout, 0, 1, &timeout);
if (timeout == Qundef) {
timeout = Qnil;
}
return addrinfo_list_new(node, service, family, socktype, protocol, flags, timeout);
} возвращает список объектов addrinfo в виде массива.
Этот метод преобразует имя узла (hostname) и имя службы (port) в объекты addrinfo. Поскольку это преобразование не единственное, результат представляет собой список объектов addrinfo.
nodename или service могут быть nil, если преобразование не требуется.
family, socktype и protocol являются подсказками для предпочтительного протокола. Если результат будет использоваться для сокета с типом SOCK_STREAM, socktype должен быть указан как SOCK_STREAM. В этом случае Addrinfo.getaddrinfo возвращает список addrinfo, подходящий для SOCK_STREAM. Если они опушены или указан nil, результат не ограничен.
Аналогично, PF_INET6 в качестве family ограничивает результат IPv6.
flags должны быть побитовым ИЛИ констант 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 опущен, а servname задан как целое число, потому что некоторые номера портов, например 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 используется четвёртый элемент — числовой IP-адрес, для построения адреса сокета в экземпляре Addrinfo. Если третий элемент — текстовое имя хоста — не равен nil, он также записывается, но используется только для Addrinfo#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 — разумное значение для большинства протоколов, за исключением сырого сокета.
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);
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 174
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
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, если каноническое имя отсутствует.
Каноническое имя устанавливается методом Addrinfo.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 136 def connect(timeout: nil, &block) connect_internal(nil, timeout, &block) end
создаёт сокет, подключённый к адресу текущего объекта.
Необязательный аргумент 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 113 def connect_from(*args, timeout: nil, &block) connect_internal(family_addrinfo(*args), timeout, &block) end
создаёт сокет, подключённый к адресу текущего объекта.
Если один или несколько аргументов заданы как 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 159 def connect_to(*args, timeout: nil, &block) remote_addrinfo = family_addrinfo(*args) remote_addrinfo.connect_internal(self, timeout, &block) end
создаёт сокет, подключённый к remote_addr_args и привязанный к текущему объекту.
Необязательный последний аргумент 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 17
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 из аргументов.
Аргументы интерпретируются аналогично текущему объекту.
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));
} возвращает имя узла и порт в виде пары строк. Преобразует структуру 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-адрес и номер порта в виде массива из двух элементов.
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 196
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
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
возвращает адрес сокета в формате закодированной строки 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);
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;
long n;
if (family != AF_UNIX)
rb_raise(rb_eSocket, "need AF_UNIX address");
addr = &rai->addr.un;
n = rai_unixsocket_len(rai);
if (n < 0)
rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.",
(size_t)rai->sockaddr_len, offsetof(struct sockaddr_un, sun_path));
if ((long)sizeof(addr->sun_path) < n)
rb_raise(rb_eSocket,
"too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
(size_t)n, sizeof(addr->sun_path));
return rb_str_new(addr->sun_path, n);
} Возвращает путь к сокету в виде строки.
Addrinfo.unix("/tmp/sock").unix_path #=> "/tmp/sock"
Защищённые методы экземпляра
# File ext/socket/lib/socket.rb, line 50
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
case sock.connect_nonblock(self, exception: false)
when 0 # success or EISCONN, other errors raise
break
when :wait_writable
sock.wait_writable(timeout) or
raise Errno::ETIMEDOUT, 'user specified timeout'
end while true
else
sock.connect(self)
end
rescue Exception
sock.close
raise
end
if block_given?
begin
yield sock
ensure
sock.close
end
else
sock
end
end создаёт новый Socket соединённый с адресом local_addrinfo.
Если local_addrinfo равно nil, адрес сокета не привязывается.
timeout задаёт время ожидания в секундах. При превышении времени ожидания генерируется исключение Errno::ETIMEDOUT.
Если передан блок, созданный сокет передаётся в блок для каждого адреса.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.