/* $NetBSD: inet_addr_list.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */
/*++
/* NAME
/* inet_addr_list 3
/* SUMMARY
/* internet address list manager
/* SYNOPSIS
/* #include <inet_addr_list.h>
/*
/* void inet_addr_list_init(list)
/* INET_ADDR_LIST *list;
/*
/* void inet_addr_list_append(list,addr)
/* INET_ADDR_LIST *list;
/* struct sockaddr *addr;
/*
/* void inet_addr_list_uniq(list)
/* INET_ADDR_LIST *list;
/*
/* void inet_addr_list_free(list)
/* INET_ADDR_LIST *list;
/* DESCRIPTION
/* This module maintains simple lists of internet addresses.
/*
/* inet_addr_list_init() initializes a user-provided structure
/* so that it can be used by inet_addr_list_append() and by
/* inet_addr_list_free().
/*
/* inet_addr_list_append() appends the specified address to
/* the specified list, extending the list on the fly.
/*
/* inet_addr_list_uniq() sorts the specified address list and
/* eliminates duplicates.
/*
/* inet_addr_list_free() reclaims memory used for the
/* specified address list.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netdb.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <myaddrinfo.h>
#include <sock_addr.h>
#include <inet_addr_list.h>
/* inet_addr_list_init - initialize internet address list */
void inet_addr_list_init(INET_ADDR_LIST *list)
{
int init_size;
list->used = 0;
list->size = 0;
init_size = 2;
list->addrs = (struct sockaddr_storage *)
mymalloc(sizeof(*list->addrs) * init_size);
list->size = init_size;
}
/* inet_addr_list_append - append address to internet address list */
void inet_addr_list_append(INET_ADDR_LIST *list,
struct sockaddr *addr)
{
const char *myname = "inet_addr_list_append";
MAI_HOSTADDR_STR hostaddr;
int new_size;
if (msg_verbose > 1) {
SOCKADDR_TO_HOSTADDR(addr, SOCK_ADDR_LEN(addr),
&hostaddr, (MAI_SERVPORT_STR *) 0, 0);
msg_info("%s: %s", myname, hostaddr.buf);
}
if (list->used >= list->size) {
new_size = list->size * 2;
list->addrs = (struct sockaddr_storage *)
myrealloc((void *) list->addrs, sizeof(*list->addrs) * new_size);
list->size = new_size;
}
memcpy(list->addrs + list->used++, addr, SOCK_ADDR_LEN(addr));
}
/* inet_addr_list_comp - compare addresses */
static int inet_addr_list_comp(const void *a, const void *b)
{
/*
* In case (struct *) != (void *).
*/
return (sock_addr_cmp_addr(SOCK_ADDR_PTR(a), SOCK_ADDR_PTR(b)));
}
/* inet_addr_list_uniq - weed out duplicates */
void inet_addr_list_uniq(INET_ADDR_LIST *list)
{
int n;
int m;
/*
* Put the identical members right next to each other.
*/
qsort((void *) list->addrs, list->used,
sizeof(list->addrs[0]), inet_addr_list_comp);
/*
* Nuke the duplicates. Postcondition after while loop: m is the largest
* index for which list->addrs[n] == list->addrs[m].
*/
for (m = n = 0; m < list->used; m++, n++) {
if (m != n)
list->addrs[n] = list->addrs[m];
while (m + 1 < list->used
&& inet_addr_list_comp((void *) &(list->addrs[n]),
(void *) &(list->addrs[m + 1])) == 0)
m += 1;
}
list->used = n;
}
/* inet_addr_list_free - destroy internet address list */
void inet_addr_list_free(INET_ADDR_LIST *list)
{
myfree((void *) list->addrs);
}
#ifdef TEST
#include <inet_proto.h>
/*
* Duplicate elimination needs to be tested.
*/
#include <inet_addr_host.h>
static void inet_addr_list_print(INET_ADDR_LIST *list)
{
MAI_HOSTADDR_STR hostaddr;
struct sockaddr_storage *sa;
for (sa = list->addrs; sa < list->addrs + list->used; sa++) {
SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
&hostaddr, (MAI_SERVPORT_STR *) 0, 0);
msg_info("%s", hostaddr.buf);
}
}
int main(int argc, char **argv)
{
INET_ADDR_LIST list;
INET_PROTO_INFO *proto_info;
proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
inet_addr_list_init(&list);
while (--argc && *++argv)
if (inet_addr_host(&list, *argv) == 0)
msg_fatal("host not found: %s", *argv);
msg_info("list before sort/uniq");
inet_addr_list_print(&list);
inet_addr_list_uniq(&list);
msg_info("list after sort/uniq");
inet_addr_list_print(&list);
inet_addr_list_free(&list);
return (0);
}
#endif