inet_addr_list.c revision 1.2
1/*	$NetBSD: inet_addr_list.c,v 1.2 2017/02/14 01:16:49 christos Exp $	*/
2
3/*++
4/* NAME
5/*	inet_addr_list 3
6/* SUMMARY
7/*	internet address list manager
8/* SYNOPSIS
9/*	#include <inet_addr_list.h>
10/*
11/*	void	inet_addr_list_init(list)
12/*	INET_ADDR_LIST *list;
13/*
14/*	void	inet_addr_list_append(list,addr)
15/*	INET_ADDR_LIST *list;
16/*	struct sockaddr *addr;
17/*
18/*	void	inet_addr_list_uniq(list)
19/*	INET_ADDR_LIST *list;
20/*
21/*	void	inet_addr_list_free(list)
22/*	INET_ADDR_LIST *list;
23/* DESCRIPTION
24/*	This module maintains simple lists of internet addresses.
25/*
26/*	inet_addr_list_init() initializes a user-provided structure
27/*	so that it can be used by inet_addr_list_append() and by
28/*	inet_addr_list_free().
29/*
30/*	inet_addr_list_append() appends the specified address to
31/*	the specified list, extending the list on the fly.
32/*
33/*	inet_addr_list_uniq() sorts the specified address list and
34/*	eliminates duplicates.
35/*
36/*	inet_addr_list_free() reclaims memory used for the
37/*	specified address list.
38/* LICENSE
39/* .ad
40/* .fi
41/*	The Secure Mailer license must be distributed with this software.
42/* AUTHOR(S)
43/*	Wietse Venema
44/*	IBM T.J. Watson Research
45/*	P.O. Box 704
46/*	Yorktown Heights, NY 10598, USA
47/*--*/
48
49/* System library. */
50
51#include <sys_defs.h>
52#include <sys/socket.h>
53#include <netinet/in.h>
54#include <arpa/inet.h>
55#include <stdlib.h>
56#include <netdb.h>
57
58/* Utility library. */
59
60#include <msg.h>
61#include <mymalloc.h>
62#include <myaddrinfo.h>
63#include <sock_addr.h>
64#include <inet_addr_list.h>
65
66/* inet_addr_list_init - initialize internet address list */
67
68void    inet_addr_list_init(INET_ADDR_LIST *list)
69{
70    int     init_size;
71
72    list->used = 0;
73    list->size = 0;
74    init_size = 2;
75    list->addrs = (struct sockaddr_storage *)
76	mymalloc(sizeof(*list->addrs) * init_size);
77    list->size = init_size;
78}
79
80/* inet_addr_list_append - append address to internet address list */
81
82void    inet_addr_list_append(INET_ADDR_LIST *list,
83			              struct sockaddr *addr)
84{
85    const char *myname = "inet_addr_list_append";
86    MAI_HOSTADDR_STR hostaddr;
87    int     new_size;
88
89    if (msg_verbose > 1) {
90	SOCKADDR_TO_HOSTADDR(addr, SOCK_ADDR_LEN(addr),
91			     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
92	msg_info("%s: %s", myname, hostaddr.buf);
93    }
94    if (list->used >= list->size) {
95	new_size = list->size * 2;
96	list->addrs = (struct sockaddr_storage *)
97	    myrealloc((void *) list->addrs, sizeof(*list->addrs) * new_size);
98	list->size = new_size;
99    }
100    memcpy(list->addrs + list->used++, addr, SOCK_ADDR_LEN(addr));
101}
102
103/* inet_addr_list_comp - compare addresses */
104
105static int inet_addr_list_comp(const void *a, const void *b)
106{
107
108    /*
109     * In case (struct *) != (void *).
110     */
111    return (sock_addr_cmp_addr(SOCK_ADDR_PTR(a), SOCK_ADDR_PTR(b)));
112}
113
114/* inet_addr_list_uniq - weed out duplicates */
115
116void    inet_addr_list_uniq(INET_ADDR_LIST *list)
117{
118    int     n;
119    int     m;
120
121    /*
122     * Put the identical members right next to each other.
123     */
124    qsort((void *) list->addrs, list->used,
125	  sizeof(list->addrs[0]), inet_addr_list_comp);
126
127    /*
128     * Nuke the duplicates. Postcondition after while loop: m is the largest
129     * index for which list->addrs[n] == list->addrs[m].
130     */
131    for (m = n = 0; m < list->used; m++, n++) {
132	if (m != n)
133	    list->addrs[n] = list->addrs[m];
134	while (m + 1 < list->used
135	       && inet_addr_list_comp((void *) &(list->addrs[n]),
136				      (void *) &(list->addrs[m + 1])) == 0)
137	    m += 1;
138    }
139    list->used = n;
140}
141
142/* inet_addr_list_free - destroy internet address list */
143
144void    inet_addr_list_free(INET_ADDR_LIST *list)
145{
146    myfree((void *) list->addrs);
147}
148
149#ifdef TEST
150#include <inet_proto.h>
151
152 /*
153  * Duplicate elimination needs to be tested.
154  */
155#include <inet_addr_host.h>
156
157static void inet_addr_list_print(INET_ADDR_LIST *list)
158{
159    MAI_HOSTADDR_STR hostaddr;
160    struct sockaddr_storage *sa;
161
162    for (sa = list->addrs; sa < list->addrs + list->used; sa++) {
163	SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
164			     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
165	msg_info("%s", hostaddr.buf);
166    }
167}
168
169int     main(int argc, char **argv)
170{
171    INET_ADDR_LIST list;
172    INET_PROTO_INFO *proto_info;
173
174    proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
175    inet_addr_list_init(&list);
176    while (--argc && *++argv)
177	if (inet_addr_host(&list, *argv) == 0)
178	    msg_fatal("host not found: %s", *argv);
179    msg_info("list before sort/uniq");
180    inet_addr_list_print(&list);
181    inet_addr_list_uniq(&list);
182    msg_info("list after sort/uniq");
183    inet_addr_list_print(&list);
184    inet_addr_list_free(&list);
185    return (0);
186}
187
188#endif
189