libc

/* $Id$ */
/* Copyright (c) 2013-2017 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS System libc */
/* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
/* prototypes */
static int _netdb(char const * progname);
static int _gai_strerror(char const * message, int value);
static int _getaddrinfo(char const * progname);
static int _gethostbyaddr(char const * progname, char const * addr,
size_t length, int type);
static int _gethostent(char const * progname);
static int _getnameinfo(char const * progname, in_port_t port,
char const * expected);
static int _getnetent(char const * progname);
static int _getprotoent(char const * progname);
static int _getservbyname(char const * progname, char const * name,
char const * protocol);
static int _getservbyport(char const * progname, int port,
char const * protocol);
static int _getservent(char const * progname);
static int _hstrerror(char const * message, int value);
/* functions */
/* netdb */
static int _netdb(char const * progname)
{
int ret = 0;
/* gethostbyaddr */
ret |= _gethostbyaddr(progname, "\x7f\x00\x00\x01", 4, AF_INET);
/* gethostent */
ret |= _gethostent(progname);
/* getnameinfo */
ret |= _getnameinfo(progname, 22, "ssh");
ret |= _getnameinfo(progname, 23, "telnet");
/* getnetent */
ret |= _getnetent(progname);
/* getprotoent */
ret |= _getprotoent(progname);
/* getservent */
ret |= _getservbyname(progname, "ssh", "tcp");
ret |= _getservbyport(progname, 22, "tcp");
ret |= _getservent(progname);
/* hstrerror */
ret |= _hstrerror("HOST_NOT_FOUND", HOST_NOT_FOUND);
ret |= _hstrerror("TRY_AGAIN", TRY_AGAIN);
ret |= _hstrerror("NO_RECOVERY", NO_RECOVERY);
ret |= _hstrerror("NO_DATA", NO_DATA);
/* gai_strerror */
ret |= _gai_strerror("EAI_AGAIN", EAI_AGAIN);
ret |= _gai_strerror("EAI_BADFLAGS", EAI_BADFLAGS);
ret |= _gai_strerror("EAI_FAIL", EAI_FAIL);
ret |= _gai_strerror("EAI_FAMILY", EAI_FAMILY);
ret |= _gai_strerror("EAI_MEMORY", EAI_MEMORY);
ret |= _gai_strerror("EAI_NONAME", EAI_NONAME);
ret |= _gai_strerror("EAI_OVERFLOW", EAI_OVERFLOW);
ret |= _gai_strerror("EAI_SERVICE", EAI_SERVICE);
ret |= _gai_strerror("EAI_SOCKTYPE", EAI_SOCKTYPE);
ret |= _gai_strerror("EAI_SYSTEM", EAI_SYSTEM);
/* getaddrinfo */
ret |= _getaddrinfo(progname);
return ret;
}
/* gai_strerror */
static int _gai_strerror(char const * message, int value)
{
printf("%s: %s\n", message, gai_strerror(value));
return 0;
}
/* getaddrinfo */
static int _getaddrinfo(char const * progname)
{
int ret = 0;
struct addrinfo hints;
struct addrinfo * ai;
int res;
struct addrinfo * p;
struct sockaddr_in * sin;
struct sockaddr_in6 * sin6;
char buf[32];
/* FIXME also test without hints and without AI_PASSIVE set */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_PASSIVE;
if((res = getaddrinfo("localhost", "http", &hints, &ai)) != 0)
{
fprintf(stderr, "%s: %s: %s\n", progname, "getaddrinfo",
gai_strerror(res));
return 1;
}
for(p = ai; p != NULL; p = p->ai_next)
if(p->ai_family == AF_INET)
{
sin = (struct sockaddr_in *)p->ai_addr;
/* FIXME also verify the address */
if(sin->sin_port != 80)
ret = 1;
printf("%s: %s:%u%s\n", "localhost", inet_ntoa(
sin->sin_addr),
sin->sin_port,
(ret == 0) ? "" : " (WRONG)");
}
else if(p->ai_family == AF_INET6)
{
sin6 = (struct sockaddr_in6 *)p->ai_addr;
/* FIXME also verify the address */
if(sin6->sin6_port != 80)
ret = 1;
printf("%s: %s:%u%s\n", "localhost", inet_ntop(
p->ai_family, &sin6->sin6_addr,
buf, sizeof(buf)),
sin6->sin6_port,
(ret == 0) ? "" : " (WRONG)");
}
freeaddrinfo(ai);
return ret;
}
/* gethostbyaddr */
static int _gethostbyaddr(char const * progname, char const * addr,
size_t length, int type)
{
printf("%s: Testing gethostbyaddr()\n", progname);
return (gethostbyaddr(addr, length, type) != NULL) ? 0 : 1;
}
/* gethostent */
static int _gethostent(char const * progname)
{
struct hostent * he;
unsigned int i;
char * const * p;
char const * sep;
printf("%s: Testing gethostent()\n", progname);
sethostent(1);
for(i = 0; (he = gethostent()) != NULL; i++)
{
printf("%s\t%d %d", he->h_name, he->h_addrtype, he->h_length);
if(he->h_aliases != NULL)
{
sep = "\t";
for(p = he->h_aliases; *p != NULL; p++)
{
printf("%s%s", sep, *p);
sep = ", ";
}
}
putchar('\n');
}
endhostent();
printf("%u hosts listed\n", i);
return (i > 0) ? 0 : 1;
}
/* getnameinfo */
static int _getnameinfo(char const * progname, in_port_t port,
char const * expected)
{
struct sockaddr_in sa;
char node[16];
char service[16];
const int flags = 0;
int res;
printf("%s: Testing getnameinfo(%u, \"%s\")\n", progname, port,
expected);
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sa.sin_port = port;
if((res = getnameinfo((struct sockaddr *)&sa, sizeof(sa),
node, sizeof(node),
service, sizeof(service), flags)) != 0)
{
fprintf(stderr, "%s: %s: %s\n", progname, "getnameinfo",
gai_strerror(res));
return 1;
}
if(strcmp(service, expected) != 0)
{
fprintf(stderr, "%s: %s: Wrong service (expected: %s)\n",
progname, service, expected);
return 1;
}
return 0;
}
/* getnetent */
static int _getnetent(char const * progname)
{
struct netent * ne;
unsigned int i;
char * const * p;
char const * sep;
printf("%s: Testing getnetent()\n", progname);
setnetent(1);
for(i = 0; (ne = getnetent()) != NULL; i++)
{
printf("%s\t%d %u", ne->n_name, ne->n_addrtype, ne->n_net);
if(ne->n_aliases != NULL)
{
sep = "\t";
for(p = ne->n_aliases; *p != NULL; p++)
{
printf("%s%s", sep, *p);
sep = ", ";
}
}
putchar('\n');
}
endnetent();
printf("%u networks listed\n", i);
return 0;
}
/* getprotoent */
static int _getprotoent(char const * progname)
{
struct protoent * pe;
unsigned int i;
char * const * p;
char const * sep;
printf("%s: Testing getprotoent()\n", progname);
setprotoent(1);
for(i = 0; (pe = getprotoent()) != NULL; i++)
{
printf("%s\t%d", pe->p_name, pe->p_proto);
if(pe->p_aliases != NULL)
{
sep = "\t";
for(p = pe->p_aliases; *p != NULL; p++)
{
printf("%s%s", sep, *p);
sep = ", ";
}
}
putchar('\n');
}
endprotoent();
printf("%u protocols listed\n", i);
return 0;
}
/* getservbyname */
static int _getservbyname(char const * progname, char const * name,
char const * protocol)
{
struct servent * se;
printf("%s: Testing getservbyname(): %s/%s\n", progname, name,
protocol);
if((se = getservbyname(name, protocol)) == NULL)
return 0;
printf("%s\t%d/%s\n", se->s_name, se->s_port, se->s_proto);
return 0;
}
/* getservbyport */
static int _getservbyport(char const * progname, int port,
char const * protocol)
{
struct servent * se;
printf("%s: Testing getservbyport(): %d/%s\n", progname, port,
protocol);
if((se = getservbyport(port, protocol)) == NULL)
return 0;
printf("%s\t%d/%s\n", se->s_name, se->s_port, se->s_proto);
return 0;
}
/* getservent */
static int _getservent(char const * progname)
{
struct servent * se;
unsigned int i;
char * const * p;
printf("%s: Testing getservent()\n", progname);
setservent(1);
for(i = 0; (se = getservent()) != NULL; i++)
{
printf("%s\t%d/%s", se->s_name, se->s_port, se->s_proto);
if(se->s_aliases != NULL)
for(p = se->s_aliases; *p != NULL; p++)
printf(" %s", *p);
putchar('\n');
}
endservent();
printf("%u services listed\n", i);
return 0;
}
/* hstrerror */
static int _hstrerror(char const * message, int value)
{
printf("%s: %s\n", message, hstrerror(value));
return 0;
}
/* main */
int main(int argc, char * argv[])
{
int ret = 0;
(void) argc;
ret |= _netdb(argv[0]);
return (ret == 0) ? 0 : 2;
}