Admin Panel
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
//#include <netinet/in.h>
#include <sys/types.h>
#include <netdb.h>
#include <arpa/inet.h>
#if defined(__AROS__) || defined(__MORPHOS__)
#include <proto/exec.h>
#include <proto/socket.h>
#include <errno.h>
#ifdef __MORPHOS__
#include <net/socketbasetags.h>
#endif
#define close CloseSocket
struct Library *SocketBase = NULL;
#endif
#ifdef AF_INET
#define IPv4 /* this is tested throughout the code that follows */
#endif
/* no one constant that all implementations define, sigh */
#if defined(IPV6ADDR_ANY_INIT)
#define IPv6 /* this is tested throughout the code that follows */
#elif defined(IPV6_FLOWINFO_FLOWLABEL)
#define IPv6 /* this is tested throughout the code that follows */
#endif
/*
* Test program for getaddrinfo() and getnameinfo().
*/
/* function prototypes for internal functions */
static void do_errtest(void);
static void do_funccall(const char *, const char *, int, int, int, int, int);
static int do_onetest(char *, char *, struct addrinfo *, int);
static const char *str_fam(int);
static const char *str_sock(int);
static void usage(const char *);
/* globals */
int vflag;
#if defined(__AROS__) || defined(__MORPHOS__)
void socket_cleanup(void)
{
if (SocketBase)
{
CloseLibrary(SocketBase);
SocketBase = NULL;
}
}
#endif
int
main(int argc, char **argv)
{
int doerrtest = 0;
int loopcount = 1;
int c, i;
char *host = NULL;
char hostbuf[NI_MAXHOST];
char *serv = NULL;
char servbuf[NI_MAXSERV];
struct protoent *proto;
struct addrinfo hints; /* set by command-line options */
if (argc < 2)
usage("");
#if defined(__AROS__) || defined(__MORPHOS__)
SocketBase = OpenLibrary("bsdsocket.library", 0);
if (!SocketBase)
{
printf("can't open bsdsocket.library\n");
return 1;
}
if (SocketBaseTags(
SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (IPTR)&errno,
TAG_DONE))
{
printf("SocketBaseTags failed\n");
CloseLibrary(SocketBase);
return 1;
}
atexit(socket_cleanup);
#endif
memset(&hints, 0, sizeof(struct addrinfo));
opterr = 0; /* don't want getopt() writing to stderr */
while ( (c = getopt(argc, argv, "cef:h:l:pr:s:t:v")) != -1) {
switch (c) {
case 'c':
hints.ai_flags |= AI_CANONNAME;
break;
case 'e':
doerrtest = 1;
break;
case 'f': /* address family */
#ifdef IPv4
if (strcmp(optarg, "inet") == 0) {
hints.ai_family = AF_INET;
break;
}
#endif
#ifdef IPv6
if (strcmp(optarg, "inet6") == 0) {
hints.ai_family = AF_INET6;
break;
}
#endif
#ifdef UNIXdomain
if (strcmp(optarg, "unix") == 0) {
hints.ai_family = AF_LOCAL;
break;
}
#endif
usage("invalid -f option");
case 'h': /* host */
strncpy(hostbuf, optarg, NI_MAXHOST-1);
host = hostbuf;
break;
case 'l': /* loop count */
loopcount = atoi(optarg);
break;
case 'p':
hints.ai_flags |= AI_PASSIVE;
break;
case 'r': /* protocol */
if ((proto = getprotobyname(optarg)) == NULL) {
hints.ai_protocol = atoi(optarg);
} else {
hints.ai_protocol = proto->p_proto;
}
break;
case 's':
strncpy(servbuf, optarg, NI_MAXSERV-1);
serv = servbuf;
break;
case 't': /* socket type */
if (strcmp(optarg, "stream") == 0) {
hints.ai_socktype = SOCK_STREAM;
break;
}
if (strcmp(optarg, "dgram") == 0) {
hints.ai_socktype = SOCK_DGRAM;
break;
}
if (strcmp(optarg, "raw") == 0) {
hints.ai_socktype = SOCK_RAW;
break;
}
#ifdef SOCK_RDM
if (strcmp(optarg, "rdm") == 0) {
hints.ai_socktype = SOCK_RDM;
break;
}
#endif
#ifdef SOCK_SEQPACKET
if (strcmp(optarg, "seqpacket") == 0) {
hints.ai_socktype = SOCK_SEQPACKET;
break;
}
#endif
usage("invalid -t option");
case 'v':
vflag = 1;
break;
case '?':
usage("unrecognized option");
}
}
if (optind < argc) {
usage("extra args");
}
if (doerrtest) {
do_errtest();
exit(0);
}
for (i = 1; i <= loopcount; i++) {
if (do_onetest(host, serv, &hints, i) > 0)
exit(1);
if (i % 1000 == 0) {
printf(" %d", i);
fflush(stdout);
}
}
exit(0);
}
/*
* Check that the right error codes are returned for invalid input.
* Test all the errors that are easy to test for.
*/
static void
do_errtest(void)
{
/* passive open with no hostname and no address family */
do_funccall(NULL, "ftp", AI_PASSIVE, 0, 0, 0, 0);
/* kind of hard to automatically test EAI_AGAIN ??? */
/* invalid flags */
do_funccall("localhost", NULL, 999999, 0, 0, 0, EAI_BADFLAGS);
/* how to test EAI_FAIL ??? */
/* invalid address family */
do_funccall("localhost", NULL, 0, AF_SNA, 0, 0, EAI_FAMILY);
/* hard to test for EAI_MEMORY: would have to malloc() until
failure, then give some back, then call getaddrinfo and
hope that its memory requests would not be satisfied. */
/* to test for EAI_NODATA: would have to know of a host with
no A record in the DNS */
#ifdef notdef /* following depends on resolver, sigh */
/* believe it or not, there is a registered domain "bar.com",
so the following should generate NO_DATA from the DNS */
do_funccall("foo.bar.foo.bar.foo.bar.com", NULL, 0, 0, 0, 0, EAI_NODATA);
#endif
/* no hostname, no service name */
do_funccall(NULL, NULL, 0, 0, 0, 0, EAI_NONAME);
/* invalid hostname (should be interpreted in local default domain) */
do_funccall("lkjjkhjhghgfgfd", NULL, 0, 0, 0, 0, EAI_NONAME);
/* invalid service name */
do_funccall(NULL, "nosuchservice", 0, 0, 0, 0, EAI_NONAME);
/* service valid but not supported for socket type */
do_funccall("localhost", "telnet", 0, 0, SOCK_DGRAM, 0, EAI_SERVICE);
/* service valid but not supported for socket type */
do_funccall("localhost", "tftp", 0, 0, SOCK_STREAM, 0, EAI_SERVICE);
/* invalid socket type */
do_funccall("localhost", NULL, 0, AF_INET, SOCK_SEQPACKET, 0, EAI_SOCKTYPE);
/* EAI_SYSTEM not generated by my implementation */
}
static void
do_funccall(const char *host, const char *serv,
int flags, int family, int socktype, int protocol, int exprc)
{
int rc;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_flags = flags;
hints.ai_family = family;
hints.ai_socktype = socktype;
hints.ai_protocol = protocol;
rc = getaddrinfo(host, serv, &hints, &res);
if (rc != exprc) {
printf("expected return = %d (%s),\nactual return = %d (%s)\n",
exprc, gai_strerror(exprc), rc, gai_strerror(rc));
if (host != NULL)
printf(" host = %s\n", host);
if (serv != NULL)
printf(" serv = %s\n", serv);
printf(" flags = %d, family = %s, socktype = %s, protocol = %d\n",
flags, str_fam(family), str_sock(socktype), protocol);
exit(2);
}
}
static int
do_onetest(char *host, char *serv, struct addrinfo *hints, int iteration)
{
int rc, fd, verbose;
struct addrinfo *res, *rescopy;
char rhost[NI_MAXHOST], rserv[NI_MAXSERV];
char temp[46];
verbose = vflag && (iteration == 1); /* only first time */
if (host != NULL && verbose)
printf("host = %s\n", host);
if (serv != NULL && verbose)
printf("serv = %s\n", serv);
rc = getaddrinfo(host, serv, hints, &res);
if (rc != 0) {
printf("getaddrinfo return code = %d (%s)\n", rc, gai_strerror(rc));
return(1);
}
rescopy = res;
do {
if (iteration == 1) { /* always print results first time */
printf("\nsocket(%s, %s, %d)", str_fam(res->ai_family),
str_sock(res->ai_socktype), res->ai_protocol);
/* canonname should be set only in first addrinfo{} */
if (hints->ai_flags & AI_CANONNAME) {
if (res->ai_canonname)
printf(", ai_canonname = %s", res->ai_canonname);
}
printf("\n");
printf("\taddress: %s\n",
//inet_ntop(res->ai_addr, res->ai_addrlen));
inet_ntop(res->ai_family, &(((struct sockaddr_in *)res->ai_addr)->sin_addr), temp, sizeof(temp)));
//inet_ntoa(res->ai_addr));
}
/* Call socket() to make sure return values are valid */
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (fd < 0)
printf("call to socket() failed!\n");
else
close(fd);
/*
* Call getnameinfo() to check the reverse mapping.
*/
rc = getnameinfo(res->ai_addr, res->ai_addrlen,
rhost, NI_MAXHOST, rserv, NI_MAXSERV,
(res->ai_socktype == SOCK_DGRAM) ? NI_DGRAM: 0);
if (rc == 0) {
if (verbose)
printf("\tgetnameinfo: host = %s, serv = %s\n",
rhost, rserv);
} else
printf("getnameinfo returned %d (%s)\n", rc, gai_strerror(rc));
} while ( (res = res->ai_next) != NULL);
freeaddrinfo(rescopy);
return(0);
}
static void
usage(const char *msg)
{
printf(
"usage: testaddrinfo [ options ]\n"
"options: -h <host> (can be hostname or address string)\n"
" -s <service> (can be service name or decimal port number)\n"
" -c AI_CANONICAL flag\n"
" -p AI_PASSIVE flag\n"
" -l N loop N times (check for memory leaks with ps)\n"
" -f X address family, X = inet, inet6, unix\n"
" -r X protocol, X = tcp, udp, ... or number e.g. 6, 17, ...\n"
" -t X socket type, X = stream, dgram, raw, rdm, seqpacket\n"
" -v verbose\n"
" -e only do test of error returns (no options required)\n"
" without -e, one or both of <host> and <service> must be specified.\n"
);
if (msg[0] != 0)
printf("%s\n", msg);
exit(1);
}
static const char *
str_fam(int family)
{
#ifdef IPv4
if (family == AF_INET)
return("AF_INET");
#endif
#ifdef IPv6
if (family == AF_INET6)
return("AF_INET6");
#endif
#ifdef UNIXdomain
if (family == AF_LOCAL)
return("AF_LOCAL");
#endif
return("<unknown family>");
}
static const char *
str_sock(int socktype)
{
switch(socktype) {
case SOCK_STREAM: return "SOCK_STREAM";
case SOCK_DGRAM: return "SOCK_DGRAM";
case SOCK_RAW: return "SOCK_RAW";
#ifdef SOCK_RDM
case SOCK_RDM: return "SOCK_RDM";
#endif
#ifdef SOCK_SEQPACKET
case SOCK_SEQPACKET:return "SOCK_SEQPACKET";
#endif
default: return "<unknown socktype>";
}
}