Spec-Zone.ru › Ruby 3

класс 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 в виде массива.

Этот метод преобразует имя узла (имя хоста) и службу (порт) в 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>
END_OF_DOCUMENT_MARKER

Методы открытого экземпляра

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 должны быть побитовым OR констант 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 → [addr, порт] Показать исходный код
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 для адреса IPv6, сопоставленного с IPv4 (::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

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

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
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 или 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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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