~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjlib/src/pj/ip_helper_generic.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: ip_helper_generic.c 4355 2013-02-19 16:27:37Z bennylp $ */
2
 
/* 
3
 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
 
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19
 
 */
20
 
#include <pj/ip_helper.h>
21
 
#include <pj/addr_resolv.h>
22
 
#include <pj/assert.h>
23
 
#include <pj/errno.h>
24
 
#include <pj/string.h>
25
 
#include <pj/compat/socket.h>
26
 
#include <pj/sock.h>
27
 
 
28
 
/* Set to 1 to enable tracing */
29
 
#if 0
30
 
#   include <pj/log.h>
31
 
#   define THIS_FILE    "ip_helper_generic.c"
32
 
#   define TRACE_(exp)  PJ_LOG(5,exp)
33
 
    static const char *get_os_errmsg(void)
34
 
    {
35
 
        static char errmsg[PJ_ERR_MSG_SIZE];
36
 
        pj_strerror(pj_get_os_error(), errmsg, sizeof(errmsg));
37
 
        return errmsg;
38
 
    }
39
 
    static const char *get_addr(void *addr)
40
 
    {
41
 
        static char txt[PJ_INET6_ADDRSTRLEN];
42
 
        struct sockaddr *ad = (struct sockaddr*)addr;
43
 
        if (ad->sa_family != PJ_AF_INET && ad->sa_family != PJ_AF_INET6)
44
 
            return "?";
45
 
        return pj_inet_ntop2(ad->sa_family, pj_sockaddr_get_addr(ad), 
46
 
                             txt, sizeof(txt));
47
 
    }
48
 
#else
49
 
#   define TRACE_(exp)
50
 
#endif
51
 
 
52
 
 
53
 
#if 0
54
 
    /* dummy */
55
 
 
56
 
#elif defined(PJ_HAS_IFADDRS_H) && PJ_HAS_IFADDRS_H != 0 && \
57
 
      defined(PJ_HAS_NET_IF_H) && PJ_HAS_NET_IF_H != 0
58
 
/* Using getifaddrs() is preferred since it can work with both IPv4 and IPv6 */
59
 
static pj_status_t if_enum_by_af(int af,
60
 
                                 unsigned *p_cnt,
61
 
                                 pj_sockaddr ifs[])
62
 
{
63
 
    struct ifaddrs *ifap = NULL, *it;
64
 
    unsigned max;
65
 
 
66
 
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
67
 
    
68
 
    TRACE_((THIS_FILE, "Starting interface enum with getifaddrs() for af=%d",
69
 
            af));
70
 
 
71
 
    if (getifaddrs(&ifap) != 0) {
72
 
        TRACE_((THIS_FILE, " getifarrds() failed: %s", get_os_errmsg()));
73
 
        return PJ_RETURN_OS_ERROR(pj_get_netos_error());
74
 
    }
75
 
 
76
 
    it = ifap;
77
 
    max = *p_cnt;
78
 
    *p_cnt = 0;
79
 
    for (; it!=NULL && *p_cnt < max; it = it->ifa_next) {
80
 
        struct sockaddr *ad = it->ifa_addr;
81
 
 
82
 
        TRACE_((THIS_FILE, " checking %s", it->ifa_name));
83
 
 
84
 
        if ((it->ifa_flags & IFF_UP)==0) {
85
 
            TRACE_((THIS_FILE, "  interface is down"));
86
 
            continue; /* Skip when interface is down */
87
 
        }
88
 
 
89
 
#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
90
 
        if (it->ifa_flags & IFF_LOOPBACK) {
91
 
            TRACE_((THIS_FILE, "  loopback interface"));
92
 
            continue; /* Skip loopback interface */
93
 
        }
94
 
#endif
95
 
 
96
 
        if (ad==NULL) {
97
 
            TRACE_((THIS_FILE, "  NULL address ignored"));
98
 
            continue; /* reported to happen on Linux 2.6.25.9 
99
 
                         with ppp interface */
100
 
        }
101
 
 
102
 
        if (ad->sa_family != af) {
103
 
            TRACE_((THIS_FILE, "  address %s ignored (af=%d)", 
104
 
                    get_addr(ad), ad->sa_family));
105
 
            continue; /* Skip when interface is down */
106
 
        }
107
 
 
108
 
        /* Ignore 0.0.0.0/8 address. This is a special address
109
 
         * which doesn't seem to have practical use.
110
 
         */
111
 
        if (af==pj_AF_INET() &&
112
 
            (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 24) == 0)
113
 
        {
114
 
            TRACE_((THIS_FILE, "  address %s ignored (0.0.0.0/8 class)", 
115
 
                    get_addr(ad), ad->sa_family));
116
 
            continue;
117
 
        }
118
 
 
119
 
        TRACE_((THIS_FILE, "  address %s (af=%d) added at index %d", 
120
 
                get_addr(ad), ad->sa_family, *p_cnt));
121
 
 
122
 
        pj_bzero(&ifs[*p_cnt], sizeof(ifs[0]));
123
 
        pj_memcpy(&ifs[*p_cnt], ad, pj_sockaddr_get_len(ad));
124
 
        PJ_SOCKADDR_RESET_LEN(&ifs[*p_cnt]);
125
 
        (*p_cnt)++;
126
 
    }
127
 
 
128
 
    freeifaddrs(ifap);
129
 
    TRACE_((THIS_FILE, "done, found %d address(es)", *p_cnt));
130
 
    return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
131
 
}
132
 
 
133
 
