соответствие getaddrinfo в Windows против систем Unixy - PullRequest
0 голосов
/ 14 апреля 2020

Когда я запускаю getaddrinfo() на Windows против NetBSD / MacOS / Linux, я получаю некоторые существенные поведенческие различия. Если я использую буфер hints с ai_socktype = 0:

  • В системах Unixy результаты, по-видимому, включают все доступные типы сокетов. Т.е. если в системе есть SOCK_STREAM, SOCK_DGRAM, оба они будут возвращены. Для систем с SOCK_RAW также будет возвращено SOCK_RAW.
  • При Windows будет возвращен один результат, и результат будет иметь ai_socktype = 0 (т.е. он вернет вход, а не все совпадения) , Если это протокол "известного tcp" или "известного udp", в этом случае ai_socktype устанавливается соответствующим образом.

Я использую этот небольшой пример, чтобы поэкспериментировать с:

#include <stdio.h>
#include <string.h>

#ifdef _WIN32
#include <Winsock2.h>
#include <ws2tcpip.h>
#include <assert.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif


int main(int argc, const char *argv[])
{
  int n;
  struct addrinfo *res0 = NULL, *res;
  const char *hostname = NULL;
  /* const char *service = "http"; */
  /* const char *service = "tftp"; */
  /* const char *service = "8080"; */
   const char *service = "27000";

  struct addrinfo hints;

#ifdef _WIN32
  WSADATA wsaData;
  int ret;

  ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
  assert(ret == 0);
#endif

  (void)memset(&hints, 0x00, sizeof(hints));

  hints.ai_family = PF_UNSPEC;

  n = getaddrinfo(hostname, service, &hints, &res0);
  if(n < 0) {
    return 1;
  }

  for(res = res0; res; res = res->ai_next) {
    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

    n = getnameinfo((struct sockaddr *)res->ai_addr, res->ai_addrlen,
        hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
        NI_NOFQDN|NI_NUMERICHOST|NI_NUMERICSERV);
    if(n != 0) {
      printf("getnameinfo() failed: %s\n", gai_strerror(n));
      return 1;
    }
    printf("%s %s %u %u\n", hbuf, sbuf, (unsigned)res->ai_socktype,
        (unsigned)res->ai_protocol);
  }

  freeaddrinfo(res0);

#ifdef _WIN32
  ret = WSACleanup();
  assert(ret == 0);
#endif

  return 0;
}

При запуске на Windows с service, установленным на "http", я получу ai_socktype = SOCK_STREAM результаты (один для IPv6 и один для IPv4). При запуске с "tftp" я получаю ai_socktype = SOCK_DGRAM результаты. 8080 дает ai_socktype = 0 результатов, как и 27000.

Мне кажется, что Windows getaddrinfo() возвращает "известные" (или общие) типы сокетов протокола в ai_socktype, и когда используемая база данных getaddrinfo() не может найти подходящих совпадений, она возвращает запись ai_socktype = 0, по сути говоря, «семейство протоколов существует, но мы ничего не знаем о типах сокетов этого порта. предполагается, что он поддерживает ".

В то время как на платформах Unixy getaddrinfo() ведет себя намного больше как запрос для поиска всех возможных совпадений, где ai_socktype = 0 означает" вернуть все совпадения ". (Или, возможно, он должен делать то, что делает Windows, но tcp и udp определены неявно для всех портов?).

Правильно ли я понял различия в поведении? Есть ли способ заставить Windows 'getaddrinfo() вести себя так же, как в системах Unixy? Я пролистал https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo (извините будущих читателей, я знаю, что Microsoft нравится перемещать их документацию, ломая ссылки с течением времени), но не увидел ничего, что могло бы сделать это "соответствующим всем records ".

Кроме того, из какой базы данных Windows получены совпадения ее типа socktype? Какое-то время я волновался, что эти совпадения проводятся и в системах Unixy, просто я был слишком смущен, чтобы заметить это раньше. Вот почему у меня в этом примере service / port 27000 - этот порт не указан в моих / etc / services моего Ma c, но getaddrinfo() по-прежнему возвращает SOCK_STREAM и SOCK_DGRAM для этого порта.

Редактировать:

Возможные значения параметра pServiceName, если номер порта не указан, перечислены в следующем файле:

% WINDIR% \ system32 \ drivers \ etc \ услуги

...