~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): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

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