diff options
Diffstat (limited to 'src/util/inet_addr_list.c')
-rw-r--r-- | src/util/inet_addr_list.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/util/inet_addr_list.c b/src/util/inet_addr_list.c new file mode 100644 index 0000000..e579b17 --- /dev/null +++ b/src/util/inet_addr_list.c @@ -0,0 +1,186 @@ +/*++ +/* 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 |