#elif defined(SIOCGIFCONF) && \
134
 
      defined(PJ_HAS_NET_IF_H) && PJ_HAS_NET_IF_H != 0
135
 
 
136
 
/* Note: this does not work with IPv6 */
137
 
static pj_status_t if_enum_by_af(int af,
138
 
                                 unsigned *p_cnt,
139
 
                                 pj_sockaddr ifs[])
140
 
{
141
 
    pj_sock_t sock;
142
 
    char buf[512];
143
 
    struct ifconf ifc;
144
 
    struct ifreq *ifr;
145
 
    int i, count;
146
 
    pj_status_t status;
147
 
 
148
 
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
149
 
    
150
 
    TRACE_((THIS_FILE, "Starting interface enum with SIOCGIFCONF for af=%d",
151
 
            af));
152
 
 
153
 
    status = pj_sock_socket(af, PJ_SOCK_DGRAM, 0, &sock);
154
 
    if (status != PJ_SUCCESS)
155
 
        return status;
156
 
 
157
 
    /* Query available interfaces */
158
 
    ifc.ifc_len = sizeof(buf);
159
 
    ifc.ifc_buf = buf;
160
 
 
161
 
    if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
162
 
        int oserr = pj_get_netos_error();
163
 
        TRACE_((THIS_FILE, " ioctl(SIOCGIFCONF) failed: %s", get_os_errmsg()));
164
 
        pj_sock_close(sock);
165
 
        return PJ_RETURN_OS_ERROR(oserr);
166
 
    }
167
 
 
168
 
    /* Interface interfaces */
169
 
    ifr = (struct ifreq*) ifc.ifc_req;
170
 
    count = ifc.ifc_len / sizeof(struct ifreq);
171
 
    if (count > *p_cnt)
172
 
        count = *p_cnt;
173
 
 
174
 
    *p_cnt = 0;
175
 
    for (i=0; i<count; ++i) {
176
 
        struct ifreq *itf = &ifr[i];
177
 
        struct ifreq iff = *itf;
178
 
        struct sockaddr *ad = &itf->ifr_addr;
179
 
        
180
 
        TRACE_((THIS_FILE, " checking interface %s", itf->ifr_name));
181
 
 
182
 
        /* Skip address with different family */
183
 
        if (ad->sa_family != af) {
184
 
            TRACE_((THIS_FILE, "  address %s (af=%d) ignored",
185
 
                    get_addr(ad), (int)ad->sa_family));
186
 
            continue;
187
 
        }
188
 
 
189
 
        if (ioctl(sock, SIOCGIFFLAGS, &iff) != 0) {
190
 
            TRACE_((THIS_FILE, "  ioctl(SIOCGIFFLAGS) failed: %s",
191
 
                    get_os_errmsg()));
192
 
            continue;   /* Failed to get flags, continue */
193
 
        }
194
 
 
195
 
        if ((iff.ifr_flags & IFF_UP)==0) {
196
 
            TRACE_((THIS_FILE, "  interface is down"));
197
 
            continue; /* Skip when interface is down */
198
 
        }
199
 
 
200
 
#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
201
 
        if (iff.ifr_flags & IFF_LOOPBACK) {
202
 
            TRACE_((THIS_FILE, "  loopback interface"));
203
 
            continue; /* Skip loopback interface */
204
 
        }
205
 
#endif
206
 
 
207
 
        /* Ignore 0.0.0.0/8 address. This is a special address
208
 
         * which doesn't seem to have practical use.
209
 
         */
210
 
        if (af==pj_AF_INET() &&
211
 
            (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 24) == 0)
212
 
        {
213
 
            TRACE_((THIS_FILE, "  address %s ignored (0.0.0.0/8 class)", 
214
 
                    get_addr(ad), ad->sa_family));
215
 
            continue;
216
 
        }
217
 
 
218
 
        TRACE_((THIS_FILE, "  address %s (af=%d) added at index %d", 
219
 
                get_addr(ad), ad->sa_family, *p_cnt));
220
 
 
221
 
        pj_bzero(&ifs[*p_cnt], sizeof(ifs[0]));
222
 
        pj_memcpy(&ifs[*p_cnt], ad, pj_sockaddr_get_len(ad));
223
 
        PJ_SOCKADDR_RESET_LEN(&ifs[*p_cnt]);
224
 
        (*p_cnt)++;
225
 
    }
