~ubuntu-branches/debian/squeeze/ntp/squeeze-201010051545

« back to all changes in this revision

Viewing changes to ports/winnt/libntp/interfaceiter.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2004-10-11 16:10:27 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20041011161027-icyjbji8ujym633o
Tags: 1:4.2.0a-10ubuntu2
Use ntp.ubuntulinux.org instead of pool.ntp.org

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1999-2001  Internet Software Consortium.
 
3
 *
 
4
 * Permission to use, copy, modify, and distribute this software for any
 
5
 * purpose with or without fee is hereby granted, provided that the above
 
6
 * copyright notice and this permission notice appear in all copies.
 
7
 *
 
8
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
 
9
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 
10
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 
11
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
 
12
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 
13
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
14
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 
15
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
16
 */
 
17
 
 
18
/* $Id: interfaceiter.c,v 1.7 2001/11/27 01:56:21 gson Exp $ */
 
19
 
 
20
/*
 
21
 * Note that this code will need to be revisited to support IPv6 Interfaces.
 
22
 * For now we just iterate through IPv4 interfaces.
 
23
 */
 
24
 
 
25
#include <config.h>
 
26
#include <winsock2.h>
 
27
#include <ws2tcpip.h>
 
28
#include <sys/types.h>
 
29
 
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <errno.h>
 
33
 
 
34
#include <isc/interfaceiter.h>
 
35
#include <isc/mem.h>
 
36
#include <isc/result.h>
 
37
#include <isc/string.h>
 
38
#include <isc/strerror.h>
 
39
#include <isc/types.h>
 
40
#include <isc/util.h>
 
41
 
 
42
/* Common utility functions */
 
43
 
 
44
/*
 
45
 * Extract the network address part from a "struct sockaddr".
 
46
 *
 
47
 * The address family is given explicity
 
48
 * instead of using src->sa_family, because the latter does not work
 
49
 * for copying a network mask obtained by SIOCGIFNETMASK (it does
 
50
 * not have a valid address family).
 
51
 */
 
52
 
 
53
 
 
54
#define IFITER_MAGIC            0x49464954U     /* IFIT. */
 
55
#define VALID_IFITER(t)         ((t) != NULL && (t)->magic == IFITER_MAGIC)
 
56
 
 
57
struct isc_interfaceiter {
 
58
        unsigned int            magic;          /* Magic number. */
 
59
        isc_mem_t               *mctx;
 
60
        int                     socket;
 
61
        INTERFACE_INFO          IFData;         /* Current Interface Info */
 
62
        int                     numIF;          /* Current Interface count */
 
63
        int                     totalIF;        /* Total Number
 
64
                                                   of Interfaces */
 
65
        INTERFACE_INFO          *buf;           /* Buffer for WSAIoctl data. */
 
66
        unsigned int            bufsize;        /* Bytes allocated. */
 
67
        INTERFACE_INFO          *pos;           /* Current offset in IF List */
 
68
        isc_interface_t         current;        /* Current interface data. */
 
69
        isc_result_t            result;         /* Last result code. */
 
70
};
 
71
 
 
72
 
 
73
/*
 
74
 * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
 
75
 * We assume no sane system will have more than than 1K of IP addresses on
 
76
 * all of its adapters.
 
77
 */
 
78
#define IFCONF_SIZE_INITIAL       16
 
79
#define IFCONF_SIZE_INCREMENT     64
 
80
#define IFCONF_SIZE_MAX         1040
 
81
 
 
82
static void
 
83
get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
 
84
        dst->family = family;
 
85
        switch (family) {
 
86
        case AF_INET:
 
87
                memcpy(&dst->type.in,
 
88
                       &((struct sockaddr_in *) src)->sin_addr,
 
89
                       sizeof(struct in_addr));
 
90
                break;
 
91
        case    AF_INET6:
 
92
                memcpy(&dst->type.in6,
 
93
                       &((struct sockaddr_in6 *) src)->sin6_addr,
 
94
                       sizeof(struct in6_addr));
 
95
                break;
 
96
        default:
 
97
                INSIST(0);
 
98
                break;
 
99
        }
 
100
}
 
101
 
 
102
isc_result_t
 
103
isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
 
104
        char strbuf[ISC_STRERRORSIZE]; 
 
105
        isc_interfaceiter_t *iter;
 
106
        isc_result_t result;
 
107
        int error;
 
108
        unsigned long bytesReturned = 0;
 
109
 
 
110
        REQUIRE(mctx != NULL);
 
111
        REQUIRE(iterp != NULL);
 
112
        REQUIRE(*iterp == NULL);
 
113
 
 
114
        iter = isc_mem_get(mctx, sizeof(*iter));
 
115
        if (iter == NULL)
 
116
                return (ISC_R_NOMEMORY);
 
117
 
 
118
        iter->mctx = mctx;
 
119
        iter->buf = NULL;
 
120
 
 
121
        /*
 
122
         * Create an unbound datagram socket to do the
 
123
         * SIO_GET_INTERFACE_LIST WSAIoctl on.
 
124
         */
 
125
        if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 
126
                error = WSAGetLastError();
 
