blob: e2b68aef9598dfc416a306803f47df90517c0fe1 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <arpa/inet.h>
#include <errno.h>
#include <getopt.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* sa_to_string(const struct sockaddr* sa, char* buf, size_t buflen) {
if (sa == NULL) {
return "<null>";
}
char addrstr[INET6_ADDRSTRLEN];
if (sa->sa_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
size_t n =
snprintf(buf, buflen, "inet4: %s (port %d)\n",
inet_ntop(AF_INET, &sin->sin_addr, addrstr, sizeof(addrstr)),
ntohs(sin->sin_port));
if (n >= buflen) {
return "<error: buffer overflow>";
}
return buf;
} else if (sa->sa_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
size_t n = snprintf(
buf, buflen, "inet6: %s (port %d)\n",
inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, sizeof(addrstr)),
ntohs(sin6->sin6_port));
if (n >= buflen) {
return "<error: buffer overflow>";
}
return buf;
}
return "<error: unknown family>";
}
void print_ai(struct addrinfo* ai) {
char sa_string_buf[256 + INET6_ADDRSTRLEN];
printf("family %d, socktype %d, flags %d, protocol %d, addrlen %d, addr %s",
ai->ai_family, ai->ai_socktype, ai->ai_flags, ai->ai_protocol,
ai->ai_addrlen,
sa_to_string(ai->ai_addr, sa_string_buf, sizeof(sa_string_buf)));
}
const char* name_to_string(const char* name) {
if (name == NULL) {
return "<null>";
} else {
return name;
}
}
const char* family_to_string(int family) {
if (family == AF_UNSPEC) {
} else if (family == AF_INET) {
return "inet4";
} else if (family == AF_INET6) {
return "inet6";
}
return "unknown";
}
const char* eai_to_string(int eai) {
switch (eai) {
case EAI_BADFLAGS:
return "EAI_BADFLAGS";
case EAI_NONAME:
return "EAI_NONAME";
case EAI_AGAIN:
return "EAI_AGAIN";
case EAI_FAIL:
return "EAI_FAIL";
case EAI_FAMILY:
return "EAI_FAMILY";
case EAI_SOCKTYPE:
return "EAI_SOCKTYPE";
case EAI_SERVICE:
return "EAI_SERVICE";
case EAI_MEMORY:
return "EAI_MEMORY";
case EAI_SYSTEM:
return "EAI_SYSTEM";
case EAI_OVERFLOW:
return "EAI_OVERFLOW";
}
return "<unknown error>";
}
int getaddrinfo_test(const char* node, const char* service, int family) {
printf("looking up node=%s service=%s family=%s...\n", name_to_string(node),
name_to_string(service), family_to_string(family));
struct addrinfo hints;
struct addrinfo *result, *rp;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
int eai;
eai = getaddrinfo(node, service, &hints, &result);
if (eai != 0) {
if (eai == EAI_SYSTEM) {
printf("getaddrinfo failed (%s, errno = %d)\n", eai_to_string(eai),
errno);
} else {
printf("getaddrinfo failed (%s)\n", eai_to_string(eai));
}
return -1;
}
int i = 0;
for (rp = result; rp != NULL; rp = rp->ai_next) {
printf("[%d] ", i++);
print_ai(rp);
}
freeaddrinfo(result);
return 0;
}
void usage() {
printf("usage: getaddrinfo_test [-n node][-s service][-f inet4 or inet6]\n");
}
int main(int argc, char** argv) {
char* node = NULL;
char* service = NULL;
int family = AF_UNSPEC;
int opt;
while ((opt = getopt(argc, argv, "n:s:f:")) != -1) {
switch (opt) {
case 'n':
node = optarg;
break;
case 's':
service = optarg;
break;
case 'f':
if (strcmp(optarg, "inet4") == 0) {
family = AF_INET;
} else if (strcmp(optarg, "inet6") == 0) {
family = AF_INET6;
} else {
usage();
return 1;
}
break;
default:
usage();
return 1;
}
}
if (getaddrinfo_test(node, service, family) < 0) {
return 1;
}
return 0;
}