226
 
 
227
 
    /* Done with socket */
228
 
    pj_sock_close(sock);
229
 
 
230
 
    TRACE_((THIS_FILE, "done, found %d address(es)", *p_cnt));
231
 
    return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
232
 
}
233
 
 
234
 
 
235
 
#elif defined(PJ_HAS_NET_IF_H) && PJ_HAS_NET_IF_H != 0
236
 
/* Note: this does not work with IPv6 */
237
 
static pj_status_t if_enum_by_af(int af, unsigned *p_cnt, pj_sockaddr ifs[])
238
 
{
239
 
    struct if_nameindex *if_list;
240
 
    struct ifreq ifreq;
241
 
    pj_sock_t sock;
242
 
    unsigned i, max_count;
243
 
    pj_status_t status;
244
 
 
245
 
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
246
 
 
247
 
    TRACE_((THIS_FILE, "Starting if_nameindex() for af=%d", af));
248
 
 
249
 
    status = pj_sock_socket(af, PJ_SOCK_DGRAM, 0, &sock);
250
 
    if (status != PJ_SUCCESS)
251
 
        return status;
252
 
 
253
 
    if_list = if_nameindex();
254
 
    if (if_list == NULL)
255
 
        return PJ_ENOTFOUND;
256
 
 
257
 
    max_count = *p_cnt;
258
 
    *p_cnt = 0;
259
 
    for (i=0; if_list[i].if_index && *p_cnt<max_count; ++i) {
260
 
        struct sockaddr *ad;
261
 
        int rc;
262
 
 
263
 
        strncpy(ifreq.ifr_name, if_list[i].if_name, IFNAMSIZ);
264
 
 
265
 
        TRACE_((THIS_FILE, " checking interface %s", ifreq.ifr_name));
266
 
 
267
 
        if ((rc=ioctl(sock, SIOCGIFFLAGS, &ifreq)) != 0) {
268
 
            TRACE_((THIS_FILE, "  ioctl(SIOCGIFFLAGS) failed: %s",
269
 
                    get_os_errmsg()));
270
 
            continue;   /* Failed to get flags, continue */
271
 
        }
272
 
 
273
 
        if ((ifreq.ifr_flags & IFF_UP)==0) {
274
 
            TRACE_((THIS_FILE, "  interface is down"));
275
 
            continue; /* Skip when interface is down */
276
 
        }
277
 
 
278
 
#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
279
 
        if (ifreq.ifr_flags & IFF_LOOPBACK) {
280
 
            TRACE_((THIS_FILE, "  loopback interface"));
281
 
            continue; /* Skip loopback interface */
282
 
        }
283
 
#endif
284
 
 
285
 
        /* Note: SIOCGIFADDR does not work for IPv6! */
286
 
        if ((rc=ioctl(sock, SIOCGIFADDR, &ifreq)) != 0) {
287
 
            TRACE_((THIS_FILE, "  ioctl(SIOCGIFADDR) failed: %s",
288
 
                    get_os_errmsg()));
289
 
            continue;   /* Failed to get address, continue */
290
 
        }
291
 
 
292
 
        ad = (struct sockaddr*) &ifreq.ifr_addr;
293
 
 
294
 
        if (ad->sa_family != af) {
295
 
            TRACE_((THIS_FILE, "  address %s family %d ignored", 
296
 
                               get_addr(&ifreq.ifr_addr),
297
 
                               ifreq.ifr_addr.sa_family));
298
 
            continue;   /* Not address family that we want, continue */
299
 
        }
300
 
 
301
 
        /* Ignore 0.0.0.0/8 address. This is a special address
302
 
         * which doesn't seem to have practical use.
303
 
         */
304
 
        if (af==pj_AF_INET() &&
305
 
            (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 24) == 0)
306
 
        {
307
 
            TRACE_((THIS_FILE, "  address %s ignored (0.0.0.0/8 class)", 
308
 
                    get_addr(ad), ad->sa_family));
309
 
            continue;
310
 
        }
311
 
 
312
 
        /* Got an address ! */
313
 
        TRACE_((THIS_FILE, "  address %s (af=%d) added at index %d", 
314
 
                get_addr(ad), ad->sa_family, *p_cnt));
315
 
 
316
 
        pj_bzero(&ifs[*p_cnt], sizeof(ifs[0]));
317
 
        pj_memcpy(&ifs[*p_cnt], ad, pj_sockaddr_get_len(ad));
318
 
        PJ_SOCKADDR_RESET_LEN(&ifs[*p_cnt]);
319
 
        (*p_cnt)++;
320
 
    }
321
 
 
322
 
    if_freenameindex(if_list);
323
 
    pj_sock_close(sock);
324
 
 
325
 
    TRACE_((THIS_FILE, "done, found %d address(es)", *p_cnt));
326
 
    return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
327
 
}
328
 
 
329
 