127
                isc__strerror(error, strbuf, sizeof(strbuf));
 
128
                UNEXPECTED_ERROR(__FILE__, __LINE__,
 
129
                                "making interface scan socket: %s",
 
130
                                strbuf);
 
131
                result = ISC_R_UNEXPECTED;
 
132
                goto socket_failure;
 
133
        }
 
134
 
 
135
        /*
 
136
         * Get the interface configuration, allocating more memory if
 
137
         * necessary.
 
138
         */
 
139
        iter->bufsize = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
 
140
 
 
141
        for (;;) {
 
142
                iter->buf = isc_mem_get(mctx, iter->bufsize);
 
143
                if (iter->buf == NULL) {
 
144
                        result = ISC_R_NOMEMORY;
 
145
                        goto alloc_failure;
 
146
                }
 
147
 
 
148
                if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
 
149
                             0, 0, iter->buf, iter->bufsize,
 
150
                             &bytesReturned, 0, 0) == SOCKET_ERROR)
 
151
                {
 
152
                        error = WSAGetLastError();
 
153
                        if (error != WSAEFAULT && error != WSAENOBUFS) {
 
154
                                errno = error;
 
155
                                isc__strerror(error, strbuf, sizeof(strbuf));
 
156
                                UNEXPECTED_ERROR(__FILE__, __LINE__,
 
157
                                                "get interface configuration: %s",
 
158
                                                strbuf);
 
159
                                result = ISC_R_UNEXPECTED;
 
160
                                goto ioctl_failure;
 
161
                        }
 
162
                        /*
 
163
                         * EINVAL.  Retry with a bigger buffer.
 
164
                         */
 
165
                } else {
 
166
                        /*
 
167
                         * The WSAIoctl succeeded.
 
168
                         * If the number of the returned bytes is the same
 
169
                         * as the buffer size, we will grow it just in
 
170
                         * case and retry.
 
171
                         */
 
172
                        if (bytesReturned > 0 &&
 
173
                            (bytesReturned < iter->bufsize))
 
174
                                break;
 
175
                }
 
176
                if (iter->bufsize >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
 
177
                        UNEXPECTED_ERROR(__FILE__, __LINE__,
 
178
                                         "get interface configuration: "
 
179
                                         "maximum buffer size exceeded");
 
180
                        result = ISC_R_UNEXPECTED;
 
181
                        goto ioctl_failure;
 
182
                }
 
183
                isc_mem_put(mctx, iter->buf, iter->bufsize);
 
184
 
 
185
                iter->bufsize += IFCONF_SIZE_INCREMENT *
 
186
                        sizeof(INTERFACE_INFO);
 
187
        }
 
188
 
 
189
        /*
 
190
         * A newly created iterator has an undefined position
 
191
         * until isc_interfaceiter_first() is called.
 
192
         */
 
193
        iter->pos = NULL;
 
194
        iter->result = ISC_R_FAILURE;
 
195
        iter->numIF = 0;
 
196
        iter->totalIF = bytesReturned/sizeof(INTERFACE_INFO);
 
197
 
 
198
 
 
199
        iter->magic = IFITER_MAGIC;
 
200
        *iterp = iter;
 
201
        /* We don't need the socket any more, so close it */
 
202
        closesocket(iter->socket);
 
203
        return (ISC_R_SUCCESS);
 
204
 
 
205
 ioctl_failure:
 
206
        isc_mem_put(mctx, iter->buf, iter->bufsize);
 
207
 
 
208
 alloc_failure:
 
209
        (void) closesocket(iter->socket);
 
210
 
 
211
 socket_failure:
 
212
        isc_mem_put(mctx, iter, sizeof(*iter));
 
213
        return (result);
 
214
}
 
215
 
 
216
/*
 
217
 * Get information about the current interface to iter->current.
 
218
 * If successful, return ISC_R_SUCCESS.
 
219
 * If the interface has an unsupported address family, or if
 
220
 * some operation on it fails, return ISC_R_IGNORE to make
 
221
 * the higher-level iterator code ignore it.
 
222
 */
 
223
 
 
224
static isc_result_t
 
