Spec-Zone.ru › Ruby 3.1

класс Addrinfo

Родитель:
Объект

Методы класса

foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, timeout: nil, &block) Показать исходный код
# 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)>
getaddrinfo(nodename, service, family, socktype, protocol, flags) → [addrinfo, ...] Показать исходный код
getaddrinfo(nodename, service, family, socktype, protocol) → [addrinfo, ...]
getaddrinfo(nodename, service, family, socktype) → [addrinfo, ...]
getaddrinfo(nodename, service, family) → [addrinfo, ...]
getaddrinfo(nodename, service) → [addrinfo, ...]
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)>]
ip(host) → addrinfo Показать исходный код
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)>
new(sockaddr) → addrinfo Показать исходный код
new(sockaddr, family) → addrinfo
new(sockaddr, family, socktype) → addrinfo
new(sockaddr, family, socktype, protocol) → addrinfo
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 — разумное значение для большинства протоколов, за исключением сырого сокета.

tcp(host, port) → addrinfo Показать исходный код
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)>
udp(host, port) → addrinfo Показать исходный код
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)>
unix(path [, socktype]) → addrinfo Показать исходный код
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>

Методы публичного экземпляра

afamily → целое число Показать исходный код
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
bind() { |sock| ... } Показать исходный код
# 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"
}
canonname → строка или nil Показать исходный код
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"
connect([opts]) {|socket| ... } Показать исходный код
connect([opts])
# 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
}
connect_from([local_addr_args], [opts]) {|socket| ... } Показать исходный код
connect_from([local_addr_args], [opts])
# 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
}
connect_to([remote_addr_args], [opts]) {|socket| ... } Показать исходный код
connect_to([remote_addr_args], [opts])
# 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
}
family_addrinfo(*args) Показать исходный код
# 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>
getnameinfo → [имя узла, порт] Показать исходный код
getnameinfo(flags) → [имя узла, порт]
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"]
inspect → строка Показать исходный код
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>"
inspect_sockaddr → строка Показать исходный код
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"
ip? → true или false Показать исходный код
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
ip_address → строка Показать исходный код
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"
ip_port → порт Показать исходный код
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
ip_unpack → [адрес, порт] Показать исходный код
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]
ipv4? → true или false Показать исходный код
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
ipv4_loopback?() Показать исходный код
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.

ipv4_multicast?() Показать исходный код
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.

ipv4_private?() Показать исходный код
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.

ipv6? → true или 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
ipv6_linklocal?() Показать исходный код
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.

ipv6_loopback?() Показать исходный код
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.

END_OF_DOCUMENT_MARKER
ipv6_mc_global?() Показать исходный код
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.

ipv6_mc_linklocal?() Показать исходный код
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.

ipv6_mc_nodelocal?() Показать исходный код
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.

ipv6_mc_orglocal?() Показать исходный код
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.

ipv6_mc_sitelocal?() Показать исходный код
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.

ipv6_multicast?() Показать исходный код
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.

ipv6_sitelocal?() Показать исходный код
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.

ipv6_to_ipv4() Показать исходный код
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
ipv6_unique_local?() Показать исходный код
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.

ipv6_unspecified?() Показать исходный код
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.

ipv6_v4compat?() Показать исходный код
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.

ipv6_v4mapped?() Показать исходный код
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.

listen(backlog=Socket::SOMAXCONN) { |sock| ... } Показать исходный код
# 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

создаёт сокет для прослушивания, привязанный к себе.

pfamily → integer Показать исходный код
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
protocol → integer Показать исходный код
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
socktype → integer Показать исходный код
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
to_s → string

возвращает адрес сокета в формате закодированной строки struct sockaddr.

Addrinfo.tcp("localhost", 80).to_sockaddr
#=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
Псевдоним для: to_sockaddr
to_sockaddr => string Показать исходный код
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"
Также псевдоним для: to_s
unix? → true or false Показать исходный код
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
unix_path → путь Показать исходный код
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"

Защищённые методы экземпляра

connect_internal(local_addrinfo, timeout=nil) { |socket| ... } Показать исходный код
# 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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API