#else
330
 
static pj_status_t if_enum_by_af(int af,
331
 
                                 unsigned *p_cnt,
332
 
                                 pj_sockaddr ifs[])
333
 
{
334
 
    pj_status_t status;
335
 
 
336
 
    PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && ifs, PJ_EINVAL);
337
 
 
338
 
    pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt));
339
 
 
340
 
    /* Just get one default route */
341
 
    status = pj_getdefaultipinterface(af, &ifs[0]);
342
 
    if (status != PJ_SUCCESS)
343
 
        return status;
344
 
 
345
 
    *p_cnt = 1;
346
 
    return PJ_SUCCESS;
347
 
}
348
 
#endif /* SIOCGIFCONF */
349
 
 
350
 
/*
351
 
 * Enumerate the local IP interface currently active in the host.
352
 
 */
353
 
PJ_DEF(pj_status_t) pj_enum_ip_interface(int af,
354
 
                                         unsigned *p_cnt,
355
 
                                         pj_sockaddr ifs[])
356
 
{
357
 
    unsigned start;
358
 
    pj_status_t status;
359
 
 
360
 
    start = 0;
361
 
    if (af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) {
362
 
        unsigned max = *p_cnt;
363
 
        status = if_enum_by_af(PJ_AF_INET6, &max, &ifs[start]);
364
 
        if (status == PJ_SUCCESS) {
365
 
            start += max;
366
 
            (*p_cnt) -= max;
367
 
        }
368
 
    }
369
 
 
370
 
    if (af==PJ_AF_INET || af==PJ_AF_UNSPEC) {
371
 
        unsigned max = *p_cnt;
372
 
        status = if_enum_by_af(PJ_AF_INET, &max, &ifs[start]);
373
 
        if (status == PJ_SUCCESS) {
374
 
            start += max;
375
 
            (*p_cnt) -= max;
376
 
        }
377
 
    }
378
 
 
379
 
    *p_cnt = start;
380
 
 
381
 
    return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
382
 
}
383
 
 
384
 
/*
385
 
 * Enumerate the IP routing table for this host.
386
 
 */
387
 
PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt,
388
 
                                     pj_ip_route_entry routes[])
389
 
{
390
 
    pj_sockaddr itf;
391
 
    pj_status_t status;
392
 
 
393
 
    PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && routes, PJ_EINVAL);
394
 
 
395
 
    pj_bzero(routes, sizeof(routes[0]) * (*p_cnt));
396
 
 
397
 
    /* Just get one default route */
398
 
    status = pj_getdefaultipinterface(PJ_AF_INET, &itf);
399
 
    if (status != PJ_SUCCESS)
400
 
        return status;
401
 
    
402
 
    routes[0].ipv4.if_addr.s_addr = itf.ipv4.sin_addr.s_addr;
403
 
    routes[0].ipv4.dst_addr.s_addr = 0;
404
 
    routes[0].ipv4.mask.s_addr = 0;
405
 
    *p_cnt = 1;
406
 
 
407
 
    return PJ_SUCCESS;
408
 
}
409