225
internal_current(isc_interfaceiter_t *iter, int family) {
 
226
        BOOL ifNamed = FALSE;
 
227
        unsigned long flags;
 
228
 
 
229
        REQUIRE(VALID_IFITER(iter));
 
230
        REQUIRE(iter->numIF >= 0);
 
231
 
 
232
        memset(&iter->current, 0, sizeof(iter->current));
 
233
        iter->current.af = family;
 
234
 
 
235
        get_addr(family, &iter->current.address,
 
236
                 (struct sockaddr *)&(iter->IFData.iiAddress));
 
237
 
 
238
        /*
 
239
         * Get interface flags.
 
240
         */
 
241
 
 
242
        iter->current.flags = 0;
 
243
        flags = iter->IFData.iiFlags;
 
244
 
 
245
        if ((flags & IFF_UP) != 0)
 
246
                iter->current.flags |= INTERFACE_F_UP;
 
247
 
 
248
        if ((flags & IFF_POINTTOPOINT) != 0) {
 
249
                iter->current.flags |= INTERFACE_F_POINTTOPOINT;
 
250
                sprintf(iter->current.name, "PPP Interface %d", iter->numIF);
 
251
                ifNamed = TRUE;
 
252
        }
 
253
 
 
254
        if ((flags & IFF_LOOPBACK) != 0) {
 
255
                iter->current.flags |= INTERFACE_F_LOOPBACK;
 
256
                sprintf(iter->current.name, "Loopback Interface %d",
 
257
                        iter->numIF);
 
258
                ifNamed = TRUE;
 
259
        }
 
260
 
 
261
        /*
 
262
         * If the interface is point-to-point, get the destination address.
 
263
         */
 
264
        if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
 
265
                get_addr(family, &iter->current.dstaddress,
 
266
                (struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
 
267
        }
 
268
 
 
269
        if (ifNamed == FALSE)
 
270
                sprintf(iter->current.name,
 
271
                        "TCP/IP Interface %d", iter->numIF);
 
272
 
 
273
        /*
 
274
         * Get the network mask.
 
275
         */
 
276
        switch (family) {
 
277
        case AF_INET:
 
278
                get_addr(family, &iter->current.netmask,
 
279
                         (struct sockaddr *)&(iter->IFData.iiNetmask));
 
280
                break;
 
281
        case AF_INET6:
 
282
                break;
 
283
        }
 
284
 
 
285
        return (ISC_R_SUCCESS);
 
286
}
 
287
 
 
288
/*
 
289
 * Step the iterator to the next interface.  Unlike
 
290
 * isc_interfaceiter_next(), this may leave the iterator
 
291
 * positioned on an interface that will ultimately
 
292
 * be ignored.  Return ISC_R_NOMORE if there are no more
 
293
 * interfaces, otherwise ISC_R_SUCCESS.
 
294
 */
 
295
static isc_result_t
 
296
internal_next(isc_interfaceiter_t *iter) {
 
297
        if (iter->numIF >= iter->totalIF)
 
298
                return (ISC_R_NOMORE);
 
299
 
 
300
        /*
 
301
         * The first one needs to be set up to point to the last
 
302
         * Element of the array.  Go to the end and back up
 
303
         * Microsoft's implementation is peculiar for returning
 
304
         * the list in reverse order
 
305
         */
 
306
         
 
307
        if (iter->numIF == 0)
 
308
                iter->pos = (INTERFACE_INFO *)(iter->buf + (iter->totalIF));
 
309
 
 
310
        iter->pos--;
 
311
        if (&(iter->pos) < &(iter->buf))
 
312
                return (ISC_R_NOMORE);
 
313
 
 
314
        memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
 
315
        memcpy(&(iter->IFData), iter->pos, sizeof(INTERFACE_INFO));
 
316
        iter->numIF++;
 
317
 
 
318
        return (ISC_R_SUCCESS);
 
319
}
 
320
 
 
321
isc_result_t
 
322
isc_interfaceiter_current(isc_interfaceiter_t *iter,
 
323
                          isc_interface_t *ifdata) {
 
324
        REQUIRE(iter->result == ISC_R_SUCCESS);
 
325
        memcpy(ifdata, &iter->current, sizeof(*ifdata));
 
326
        return (ISC_R_SUCCESS);
 
327
}
 
328
 
 
329
isc_result_t
 
330
isc_interfaceiter_first(isc_interfaceiter_t *iter) {
 
331
        isc_result_t result;
 
332
 
 
333
        REQUIRE(VALID_IFITER(iter));
 
334
 
 
335
        iter->numIF = 0;
 
336
        for (;;) {
 
337
                result = internal_next(iter);
 
338
                if (result != ISC_R_SUCCESS)
 
339
                        break;
 
340
                result = internal_current(iter, AF_INET);
 
341
                if (result != ISC_R_IGNORE)
 
342
                        break;
 
343
        }
 
344
        iter->result = result;
 
345
        return (result);
 
346
}
 
347
 
 
348
isc_result_t
 
349
isc_interfaceiter_next(isc_interfaceiter_t *iter) {
 
350
        isc_result_t result;
 
351
 
 
352
        REQUIRE(VALID_IFITER(iter));
 
353
        REQUIRE(iter->result == ISC_R_SUCCESS);
 
354
 
 
355
        for (;;) {
 
356
                result = internal_next(iter);
 
357
                if (result != ISC_R_SUCCESS)
 
358
                        break;
 
359
                result = internal_current(iter,AF_INET);
 
360
                if (result != ISC_R_IGNORE)
 
361
                        break;
 
362
        }
 
363
        iter->result = result;
 
364
        return (result);
 
365
}
 
366
 
 
367
void
 
368
isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
 
369
        isc_interfaceiter_t *iter;
 
370
        REQUIRE(iterp != NULL);
 
371
        iter = *iterp;
 
372
        REQUIRE(VALID_IFITER(iter));
 
373
 
 
374
        isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
 
375
 
 
376
        iter->magic = 0;
 
377
        isc_mem_put(iter->mctx, iter, sizeof(*iter));
 
378
        *iterp = NULL;
 
379
}
 
380