You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
10 KiB
360 lines
10 KiB
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
|
|
//
|
|
// Copyright (c) 1998-2001 Microsoft Corporation
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Program to perform demonstrate name resolution via getaddrinfo.
|
|
//
|
|
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
void DumpAddrInfo(ADDRINFO *AddrInfo);
|
|
void ListAddrInfo(ADDRINFO *AddrInfo);
|
|
|
|
//
|
|
// getaddrinfo flags
|
|
// This array maps values to names for pretty-printing purposes.
|
|
// Used by DecodeAIFlags().
|
|
//
|
|
// TBD: When we add support for AI_NUMERICSERV, AI_V4MAPPED, AI_ALL, and
|
|
// TBD: AI_ADDRCONFIG to getaddrinfo (and thus define them in ws2tcpip.h),
|
|
// TBD: we'll need to add them here too.
|
|
//
|
|
// Note when adding flags: all the string names plus connecting OR symbols
|
|
// must fit into the buffer in DecodeAIFlags() below. Enlarge as required.
|
|
//
|
|
typedef struct GAIFlagsArrayEntry {
|
|
int Flag;
|
|
char *Name;
|
|
} GAIFlagsArrayEntry;
|
|
GAIFlagsArrayEntry GAIFlagsArray [] = {
|
|
{AI_PASSIVE, "AI_PASSIVE"},
|
|
{AI_CANONNAME, "AI_CANONNAME"},
|
|
{AI_NUMERICHOST, "AI_NUMERICHOST"}
|
|
};
|
|
#define NUMBER_FLAGS (sizeof(GAIFlagsArray) / sizeof(GAIFlagsArrayEntry))
|
|
|
|
|
|
//
|
|
// Global variables.
|
|
//
|
|
int Verbose = FALSE;
|
|
|
|
|
|
//
|
|
// Inform the user.
|
|
//
|
|
void Usage(char *ProgName) {
|
|
fprintf(stderr, "\nPerforms name to address resolution.\n");
|
|
fprintf(stderr, "\n%s [NodeName] [-s ServiceName] [-p] [-c] [-v]\n\n",
|
|
ProgName);
|
|
WSACleanup();
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int __cdecl
|
|
main(int argc, char **argv)
|
|
{
|
|
WSADATA wsaData;
|
|
char *NodeName = NULL;
|
|
char *ServiceName = NULL;
|
|
int ReturnValue;
|
|
ADDRINFO Hints, *AddrInfo;
|
|
int Loop;
|
|
int Passive = FALSE;
|
|
int Canonical = FALSE;
|
|
int GotNodeName = FALSE;
|
|
|
|
//
|
|
// Initialize Winsock.
|
|
//
|
|
if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
|
|
printf("WSAStartup failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
//
|
|
// Parse command arguments.
|
|
//
|
|
if (argc > 1) {
|
|
for (Loop = 1;Loop < argc; Loop++) {
|
|
if (((argv[Loop][0] == '-') || (argv[Loop][0] == '/')) &&
|
|
(argv[Loop][1] != 0) && (argv[Loop][2] == 0)) {
|
|
switch(tolower(argv[Loop][1])) {
|
|
case 's':
|
|
if (argv[Loop + 1]) {
|
|
if ((argv[Loop + 1][0] != '-') &&
|
|
(argv[Loop + 1][0] != '/')) {
|
|
ServiceName = argv[++Loop];
|
|
break;
|
|
}
|
|
}
|
|
Usage(argv[0]);
|
|
break;
|
|
|
|
case 'p':
|
|
Passive = TRUE;
|
|
break;
|
|
|
|
case 'c':
|
|
Canonical = TRUE;
|
|
break;
|
|
|
|
case 'v':
|
|
Verbose = TRUE;
|
|
break;
|
|
|
|
default:
|
|
Usage(argv[0]);
|
|
break;
|
|
}
|
|
} else if (!GotNodeName) {
|
|
NodeName = argv[Loop];
|
|
GotNodeName = TRUE;
|
|
} else {
|
|
Usage(argv[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prepare Hints.
|
|
//
|
|
memset(&Hints, 0, sizeof(Hints));
|
|
Hints.ai_family = PF_UNSPEC;
|
|
if (Passive) {
|
|
Hints.ai_flags = AI_PASSIVE;
|
|
}
|
|
if (Canonical) {
|
|
Hints.ai_flags |= AI_CANONNAME;
|
|
}
|
|
if (Verbose) {
|
|
printf("\nHints contains:\n");
|
|
DumpAddrInfo(&Hints);
|
|
}
|
|
|
|
//
|
|
// Make the call.
|
|
//
|
|
if (Verbose) {
|
|
printf("\nCalling getaddrinfo(\"%s\", \"%s\", &Hints, &AddrInfo)\n",
|
|
NodeName, ServiceName);
|
|
} else {
|
|
printf("\nCalling getaddrinfo for node %s", NodeName);
|
|
if (ServiceName) {
|
|
printf(" and service %s", ServiceName);
|
|
}
|
|
printf("\n");
|
|
}
|
|
ReturnValue = getaddrinfo(NodeName, ServiceName, &Hints, &AddrInfo);
|
|
printf("Returns %d (%s)\n", ReturnValue,
|
|
ReturnValue ? gai_strerror(ReturnValue) : "no error");
|
|
if (AddrInfo != NULL) {
|
|
if (Verbose) {
|
|
printf("AddrInfo contains:\n");
|
|
DumpAddrInfo(AddrInfo);
|
|
} else {
|
|
if (AddrInfo->ai_canonname) {
|
|
printf("Canonical name for %s is %s\n", NodeName,
|
|
AddrInfo->ai_canonname);
|
|
}
|
|
printf("AddrInfo contains the following records:\n");
|
|
ListAddrInfo(AddrInfo);
|
|
}
|
|
freeaddrinfo(AddrInfo);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
//* inet6_ntoa - Converts a binary IPv6 address into a string.
|
|
//
|
|
// Returns a pointer to the output string.
|
|
//
|
|
char *
|
|
inet6_ntoa(const struct in6_addr *Address)
|
|
{
|
|
static char buffer[128]; // REVIEW: Use 128 or INET6_ADDRSTRLEN?
|
|
DWORD buflen = sizeof buffer;
|
|
struct sockaddr_in6 sin6;
|
|
|
|
memset(&sin6, 0, sizeof sin6);
|
|
sin6.sin6_family = AF_INET6;
|
|
sin6.sin6_addr = *Address;
|
|
|
|
if (WSAAddressToString((struct sockaddr *) &sin6,
|
|
sizeof sin6,
|
|
NULL, // LPWSAPROTOCOL_INFO
|
|
buffer,
|
|
&buflen) == SOCKET_ERROR)
|
|
strcpy(buffer, "<invalid>");
|
|
|
|
return buffer;
|
|
}
|
|
|
|
|
|
//* DecodeAIFlags - converts flag bits to a symbolic string.
|
|
// (i.e. 0x03 returns "AI_PASSIVE | AI_CANONNAME")
|
|
//
|
|
char *
|
|
DecodeAIFlags(unsigned int Flags)
|
|
{
|
|
static char Buffer[1024];
|
|
char *Pos;
|
|
BOOL First = TRUE;
|
|
int Loop;
|
|
|
|
Pos = Buffer;
|
|
for (Loop = 0; Loop < NUMBER_FLAGS; Loop++) {
|
|
if (Flags & GAIFlagsArray[Loop].Flag) {
|
|
if (!First)
|
|
Pos += sprintf(Pos, " | ");
|
|
Pos += sprintf(Pos, GAIFlagsArray[Loop].Name);
|
|
First = FALSE;
|
|
}
|
|
}
|
|
|
|
if (First)
|
|
return "NONE";
|
|
else
|
|
return Buffer;
|
|
}
|
|
|
|
|
|
//* DecodeAIFamily - converts address family value to a symbolic string.
|
|
//
|
|
char *
|
|
DecodeAIFamily(unsigned int Family)
|
|
{
|
|
if (Family == PF_INET)
|
|
return "PF_INET";
|
|
else if (Family == PF_INET6)
|
|
return "PF_INET6";
|
|
else if (Family == PF_UNSPEC)
|
|
return "PF_UNSPEC";
|
|
else
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
|
|
//* DecodeAISocktype - converts socktype value to a symbolic string.
|
|
//
|
|
char *
|
|
DecodeAISocktype(unsigned int Socktype)
|
|
{
|
|
if (Socktype == SOCK_STREAM)
|
|
return "SOCK_STREAM";
|
|
else if (Socktype == SOCK_DGRAM)
|
|
return "SOCK_DGRAM";
|
|
else if (Socktype == SOCK_RAW)
|
|
return "SOCK_RAW";
|
|
else if (Socktype == SOCK_RDM)
|
|
return "SOCK_RDM";
|
|
else if (Socktype == SOCK_SEQPACKET)
|
|
return "SOCK_SEQPACKET";
|
|
else if (Socktype == 0)
|
|
return "UNSPECIFIED";
|
|
else
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
|
|
//* DecodeAIProtocol - converts protocol value to a symbolic string.
|
|
//
|
|
char *
|
|
DecodeAIProtocol(unsigned int Protocol)
|
|
{
|
|
if (Protocol == IPPROTO_TCP)
|
|
return "IPPROTO_TCP";
|
|
else if (Protocol == IPPROTO_UDP)
|
|
return "IPPROTO_UDP";
|
|
else if (Protocol == 0)
|
|
return "UNSPECIFIED";
|
|
else
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
|
|
//* DumpAddrInfo - print the contents of an addrinfo structure to standard out.
|
|
//
|
|
void
|
|
DumpAddrInfo(ADDRINFO *AddrInfo)
|
|
{
|
|
int Count;
|
|
|
|
if (AddrInfo == NULL) {
|
|
printf("AddrInfo = (null)\n");
|
|
return;
|
|
}
|
|
|
|
for (Count = 1; AddrInfo != NULL; AddrInfo = AddrInfo->ai_next) {
|
|
if ((Count != 1) || (AddrInfo->ai_next != NULL))
|
|
printf("Record #%u:\n", Count++);
|
|
printf(" ai_flags = %s\n", DecodeAIFlags(AddrInfo->ai_flags));
|
|
printf(" ai_family = %s\n", DecodeAIFamily(AddrInfo->ai_family));
|
|
printf(" ai_socktype = %s\n", DecodeAISocktype(AddrInfo->ai_socktype));
|
|
printf(" ai_protocol = %s\n", DecodeAIProtocol(AddrInfo->ai_protocol));
|
|
printf(" ai_addrlen = %u\n", AddrInfo->ai_addrlen);
|
|
printf(" ai_canonname = %s\n", AddrInfo->ai_canonname);
|
|
if (AddrInfo->ai_addr != NULL) {
|
|
if (AddrInfo->ai_addr->sa_family == AF_INET) {
|
|
struct sockaddr_in *sin;
|
|
|
|
sin = (struct sockaddr_in *)AddrInfo->ai_addr;
|
|
printf(" ai_addr->sin_family = AF_INET\n");
|
|
printf(" ai_addr->sin_port = %u\n", ntohs(sin->sin_port));
|
|
printf(" ai_addr->sin_addr = %s\n", inet_ntoa(sin->sin_addr));
|
|
|
|
} else if (AddrInfo->ai_addr->sa_family == AF_INET6) {
|
|
struct sockaddr_in6 *sin6;
|
|
|
|
sin6 = (struct sockaddr_in6 *)AddrInfo->ai_addr;
|
|
printf(" ai_addr->sin6_family = AF_INET6\n");
|
|
printf(" ai_addr->sin6_port = %u\n", ntohs(sin6->sin6_port));
|
|
printf(" ai_addr->sin6_flowinfo = %u\n", sin6->sin6_flowinfo);
|
|
printf(" ai_addr->sin6_scope_id = %u\n", sin6->sin6_scope_id);
|
|
printf(" ai_addr->sin6_addr = %s\n",
|
|
inet6_ntoa(&sin6->sin6_addr));
|
|
|
|
} else {
|
|
printf(" ai_addr->sa_family = %u\n",
|
|
AddrInfo->ai_addr->sa_family);
|
|
}
|
|
} else {
|
|
printf(" ai_addr = (null)\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//* ListAddrInfo - succinctly list the contents of an addrinfo structure.
|
|
//
|
|
void
|
|
ListAddrInfo(ADDRINFO *AddrInfo)
|
|
{
|
|
int ReturnValue;
|
|
char Buffer[128];
|
|
int Buflen;
|
|
|
|
if (AddrInfo == NULL) {
|
|
printf("AddrInfo = (null)\n");
|
|
return;
|
|
}
|
|
|
|
for (; AddrInfo != NULL; AddrInfo = AddrInfo->ai_next) {
|
|
Buflen = 128;
|
|
ReturnValue = WSAAddressToString(AddrInfo->ai_addr,
|
|
AddrInfo->ai_addrlen, NULL,
|
|
Buffer, &Buflen);
|
|
if (ReturnValue == SOCKET_ERROR) {
|
|
printf("<invalid>\n");
|
|
} else {
|
|
printf("%s\n", Buffer);
|
|
}
|
|
}
|
|
}
|