Coverage Report

Created: 2025-07-04 06:19

/src/pjsip/pjlib/src/pj/sock_common.c
Line
Count
Source (jump to first uncovered line)
1
/* 
2
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
3
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
18
 */
19
#include <pj/sock.h>
20
#include <pj/assert.h>
21
#include <pj/ctype.h>
22
#include <pj/errno.h>
23
#include <pj/ip_helper.h>
24
#include <pj/os.h>
25
#include <pj/pool.h>
26
#include <pj/addr_resolv.h>
27
#include <pj/rand.h>
28
#include <pj/string.h>
29
#include <pj/compat/socket.h>
30
31
#if 0
32
    /* Enable some tracing */
33
    #include <pj/log.h>
34
    #define THIS_FILE   "sock_common.c"
35
    #define TRACE_(arg) PJ_LOG(4,arg)
36
#else
37
    #define TRACE_(arg)
38
#endif
39
40
41
/*
42
 * Convert address string with numbers and dots to binary IP address.
43
 */ 
44
PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
45
0
{
46
0
    pj_in_addr addr;
47
48
0
    pj_inet_aton(cp, &addr);
49
0
    return addr;
50
0
}
51
52
/*
53
 * Convert address string with numbers and dots to binary IP address.
54
 */ 
55
PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
56
0
{
57
0
    pj_str_t str = pj_str((char*)cp);
58
0
    return pj_inet_addr(&str);
59
0
}
60
61
/*
62
 * Get text representation.
63
 */
64
PJ_DEF(char*) pj_inet_ntop2( int af, const void *src,
65
                             char *dst, int size)
66
0
{
67
0
    pj_status_t status;
68
69
0
    status = pj_inet_ntop(af, src, dst, size);
70
0
    return (status==PJ_SUCCESS)? dst : NULL;
71
0
}
72
73
/*
74
 * Print socket address.
75
 */
76
PJ_DEF(char*) pj_sockaddr_print( const pj_sockaddr_t *addr,
77
                                 char *buf, int size,
78
                                 unsigned flags)
79
0
{
80
0
    enum {
81
0
        WITH_PORT = 1,
82
0
        WITH_BRACKETS = 2
83
0
    };
84
85
0
    char txt[PJ_INET6_ADDRSTRLEN];
86
0
    char port[32];
87
0
    const pj_addr_hdr *h = (const pj_addr_hdr*)addr;
88
0
    char *bquote, *equote;
89
0
    pj_status_t status;
90
91
0
    status = pj_inet_ntop(h->sa_family, pj_sockaddr_get_addr(addr),
92
0
                          txt, sizeof(txt));
93
0
    if (status != PJ_SUCCESS)
94
0
        return "";
95
96
0
    if (h->sa_family != PJ_AF_INET6 || (flags & WITH_BRACKETS)==0) {
97
0
        bquote = ""; equote = "";
98
0
    } else {
99
0
        bquote = "["; equote = "]";
100
0
    }
101
102
0
    if (flags & WITH_PORT) {
103
0
        pj_ansi_snprintf(port, sizeof(port), ":%d",
104
0
                         pj_sockaddr_get_port(addr));
105
0
    } else {
106
0
        port[0] = '\0';
107
0
    }
108
109
0
    pj_ansi_snprintf(buf, size, "%s%s%s%s",
110
0
                     bquote, txt, equote, port);
111
112
0
    return buf;
113
0
}
114
115
/*
116
 * Set the IP address of an IP socket address from string address, 
117
 * with resolving the host if necessary. The string address may be in a
118
 * standard numbers and dots notation or may be a hostname. If hostname
119
 * is specified, then the function will resolve the host into the IP
120
 * address.
121
 */
122
PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
123
                                                 const pj_str_t *str_addr)
124
99
{
125
99
    PJ_CHECK_STACK();
126
127
99
    PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME, 
128
99
                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
129
130
99
    PJ_SOCKADDR_RESET_LEN(addr);
131
99
    addr->sin_family = PJ_AF_INET;
132
99
    pj_bzero(addr->sin_zero_pad, sizeof(addr->sin_zero_pad));
133
134
99
    if (str_addr && str_addr->slen) {
135
0
        addr->sin_addr = pj_inet_addr(str_addr);
136
0
        if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
137
0
            pj_addrinfo ai;
138
0
            unsigned count = 1;
139
0
            pj_status_t status;
140
141
0
            status = pj_getaddrinfo(pj_AF_INET(), str_addr, &count, &ai);
142
0
            if (status==PJ_SUCCESS) {
143
0
                pj_memcpy(&addr->sin_addr, &ai.ai_addr.ipv4.sin_addr,
144
0
                          sizeof(addr->sin_addr));
145
0
            } else {
146
0
                return status;
147
0
            }
148
0
        }
149
150
99
    } else {
151
99
        addr->sin_addr.s_addr = 0;
152
99
    }
153
154
99
    return PJ_SUCCESS;
155
99
}
156
157
/* Set address from a name */
158
PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af,
159
                                             pj_sockaddr *addr,
160
                                             const pj_str_t *str_addr)
161
88
{
162
88
    pj_status_t status;
163
164
88
    if (af == PJ_AF_INET) {
165
0
        return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr);
166
0
    }
167
168
88
    PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
169
170
    /* IPv6 specific */
171
172
88
    addr->ipv6.sin6_family = PJ_AF_INET6;
173
88
    PJ_SOCKADDR_RESET_LEN(addr);
174
175
88
    if (str_addr && str_addr->slen) {
176
#if defined(PJ_SOCKADDR_USE_GETADDRINFO) && PJ_SOCKADDR_USE_GETADDRINFO!=0
177
        if (1) {
178
#else
179
0
        status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr);
180
0
        if (status != PJ_SUCCESS) {
181
0
#endif
182
0
            pj_addrinfo ai;
183
0
            unsigned count = 1;
184
185
0
            status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai);
186
0
            if (status==PJ_SUCCESS) {
187
0
                pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr,
188
0
                          sizeof(addr->ipv6.sin6_addr));
189
0
                addr->ipv6.sin6_scope_id = ai.ai_addr.ipv6.sin6_scope_id;
190
0
            }
191
0
        }
192
88
    } else {
193
88
        status = PJ_SUCCESS;
194
88
    }
195
196
88
    return status;
197
88
}
198
199
/*
200
 * Set the IP address and port of an IP socket address.
201
 * The string address may be in a standard numbers and dots notation or 
202
 * may be a hostname. If hostname is specified, then the function will 
203
 * resolve the host into the IP address.
204
 */
205
PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
206
                                         const pj_str_t *str_addr,
207
                                         pj_uint16_t port)
208
99
{
209
99
    PJ_ASSERT_RETURN(addr, PJ_EINVAL);
210
211
99
    PJ_SOCKADDR_RESET_LEN(addr);
212
99
    addr->sin_family = PJ_AF_INET;
213
99
    pj_bzero(addr->sin_zero_pad, sizeof(addr->sin_zero_pad));
214
99
    pj_sockaddr_in_set_port(addr, port);
215
99
    return pj_sockaddr_in_set_str_addr(addr, str_addr);
216
99
}
217
218
/*
219
 * Initialize IP socket address based on the address and port info.
220
 */
221
PJ_DEF(pj_status_t) pj_sockaddr_init(int af, 
222
                                     pj_sockaddr *addr,
223
                                     const pj_str_t *cp,
224
                                     pj_uint16_t port)
225
187
{
226
187
    pj_status_t status;
227
228
187
    if (af == PJ_AF_INET) {
229
99
        return pj_sockaddr_in_init(&addr->ipv4, cp, port);
230
99
    }
231
232
    /* IPv6 specific */
233
88
    PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP);
234
235
88
    pj_bzero(addr, sizeof(pj_sockaddr_in6));
236
88
    addr->addr.sa_family = PJ_AF_INET6;
237
    
238
88
    status = pj_sockaddr_set_str_addr(af, addr, cp);
239
88
    if (status != PJ_SUCCESS)
240
0
        return status;
241
242
88
    addr->ipv6.sin6_port = pj_htons(port);
243
88
    return PJ_SUCCESS;
244
88
}
245
246
/*
247
 * Compare two socket addresses.
248
 */
249
PJ_DEF(int) pj_sockaddr_cmp( const pj_sockaddr_t *addr1,
250
                             const pj_sockaddr_t *addr2)
251
0
{
252
0
    const pj_sockaddr *a1 = (const pj_sockaddr*) addr1;
253
0
    const pj_sockaddr *a2 = (const pj_sockaddr*) addr2;
254
0
    int port1, port2;
255
0
    int result;
256
257
    /* Compare address family */
258
0
    if (a1->addr.sa_family < a2->addr.sa_family)
259
0
        return -1;
260
0
    else if (a1->addr.sa_family > a2->addr.sa_family)
261
0
        return 1;
262
263
    /* Compare addresses */
264
0
    result = pj_memcmp(pj_sockaddr_get_addr(a1),
265
0
                       pj_sockaddr_get_addr(a2),
266
0
                       pj_sockaddr_get_addr_len(a1));
267
0
    if (result != 0)
268
0
        return result;
269
270
    /* Compare port number */
271
0
    port1 = pj_sockaddr_get_port(a1);
272
0
    port2 = pj_sockaddr_get_port(a2);
273
274
0
    if (port1 < port2)
275
0
        return -1;
276
0
    else if (port1 > port2)
277
0
        return 1;
278
279
    /* TODO:
280
     *  Do we need to compare flow label and scope id in IPv6? 
281
     */
282
    
283
    /* Looks equal */
284
0
    return 0;
285
0
}
286
287
/*
288
 * Get first IP address associated with the hostname.
289
 */
290
PJ_DEF(pj_in_addr) pj_gethostaddr(void)
291
0
{
292
0
    pj_sockaddr_in addr;
293
0
    const pj_str_t *hostname = pj_gethostname();
294
295
0
    pj_sockaddr_in_set_str_addr(&addr, hostname);
296
0
    return addr.sin_addr;
297
0
}
298
299
/*
300
 * Get port number of a pj_sockaddr_in
301
 */
302
PJ_DEF(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
303
0
{
304
0
    return pj_ntohs(addr->sin_port);
305
0
}
306
307
/*
308
 * Get the address part
309
 */
310
PJ_DEF(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr)
311
187
{
312
187
    const pj_sockaddr *a = (const pj_sockaddr*)addr;
313
314
187
    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
315
187
                     a->addr.sa_family == PJ_AF_INET6, NULL);
316
317
187
    if (a->addr.sa_family == PJ_AF_INET6)
318
88
        return (void*) &a->ipv6.sin6_addr;
319
99
    else
320
99
        return (void*) &a->ipv4.sin_addr;
321
187
}
322
323
/*
324
 * Check if sockaddr contains a non-zero address
325
 */
326
PJ_DEF(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr)
327
0
{
328
0
    const pj_sockaddr *a = (const pj_sockaddr*)addr;
329
330
    /* It's probably not wise to raise assertion here if
331
     * the address doesn't contain a valid address family, and
332
     * just return PJ_FALSE instead.
333
     * 
334
     * The reason is because application may need to distinguish 
335
     * these three conditions with sockaddr:
336
     *  a) sockaddr is not initialized. This is by convention
337
     *     indicated by sa_family==0.
338
     *  b) sockaddr is initialized with zero address. This is
339
     *     indicated with the address field having zero address.
340
     *  c) sockaddr is initialized with valid address/port.
341
     *
342
     * If we enable this assertion, then application will loose
343
     * the capability to specify condition a), since it will be
344
     * forced to always initialize sockaddr (even with zero address).
345
     * This may break some parts of upper layer libraries.
346
     */
347
    //PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
348
    //               a->addr.sa_family == PJ_AF_INET6, PJ_FALSE);
349
350
0
    if (a->addr.sa_family!=PJ_AF_INET && a->addr.sa_family!=PJ_AF_INET6) {
351
0
        return PJ_FALSE;
352
0
    } else if (a->addr.sa_family == PJ_AF_INET6) {
353
0
        pj_uint8_t zero[24];
354
0
        pj_bzero(zero, sizeof(zero));
355
0
        return pj_memcmp(a->ipv6.sin6_addr.s6_addr, zero, 
356
0
                         sizeof(pj_in6_addr)) != 0;
357
0
    } else
358
0
        return a->ipv4.sin_addr.s_addr != PJ_INADDR_ANY;
359
0
}
360
361
/*
362
 * Get port number
363
 */
364
PJ_DEF(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr)
365
0
{
366
0
    const pj_sockaddr *a = (const pj_sockaddr*) addr;
367
368
0
    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
369
0
                     a->addr.sa_family == PJ_AF_INET6, (pj_uint16_t)0xFFFF);
370
371
0
    return pj_ntohs((pj_uint16_t)(a->addr.sa_family == PJ_AF_INET6 ?
372
0
                                    a->ipv6.sin6_port : a->ipv4.sin_port));
373
0
}
374
375
/*
376
 * Get the length of the address part.
377
 */
378
PJ_DEF(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr)
379
0
{
380
0
    const pj_sockaddr *a = (const pj_sockaddr*) addr;
381
0
    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
382
0
                     a->addr.sa_family == PJ_AF_INET6, 0);
383
0
    return a->addr.sa_family == PJ_AF_INET6 ?
384
0
            sizeof(pj_in6_addr) : sizeof(pj_in_addr);
385
0
}
386
387
/*
388
 * Get socket address length.
389
 */
390
PJ_DEF(unsigned) pj_sockaddr_get_len(const pj_sockaddr_t *addr)
391
0
{
392
0
    const pj_sockaddr *a = (const pj_sockaddr*) addr;
393
0
    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET ||
394
0
                     a->addr.sa_family == PJ_AF_INET6, 0);
395
0
    return a->addr.sa_family == PJ_AF_INET6 ?
396
0
            sizeof(pj_sockaddr_in6) : sizeof(pj_sockaddr_in);
397
0
}
398
399
/*
400
 * Copy only the address part (sin_addr/sin6_addr) of a socket address.
401
 */
402
PJ_DEF(void) pj_sockaddr_copy_addr( pj_sockaddr *dst,
403
                                    const pj_sockaddr *src)
404
0
{
405
    /* Destination sockaddr might not be initialized */
406
0
    const char *srcbuf = (char*)pj_sockaddr_get_addr(src);
407
0
    char *dstbuf = ((char*)dst) + (srcbuf - (char*)src);
408
0
    pj_memcpy(dstbuf, srcbuf, pj_sockaddr_get_addr_len(src));
409
0
}
410
411
/*
412
 * Copy socket address.
413
 */
414
PJ_DEF(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src)
415
0
{
416
0
    pj_memcpy(dst, src, pj_sockaddr_get_len(src));
417
0
}
418
419
/*
420
 * Synthesize address.
421
 */
422
PJ_DEF(pj_status_t) pj_sockaddr_synthesize(int dst_af,
423
                                           pj_sockaddr_t *dst,
424
                                           const pj_sockaddr_t *src)
425
0
{
426
0
    char ip_addr_buf[PJ_INET6_ADDRSTRLEN];
427
0
    unsigned int count = 1;
428
0
    pj_addrinfo ai[1];
429
0
    pj_str_t ip_addr;
430
0
    pj_status_t status;
431
432
    /* Validate arguments */
433
0
    PJ_ASSERT_RETURN(src && dst, PJ_EINVAL);
434
435
0
    if (dst_af == ((const pj_sockaddr *)src)->addr.sa_family) {
436
0
        pj_sockaddr_cp(dst, src);
437
0
        return PJ_SUCCESS;
438
0
    }
439
440
0
    pj_sockaddr_print(src, ip_addr_buf, sizeof(ip_addr_buf), 0);
441
0
    ip_addr = pj_str(ip_addr_buf);
442
    
443
    /* Try to synthesize address using pj_getaddrinfo(). */
444
0
    status = pj_getaddrinfo(dst_af, &ip_addr, &count, ai); 
445
0
    if (status == PJ_SUCCESS && count > 0) {
446
0
        pj_sockaddr_cp(dst, &ai[0].ai_addr);
447
0
        pj_sockaddr_set_port(dst, pj_sockaddr_get_port(src));
448
0
    }
449
    
450
0
    return status;
451
0
}
452
453
/*
454
 * Set port number of pj_sockaddr_in
455
 */
456
PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 
457
                                     pj_uint16_t hostport)
458
99
{
459
99
    addr->sin_port = pj_htons(hostport);
460
99
}
461
462
/*
463
 * Set port number of pj_sockaddr
464
 */
465
PJ_DEF(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr, 
466
                                         pj_uint16_t hostport)
467
187
{
468
187
    int af = addr->addr.sa_family;
469
470
187
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
471
472
187
    if (af == PJ_AF_INET6)
473
88
        addr->ipv6.sin6_port = pj_htons(hostport);
474
99
    else
475
99
        addr->ipv4.sin_port = pj_htons(hostport);
476
477
187
    return PJ_SUCCESS;
478
187
}
479
480
/*
481
 * Get IPv4 address
482
 */
483
PJ_DEF(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)
484
0
{
485
0
    pj_in_addr in_addr;
486
0
    in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);
487
0
    return in_addr;
488
0
}
489
490
/*
491
 * Set IPv4 address
492
 */
493
PJ_DEF(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
494
                                     pj_uint32_t hostaddr)
495
0
{
496
0
    addr->sin_addr.s_addr = pj_htonl(hostaddr);
497
0
}
498
499
/*
500
 * Parse address
501
 */
502
PJ_DEF(pj_status_t) pj_sockaddr_parse2(int af, unsigned options,
503
                                       const pj_str_t *str,
504
                                       pj_str_t *p_hostpart,
505
                                       pj_uint16_t *p_port,
506
                                       int *raf)
507
0
{
508
0
    const char *end = str->ptr + str->slen;
509
0
    const char *last_colon_pos = NULL;
510
0
    unsigned colon_cnt = 0;
511
0
    const char *p;
512
513
0
    PJ_ASSERT_RETURN((af==PJ_AF_INET || af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) &&
514
0
                     options==0 &&
515
0
                     str!=NULL, PJ_EINVAL);
516
517
    /* Special handling for empty input */
518
0
    if (str->slen==0 || str->ptr==NULL) {
519
0
        if (p_hostpart)
520
0
            p_hostpart->slen = 0;
521
0
        if (p_port)
522
0
            *p_port = 0;
523
0
        if (raf)
524
0
            *raf = PJ_AF_INET;
525
0
        return PJ_SUCCESS;
526
0
    }
527
528
    /* Count the colon and get the last colon */
529
0
    for (p=str->ptr; p!=end; ++p) {
530
0
        if (*p == ':') {
531
0
            ++colon_cnt;
532
0
            last_colon_pos = p;
533
0
        }
534
0
    }
535
536
    /* Deduce address family if it's not given */
537
0
    if (af == PJ_AF_UNSPEC) {
538
0
        if (colon_cnt > 1)
539
0
            af = PJ_AF_INET6;
540
0
        else
541
0
            af = PJ_AF_INET;
542
0
    } else if (af == PJ_AF_INET && colon_cnt > 1)
543
0
        return PJ_EINVAL;
544
545
0
    if (raf)
546
0
        *raf = af;
547
548
0
    if (af == PJ_AF_INET) {
549
        /* Parse as IPv4. Supported formats:
550
         *  - "10.0.0.1:80"
551
         *  - "10.0.0.1"
552
         *  - "10.0.0.1:"
553
         *  - ":80"
554
         *  - ":"
555
         */
556
0
        pj_str_t hostpart;
557
0
        unsigned long port;
558
559
0
        hostpart.ptr = (char*)str->ptr;
560
561
0
        if (last_colon_pos) {
562
0
            pj_str_t port_part;
563
0
            int i;
564
565
0
            hostpart.slen = last_colon_pos - str->ptr;
566
567
0
            port_part.ptr = (char*)last_colon_pos + 1;
568
0
            port_part.slen = end - port_part.ptr;
569
570
            /* Make sure port number is valid */
571
0
            for (i=0; i<port_part.slen; ++i) {
572
0
                if (!pj_isdigit(port_part.ptr[i]))
573
0
                    return PJ_EINVAL;
574
0
            }
575
0
            port = pj_strtoul(&port_part);
576
0
            if (port > 65535)
577
0
                return PJ_EINVAL;
578
0
        } else {
579
0
            hostpart.slen = str->slen;
580
0
            port = 0;
581
0
        }
582
583
0
        if (p_hostpart)
584
0
            *p_hostpart = hostpart;
585
0
        if (p_port)
586
0
            *p_port = (pj_uint16_t)port;
587
588
0
        return PJ_SUCCESS;
589
590
0
    } else if (af == PJ_AF_INET6) {
591
592
        /* Parse as IPv6. Supported formats:
593
         *  - "fe::01:80"  ==> note: port number is zero in this case, not 80!
594
         *  - "[fe::01]:80"
595
         *  - "fe::01"
596
         *  - "fe::01:"
597
         *  - "[fe::01]"
598
         *  - "[fe::01]:"
599
         *  - "[::]:80"
600
         *  - ":::80"
601
         *  - "[::]"
602
         *  - "[::]:"
603
         *  - ":::"
604
         *  - "::"
605
         */
606
0
        pj_str_t hostpart, port_part;
607
608
0
        if (*str->ptr == '[') {
609
0
            char *end_bracket;
610
0
            int i;
611
0
            unsigned long port;
612
613
0
            if (last_colon_pos == NULL)
614
0
                return PJ_EINVAL;
615
616
0
            end_bracket = pj_strchr(str, ']');
617
0
            if (end_bracket == NULL)
618
0
                return PJ_EINVAL;
619
620
0
            hostpart.ptr = (char*)str->ptr + 1;
621
0
            hostpart.slen = end_bracket - hostpart.ptr;
622
623
0
            if (last_colon_pos < end_bracket) {
624
0
                port_part.ptr = NULL;
625
0
                port_part.slen = 0;
626
0
            } else {
627
0
                port_part.ptr = (char*)last_colon_pos + 1;
628
0
                port_part.slen = end - port_part.ptr;
629
0
            }
630
631
            /* Make sure port number is valid */
632
0
            for (i=0; i<port_part.slen; ++i) {
633
0
                if (!pj_isdigit(port_part.ptr[i]))
634
0
                    return PJ_EINVAL;
635
0
            }
636
0
            port = pj_strtoul(&port_part);
637
0
            if (port > 65535)
638
0
                return PJ_EINVAL;
639
640
0
            if (p_hostpart)
641
0
                *p_hostpart = hostpart;
642
0
            if (p_port)
643
0
                *p_port = (pj_uint16_t)port;
644
645
0
            return PJ_SUCCESS;
646
647
0
        } else {
648
            /* Treat everything as part of the IPv6 IP address */
649
0
            if (p_hostpart)
650
0
                *p_hostpart = *str;
651
0
            if (p_port)
652
0
                *p_port = 0;
653
654
0
            return PJ_SUCCESS;
655
0
        }
656
657
0
    } else {
658
0
        return PJ_EAFNOTSUP;
659
0
    }
660
661
0
}
662
663
/*
664
 * Parse address
665
 */
666
PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options,
667
                                       const pj_str_t *str,
668
                                       pj_sockaddr *addr)
669
0
{
670
0
    pj_str_t hostpart;
671
0
    pj_uint16_t port;
672
0
    pj_status_t status;
673
674
0
    PJ_ASSERT_RETURN(addr, PJ_EINVAL);
675
0
    PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC ||
676
0
                     af==PJ_AF_INET ||
677
0
                     af==PJ_AF_INET6, PJ_EINVAL);
678
0
    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
679
680
0
    status = pj_sockaddr_parse2(af, options, str, &hostpart, &port, &af);
681
0
    if (status != PJ_SUCCESS)
682
0
        return status;
683
    
684
0
#if !defined(PJ_HAS_IPV6) || !PJ_HAS_IPV6
685
0
    if (af==PJ_AF_INET6)
686
0
        return PJ_EIPV6NOTSUP;
687
0
#endif
688
689
0
    status = pj_sockaddr_init(af, addr, &hostpart, port);
690
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
691
    if (status != PJ_SUCCESS && af == PJ_AF_INET6) {
692
        /* Parsing does not yield valid address. Try to treat the last 
693
         * portion after the colon as port number.
694
         */
695
        const char *last_colon_pos=NULL, *p;
696
        const char *end = str->ptr + str->slen;
697
        unsigned long long_port;
698
        pj_str_t port_part;
699
        int i;
700
701
        /* Parse as IPv6:port */
702
        for (p=str->ptr; p!=end; ++p) {
703
            if (*p == ':')
704
                last_colon_pos = p;
705
        }
706
707
        if (last_colon_pos == NULL)
708
            return status;
709
710
        hostpart.ptr = (char*)str->ptr;
711
        hostpart.slen = last_colon_pos - str->ptr;
712
713
        port_part.ptr = (char*)last_colon_pos + 1;
714
        port_part.slen = end - port_part.ptr;
715
716
        /* Make sure port number is valid */
717
        for (i=0; i<port_part.slen; ++i) {
718
            if (!pj_isdigit(port_part.ptr[i]))
719
                return status;
720
        }
721
        long_port = pj_strtoul(&port_part);
722
        if (long_port > 65535)
723
            return status;
724
725
        port = (pj_uint16_t)long_port;
726
727
        status = pj_sockaddr_init(PJ_AF_INET6, addr, &hostpart, port);
728
    }
729
#endif
730
    
731
0
    return status;
732
0
}
733
734
735
/* Resolve the IP address of local machine */
736
PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
737
0
{
738
0
    unsigned i, count, cand_cnt;
739
0
    enum {
740
0
        CAND_CNT = 8,
741
742
        /* Weighting to be applied to found addresses */
743
0
        WEIGHT_HOSTNAME = 1,    /* hostname IP is not always valid! */
744
0
        WEIGHT_DEF_ROUTE = 2,
745
0
        WEIGHT_INTERFACE = 1,
746
0
        WEIGHT_LOOPBACK = -5,
747
0
        WEIGHT_LINK_LOCAL = -4,
748
0
        WEIGHT_DISABLED = -50,
749
750
0
        MIN_WEIGHT = WEIGHT_DISABLED+1  /* minimum weight to use */
751
0
    };
752
    /* candidates: */
753
0
    pj_sockaddr cand_addr[CAND_CNT];
754
0
    int         cand_weight[CAND_CNT];
755
0
    int         selected_cand;
756
0
    char        strip[PJ_INET6_ADDRSTRLEN+10];
757
    /* Special IPv4 addresses. */
758
0
    struct spec_ipv4_t
759
0
    {
760
0
        pj_uint32_t addr;
761
0
        pj_uint32_t mask;
762
0
        int         weight;
763
0
    } spec_ipv4[] =
764
0
    {
765
        /* 127.0.0.0/8, loopback addr will be used if there is no other
766
         * addresses.
767
         */
768
0
        { 0x7f000000, 0xFF000000, WEIGHT_LOOPBACK },
769
770
        /* 0.0.0.0/8, special IP that doesn't seem to be practically useful */
771
0
        { 0x00000000, 0xFF000000, WEIGHT_DISABLED },
772
773
        /* 169.254.0.0/16, a zeroconf/link-local address, which has higher
774
         * priority than loopback and will be used if there is no other
775
         * valid addresses.
776
         */
777
0
        { 0xa9fe0000, 0xFFFF0000, WEIGHT_LINK_LOCAL }
778
0
    };
779
    /* Special IPv6 addresses */
780
0
    struct spec_ipv6_t
781
0
    {
782
0
        pj_uint8_t addr[16];
783
0
        pj_uint8_t mask[16];
784
0
        int        weight;
785
0
    } spec_ipv6[] =
786
0
    {
787
        /* Loopback address, ::1/128 */
788
0
        { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
789
0
          {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
790
0
           0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
791
0
          WEIGHT_LOOPBACK
792
0
        },
793
794
        /* Link local, fe80::/10 */
795
0
        { {0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
796
0
          {0xff,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
797
0
          WEIGHT_LINK_LOCAL
798
0
        },
799
800
        /* Disabled, ::/128 */
801
0
        { {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
802
0
        { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
803
0
          0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
804
0
          WEIGHT_DISABLED
805
0
        }
806
0
    };
807
0
    pj_addrinfo ai;
808
0
    pj_status_t status;
809
810
    /* May not be used if TRACE_ is disabled */
811
0
    PJ_UNUSED_ARG(strip);
812
813
#ifdef _MSC_VER
814
    /* Get rid of "uninitialized he variable" with MS compilers */
815
    pj_bzero(&ai, sizeof(ai));
816
#endif
817
818
0
    cand_cnt = 0;
819
0
    pj_bzero(cand_addr, sizeof(cand_addr));
820
0
    pj_bzero(cand_weight, sizeof(cand_weight));
821
0
    for (i=0; i<PJ_ARRAY_SIZE(cand_addr); ++i) {
822
0
        cand_addr[i].addr.sa_family = (pj_uint16_t)af;
823
0
        PJ_SOCKADDR_RESET_LEN(&cand_addr[i]);
824
0
    }
825
826
0
    addr->addr.sa_family = (pj_uint16_t)af;
827
0
    PJ_SOCKADDR_RESET_LEN(addr);
828
829
0
#if !defined(PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION) || \
830
0
    PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION == 0
831
    /* Get hostname's IP address */
832
0
    {
833
0
        const pj_str_t *hostname = pj_gethostname();
834
0
        count = 1;
835
836
0
        if (hostname->slen > 0)
837
0
            status = pj_getaddrinfo(af, hostname, &count, &ai);
838
0
        else
839
0
            status = PJ_ERESOLVE;
840
841
0
        if (status == PJ_SUCCESS) {
842
0
            pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af);
843
0
            pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr);
844
0
            pj_sockaddr_set_port(&cand_addr[cand_cnt], 0);
845
0
            cand_weight[cand_cnt] += WEIGHT_HOSTNAME;
846
0
            ++cand_cnt;
847
848
0
            TRACE_((THIS_FILE, "hostname IP is %s",
849
0
                    pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 3)));
850
0
        }
851
0
    }
852
#else
853
    PJ_UNUSED_ARG(ai);
854
#endif
855
856
    /* Get default interface (interface for default route) */
857
0
    if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
858
0
        status = pj_getdefaultipinterface(af, addr);
859
0
        if (status == PJ_SUCCESS) {
860
0
            TRACE_((THIS_FILE, "default IP is %s",
861
0
                    pj_sockaddr_print(addr, strip, sizeof(strip), 3)));
862
863
0
            pj_sockaddr_set_port(addr, 0);
864
0
            for (i=0; i<cand_cnt; ++i) {
865
0
                if (pj_sockaddr_cmp(&cand_addr[i], addr)==0)
866
0
                    break;
867
0
            }
868
869
0
            cand_weight[i] += WEIGHT_DEF_ROUTE;
870
0
            if (i >= cand_cnt) {
871
0
                pj_sockaddr_copy_addr(&cand_addr[i], addr);
872
0
                ++cand_cnt;
873
0
            }
874
0
        }
875
0
    }
876
877
878
    /* Enumerate IP interfaces */
879
0
    if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
880
0
        unsigned start_if = cand_cnt;
881
0
        count = PJ_ARRAY_SIZE(cand_addr) - start_if;
882
883
0
        status = pj_enum_ip_interface(af, &count, &cand_addr[start_if]);
884
0
        if (status == PJ_SUCCESS && count) {
885
            /* Clear the port number */
886
0
            for (i=0; i<count; ++i)
887
0
                pj_sockaddr_set_port(&cand_addr[start_if+i], 0);
888
889
            /* For each candidate that we found so far (that is the hostname
890
             * address and default interface address, check if they're found
891
             * in the interface list. If found, add the weight, and if not,
892
             * decrease the weight.
893
             */
894
0
            for (i=0; i<cand_cnt; ++i) {
895
0
                unsigned j;
896
0
                for (j=0; j<count; ++j) {
897
0
                    if (pj_sockaddr_cmp(&cand_addr[i], 
898
0
                                        &cand_addr[start_if+j])==0)
899
0
                        break;
900
0
                }
901
902
0
                if (j == count) {
903
                    /* Not found */
904
0
                    cand_weight[i] -= WEIGHT_INTERFACE;
905
0
                } else {
906
0
                    cand_weight[i] += WEIGHT_INTERFACE;
907
0
                }
908
0
            }
909
910
            /* Add remaining interface to candidate list. */
911
0
            for (i=0; i<count; ++i) {
912
0
                unsigned j;
913
0
                for (j=0; j<cand_cnt; ++j) {
914
0
                    if (pj_sockaddr_cmp(&cand_addr[start_if+i], 
915
0
                                        &cand_addr[j])==0)
916
0
                        break;
917
0
                }
918
919
0
                if (j == cand_cnt) {
920
0
                    if (cand_cnt != (start_if + i)) {
921
0
                        pj_sockaddr_copy_addr(&cand_addr[cand_cnt],
922
0
                                              &cand_addr[start_if + i]);
923
0
                    }
924
0
                    cand_weight[cand_cnt] += WEIGHT_INTERFACE;
925
0
                    ++cand_cnt;
926
0
                }
927
0
            }
928
0
        }
929
0
    }
930
931
    /* Apply weight adjustment for special IPv4/IPv6 addresses
932
     * See https://github.com/pjsip/pjproject/issues/1046
933
     */
934
0
    if (af == PJ_AF_INET) {
935
0
        for (i=0; i<cand_cnt; ++i) {
936
0
            unsigned j;
937
0
            for (j=0; j<PJ_ARRAY_SIZE(spec_ipv4); ++j) {
938
0
                    pj_uint32_t a = pj_ntohl(cand_addr[i].ipv4.sin_addr.s_addr);
939
0
                    pj_uint32_t pa = spec_ipv4[j].addr;
940
0
                    pj_uint32_t pm = spec_ipv4[j].mask;
941
942
0
                    if ((a & pm) == pa) {
943
0
                        cand_weight[i] += spec_ipv4[j].weight;
944
0
                        break;
945
0
                    }
946
0
            }
947
0
        }
948
0
    } else if (af == PJ_AF_INET6) {
949
0
        for (i=0; i<PJ_ARRAY_SIZE(spec_ipv6); ++i) {
950
0
                unsigned j;
951
0
                for (j=0; j<cand_cnt; ++j) {
952
0
                    pj_uint8_t *a = cand_addr[j].ipv6.sin6_addr.s6_addr;
953
0
                    pj_uint8_t am[16];
954
0
                    pj_uint8_t *pa = spec_ipv6[i].addr;
955
0
                    pj_uint8_t *pm = spec_ipv6[i].mask;
956
0
                    unsigned k;
957
958
0
                    for (k=0; k<16; ++k) {
959
0
                        am[k] = (pj_uint8_t)((a[k] & pm[k]) & 0xFF);
960
0
                    }
961
962
0
                    if (pj_memcmp(am, pa, 16)==0) {
963
0
                        cand_weight[j] += spec_ipv6[i].weight;
964
0
                    }
965
0
                }
966
0
        }
967
0
    } else {
968
0
        return PJ_EAFNOTSUP;
969
0
    }
970
971
    /* Enumerate candidates to get the best IP address to choose */
972
0
    selected_cand = -1;
973
0
    for (i=0; i<cand_cnt; ++i) {
974
0
        TRACE_((THIS_FILE, "Checking candidate IP %s, weight=%d",
975
0
                pj_sockaddr_print(&cand_addr[i], strip, sizeof(strip), 3),
976
0
                cand_weight[i]));
977
978
0
        if (cand_weight[i] < MIN_WEIGHT) {
979
0
            continue;
980
0
        }
981
982
0
        if (selected_cand == -1)
983
0
            selected_cand = i;
984
0
        else if (cand_weight[i] > cand_weight[selected_cand])
985
0
            selected_cand = i;
986
0
    }
987
988
    /* If else fails, returns loopback interface as the last resort */
989
0
    if (selected_cand == -1) {
990
0
        if (af==PJ_AF_INET) {
991
0
            addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001);
992
0
        } else {
993
0
            pj_in6_addr *s6_addr_;
994
995
0
            s6_addr_ = (pj_in6_addr*) pj_sockaddr_get_addr(addr);
996
0
            pj_bzero(s6_addr_, sizeof(pj_in6_addr));
997
0
            s6_addr_->s6_addr[15] = 1;
998
0
        }
999
0
        TRACE_((THIS_FILE, "Loopback IP %s returned",
1000
0
                pj_sockaddr_print(addr, strip, sizeof(strip), 3)));
1001
0
    } else {
1002
0
        pj_sockaddr_copy_addr(addr, &cand_addr[selected_cand]);
1003
0
        TRACE_((THIS_FILE, "Candidate %s selected",
1004
0
                pj_sockaddr_print(addr, strip, sizeof(strip), 3)));
1005
0
    }
1006
1007
0
    return PJ_SUCCESS;
1008
0
}
1009
1010
/* Get IP interface for sending to the specified destination */
1011
PJ_DEF(pj_status_t) pj_getipinterface(int af,
1012
                                      const pj_str_t *dst,
1013
                                      pj_sockaddr *itf_addr,
1014
                                      pj_bool_t allow_resolve,
1015
                                      pj_sockaddr *p_dst_addr)
1016
0
{
1017
0
    pj_sockaddr dst_addr;
1018
0
    pj_sock_t fd;
1019
0
    int len;
1020
0
    pj_uint8_t zero[64];
1021
0
    pj_status_t status;
1022
1023
0
    pj_sockaddr_init(af, &dst_addr, NULL, 53);
1024
0
    status = pj_inet_pton(af, dst, pj_sockaddr_get_addr(&dst_addr));
1025
0
    if (status != PJ_SUCCESS) {
1026
        /* "dst" is not an IP address. */
1027
0
        if (allow_resolve) {
1028
0
            status = pj_sockaddr_init(af, &dst_addr, dst, 53);
1029
0
        } else {
1030
0
            pj_str_t cp;
1031
1032
0
            if (af == PJ_AF_INET) {
1033
0
                cp = pj_str("1.1.1.1");
1034
0
            } else {
1035
0
                cp = pj_str("1::1");
1036
0
            }
1037
0
            status = pj_sockaddr_init(af, &dst_addr, &cp, 53);
1038
0
        }
1039
1040
0
        if (status != PJ_SUCCESS)
1041
0
            return status;
1042
0
    }
1043
1044
    /* Create UDP socket and connect() to the destination IP */
1045
0
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
1046
0
    if (status != PJ_SUCCESS) {
1047
0
        return status;
1048
0
    }
1049
1050
0
    status = pj_sock_connect(fd, &dst_addr, pj_sockaddr_get_len(&dst_addr));
1051
0
    if (status != PJ_SUCCESS) {
1052
0
        pj_sock_close(fd);
1053
0
        return status;
1054
0
    }
1055
1056
0
    len = sizeof(*itf_addr);
1057
0
    status = pj_sock_getsockname(fd, itf_addr, &len);
1058
0
    if (status != PJ_SUCCESS) {
1059
0
        pj_sock_close(fd);
1060
0
        return status;
1061
0
    }
1062
1063
0
    pj_sock_close(fd);
1064
1065
    /* Check that the address returned is not zero */
1066
0
    pj_bzero(zero, sizeof(zero));
1067
0
    if (pj_memcmp(pj_sockaddr_get_addr(itf_addr), zero,
1068
0
                  pj_sockaddr_get_addr_len(itf_addr))==0)
1069
0
    {
1070
0
        return PJ_ENOTFOUND;
1071
0
    }
1072
1073
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
1074
    /* Check if the local address is link-local but the destination
1075
     * is not link-local.
1076
     */
1077
    if (af == pj_AF_INET6() &&
1078
        IN6_IS_ADDR_LINKLOCAL(&itf_addr->ipv6.sin6_addr) &&
1079
        (!IN6_IS_ADDR_LINKLOCAL(&dst_addr.ipv6.sin6_addr)))
1080
    {
1081
        TRACE_((THIS_FILE, "Local interface address is link-local and "
1082
                           "the destination host is external"));
1083
1084
        return PJ_ENOTFOUND;
1085
    }
1086
#endif
1087
1088
0
    if (p_dst_addr)
1089
0
        *p_dst_addr = dst_addr;
1090
1091
0
    return PJ_SUCCESS;
1092
0
}
1093
1094
/* Get the default IP interface */
1095
PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr)
1096
0
{
1097
0
    pj_str_t cp;
1098
1099
0
    if (af == PJ_AF_INET) {
1100
0
        cp = pj_str("1.1.1.1");
1101
0
    } else {
1102
0
        cp = pj_str("1::1");
1103
0
    }
1104
1105
0
    return pj_getipinterface(af, &cp, addr, PJ_FALSE, NULL);
1106
0
}
1107
1108
1109
/*
1110
 * Bind socket at random port.
1111
 */
1112
PJ_DEF(pj_status_t) pj_sock_bind_random(  pj_sock_t sockfd,
1113
                                          const pj_sockaddr_t *addr,
1114
                                          pj_uint16_t port_range,
1115
                                          pj_uint16_t max_try)
1116
0
{
1117
0
    pj_sockaddr bind_addr;
1118
0
    int addr_len;
1119
0
    pj_uint16_t base_port;
1120
0
    pj_status_t status = PJ_SUCCESS;
1121
1122
0
    PJ_CHECK_STACK();
1123
1124
0
    PJ_ASSERT_RETURN(addr, PJ_EINVAL);
1125
1126
0
    pj_sockaddr_cp(&bind_addr, addr);
1127
0
    addr_len = pj_sockaddr_get_len(addr);
1128
0
    base_port = pj_sockaddr_get_port(addr);
1129
1130
0
    if (base_port == 0 || port_range == 0) {
1131
0
        return pj_sock_bind(sockfd, &bind_addr, addr_len);
1132
0
    }
1133
1134
0
    for (; max_try; --max_try) {
1135
0
        pj_uint16_t port;
1136
0
        port = (pj_uint16_t)(base_port + pj_rand() % (port_range + 1));
1137
0
        pj_sockaddr_set_port(&bind_addr, port);
1138
0
        status = pj_sock_bind(sockfd, &bind_addr, addr_len);
1139
0
        if (status == PJ_SUCCESS)
1140
0
            break;
1141
0
    }
1142
1143
0
    return status;
1144
0
}
1145
1146
1147
/*
1148
 * Adjust socket send/receive buffer size.
1149
 */
1150
PJ_DEF(pj_status_t) pj_sock_setsockopt_sobuf( pj_sock_t sockfd,
1151
                                              pj_uint16_t optname,
1152
                                              pj_bool_t auto_retry,
1153
                                              unsigned *buf_size)
1154
0
{
1155
0
    pj_status_t status;
1156
0
    int try_size, cur_size, i, step, size_len;
1157
0
    enum { MAX_TRY = 20 };
1158
1159
0
    PJ_CHECK_STACK();
1160
1161
0
    PJ_ASSERT_RETURN(sockfd != PJ_INVALID_SOCKET &&
1162
0
                     buf_size &&
1163
0
                     *buf_size > 0 &&
1164
0
                     (optname == pj_SO_RCVBUF() ||
1165
0
                      optname == pj_SO_SNDBUF()),
1166
0
                     PJ_EINVAL);
1167
1168
0
    size_len = sizeof(cur_size);
1169
0
    status = pj_sock_getsockopt(sockfd, pj_SOL_SOCKET(), optname,
1170
0
                                &cur_size, &size_len);
1171
0
    if (status != PJ_SUCCESS)
1172
0
        return status;
1173
1174
0
    try_size = *buf_size;
1175
0
    step = (try_size - cur_size) / MAX_TRY;
1176
0
    if (step < 4096)
1177
0
        step = 4096;
1178
1179
0
    for (i = 0; i < (MAX_TRY-1); ++i) {
1180
0
        if (try_size <= cur_size) {
1181
            /* Done, return current size */
1182
0
            *buf_size = cur_size;
1183
0
            break;
1184
0
        }
1185
1186
0
        status = pj_sock_setsockopt(sockfd, pj_SOL_SOCKET(), optname,
1187
0
                                    &try_size, sizeof(try_size));
1188
0
        if (status == PJ_SUCCESS) {
1189
0
            status = pj_sock_getsockopt(sockfd, pj_SOL_SOCKET(), optname,
1190
0
                                        &cur_size, &size_len);
1191
0
            if (status != PJ_SUCCESS) {
1192
                /* Ops! No info about current size, just return last try size
1193
                 * and quit.
1194
                 */
1195
0
                *buf_size = try_size;
1196
0
                break;
1197
0
            }
1198
0
        }
1199
1200
0
        if (!auto_retry)
1201
0
            break;
1202
1203
0
        try_size -= step;
1204
0
    }
1205
1206
0
    return status;
1207
0
}
1208
1209
1210
PJ_DEF(pj_status_t) pj_sockopt_params_clone(pj_pool_t *pool,
1211
                                            pj_sockopt_params *dst,
1212
                                            const pj_sockopt_params *src)
1213
0
{
1214
0
    unsigned int i;
1215
1216
0
    PJ_ASSERT_RETURN(pool && src && dst, PJ_EINVAL);
1217
1218
0
    pj_memcpy(dst, src, sizeof(pj_sockopt_params));
1219
0
    for (i = 0; i < dst->cnt && i < PJ_MAX_SOCKOPT_PARAMS; ++i) {
1220
0
        if (dst->options[i].optlen == 0) {
1221
0
            dst->options[i].optval = NULL;
1222
0
            continue;
1223
0
        }
1224
0
        dst->options[i].optval = pj_pool_alloc(pool, dst->options[i].optlen);
1225
0
        pj_memcpy(dst->options[i].optval, src->options[i].optval,
1226
0
                  dst->options[i].optlen);
1227
0
    }
1228
1229
0
    return PJ_SUCCESS;
1230
0
}
1231
1232
1233
PJ_DEF(char *) pj_addr_str_print( const pj_str_t *host_str, int port, 
1234
                                  char *buf, int size, unsigned flag)
1235
0
{
1236
0
    enum {
1237
0
        WITH_PORT = 1
1238
0
    };
1239
0
    char *bquote, *equote;
1240
0
    int af = pj_AF_UNSPEC();    
1241
0
    pj_in6_addr dummy6;
1242
1243
    /* Check if this is an IPv6 address */
1244
0
    if (pj_inet_pton(pj_AF_INET6(), host_str, &dummy6) == PJ_SUCCESS)
1245
0
        af = pj_AF_INET6();
1246
1247
0
    if (af == pj_AF_INET6()) {
1248
0
        bquote = "[";
1249
0
        equote = "]";    
1250
0
    } else {
1251
0
        bquote = "";
1252
0
        equote = "";    
1253
0
    } 
1254
1255
0
    if (flag & WITH_PORT) {
1256
0
        pj_ansi_snprintf(buf, size, "%s%.*s%s:%d",
1257
0
                         bquote, (int)host_str->slen, host_str->ptr, equote, 
1258
0
                         port);
1259
0
    } else {
1260
0
        pj_ansi_snprintf(buf, size, "%s%.*s%s",
1261
0
                         bquote, (int)host_str->slen, host_str->ptr, equote);
1262
0
    }
1263
0
    return buf;
1264
0
}
1265
1266
/*
1267
 * Simulate unix-like socketpair()
1268
 * Use a pair of IPv4/IPv6 local sockets (listening on 127.0.0.1/::1)
1269
 */
1270
static pj_status_t socketpair_imp(int family,
1271
                                  int type,
1272
                                  int protocol,
1273
                                  pj_sock_t sv[2])
1274
0
{
1275
0
    pj_status_t status;
1276
0
    pj_sock_t lfd = PJ_INVALID_SOCKET;
1277
0
    pj_sock_t cfd = PJ_INVALID_SOCKET;
1278
0
    pj_str_t loopback;
1279
0
    pj_sockaddr sa;
1280
0
    int salen;
1281
0
    int type0 = type;
1282
1283
0
#if PJ_HAS_TCP
1284
0
    PJ_ASSERT_RETURN((type & 0xF) == pj_SOCK_DGRAM() ||
1285
0
                     (type & 0xF) == pj_SOCK_STREAM(),
1286
0
                     PJ_EINVAL);
1287
#else
1288
    PJ_ASSERT_RETURN((type & 0xF) == pj_SOCK_DGRAM(), PJ_EINVAL);
1289
#endif
1290
1291
0
    PJ_ASSERT_RETURN(family == pj_AF_INET() || family == pj_AF_INET6(),
1292
0
                     PJ_EINVAL);
1293
1294
0
    loopback = family == pj_AF_INET() ? pj_str("127.0.0.1") : pj_str("::1");
1295
1296
#if !defined(SOCK_CLOEXEC)
1297
    if ((type0 & pj_SOCK_CLOEXEC()) == pj_SOCK_CLOEXEC())
1298
        type &= ~pj_SOCK_CLOEXEC();
1299
#else
1300
0
    PJ_UNUSED_ARG(type0);
1301
0
#endif
1302
1303
    /* listen */
1304
0
    status = pj_sock_socket(family, type, protocol, &lfd);
1305
0
    if (status != PJ_SUCCESS)
1306
0
        goto on_error;
1307
1308
0
    pj_sockaddr_init(family, &sa, &loopback, 0);
1309
0
    salen = pj_sockaddr_get_len(&sa);
1310
0
    status = pj_sock_bind(lfd, &sa, salen);
1311
0
    if (status != PJ_SUCCESS)
1312
0
        goto on_error;
1313
1314
0
    status = pj_sock_getsockname(lfd, &sa, &salen);
1315
0
    if (status != PJ_SUCCESS)
1316
0
        goto on_error;
1317
1318
0
#if PJ_HAS_TCP
1319
0
    if ((type & 0xF) == pj_SOCK_STREAM()) {
1320
0
        status = pj_sock_listen(lfd, 1);
1321
0
        if (status != PJ_SUCCESS)
1322
0
            goto on_error;
1323
0
    }
1324
0
#endif
1325
1326
    /* connect to listen fd */
1327
0
    status = pj_sock_socket(family, type, protocol, &cfd);
1328
0
    if (status != PJ_SUCCESS)
1329
0
        goto on_error;
1330
0
    status = pj_sock_connect(cfd, &sa, salen);
1331
0
    if (status != PJ_SUCCESS)
1332
0
        goto on_error;
1333
1334
0
    if ((type & 0xF) == pj_SOCK_DGRAM()) {
1335
0
        status = pj_sock_getsockname(cfd, &sa, &salen);
1336
0
        if (status != PJ_SUCCESS)
1337
0
            goto on_error;
1338
0
        status = pj_sock_connect(lfd, &sa, salen);
1339
0
        if (status != PJ_SUCCESS)
1340
0
            goto on_error;
1341
0
        sv[0] = lfd;
1342
0
        sv[1] = cfd;
1343
0
    }
1344
0
#if PJ_HAS_TCP
1345
0
    else if ((type & 0xF) == pj_SOCK_STREAM()) {
1346
0
        pj_sock_t newfd = PJ_INVALID_SOCKET;
1347
0
        status = pj_sock_accept(lfd, &newfd, NULL, NULL);
1348
0
        if (status != PJ_SUCCESS)
1349
0
            goto on_error;
1350
0
        pj_sock_close(lfd);
1351
0
        sv[0] = newfd;
1352
0
        sv[1] = cfd;
1353
0
    }
1354
0
#endif
1355
1356
#if !defined(SOCK_CLOEXEC)
1357
    if ((type0 & pj_SOCK_CLOEXEC()) == pj_SOCK_CLOEXEC()) {
1358
        pj_set_cloexec_flag((int)sv[0]);
1359
        pj_set_cloexec_flag((int)sv[1]);
1360
    }
1361
#endif
1362
1363
0
    return PJ_SUCCESS;
1364
1365
0
on_error:
1366
0
    if (lfd != PJ_INVALID_SOCKET)
1367
0
        pj_sock_close(lfd);
1368
0
    if (cfd != PJ_INVALID_SOCKET)
1369
0
        pj_sock_close(cfd);
1370
0
    return status;
1371
0
}
1372
1373
#if defined(PJ_SOCK_HAS_SOCKETPAIR) && PJ_SOCK_HAS_SOCKETPAIR != 0
1374
PJ_DEF(pj_status_t) pj_sock_socketpair(int family,
1375
                                       int type,
1376
                                       int protocol,
1377
                                       pj_sock_t sv[2])
1378
0
{
1379
0
    int status;
1380
0
    int tmp_sv[2];
1381
0
    int type0 = type;
1382
1383
0
    PJ_CHECK_STACK();
1384
1385
#if !defined(SOCK_CLOEXEC)
1386
    if ((type0 & pj_SOCK_CLOEXEC()) == pj_SOCK_CLOEXEC())
1387
        type &= ~pj_SOCK_CLOEXEC();
1388
#endif
1389
1390
0
    status = socketpair(family, type, protocol, tmp_sv);
1391
0
    if (status != PJ_SUCCESS) {
1392
0
        if (errno == EOPNOTSUPP) {
1393
0
            return socketpair_imp(family, type0, protocol, sv);
1394
0
        }
1395
0
        status = PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
1396
0
        return status;
1397
0
    }
1398
0
    sv[0] = tmp_sv[0];
1399
0
    sv[1] = tmp_sv[1];
1400
0
    return PJ_SUCCESS;
1401
0
}
1402
#else
1403
PJ_DEF(pj_status_t) pj_sock_socketpair(int family,
1404
                                       int type,
1405
                                       int protocol,
1406
                                       pj_sock_t sv[2])
1407
{
1408
    PJ_CHECK_STACK();
1409
    return socketpair_imp(family, type, protocol, sv);
1410
}
1411
#endif
1412
1413
1414
/* Check IP address type. */
1415
PJ_DEF(pj_bool_t) pj_check_addr_type(const pj_sockaddr *addr, unsigned type)
1416
0
{
1417
0
    int af;
1418
1419
0
    PJ_ASSERT_RETURN(addr && type, PJ_EINVAL);
1420
0
    PJ_ASSERT_RETURN(addr->addr.sa_family == PJ_AF_INET ||
1421
0
                     addr->addr.sa_family == PJ_AF_INET6, PJ_EINVAL);
1422
1423
0
    af = addr->addr.sa_family;
1424
1425
0
    if (af == PJ_AF_INET) {
1426
0
        enum {
1427
            /* Disabled: 0.0.0.0/8 */
1428
0
            ADDR4_DISABLED = 0x00000000,
1429
0
            MASK4_DISABLED = 0xFF000000,
1430
            /* Loopback: 127.0.0.0/8 */
1431
0
            ADDR4_LOOPBACK = 0x7f000000,
1432
0
            MASK4_LOOPBACK = 0xFF000000,
1433
            /* Link-local: 169.254.0.0/16 */
1434
0
            ADDR4_LINKLOCAL = 0xa9fe0000,
1435
0
            MASK4_LINKLOCAL = 0xFFFF0000,
1436
            /* Multicast: 224.0.0.0/3 */
1437
0
            ADDR4_MULTICAST = 0xE0000000,
1438
0
            MASK4_MULTICAST = 0xF0000000,
1439
0
        };
1440
1441
0
        pj_uint32_t a = pj_ntohl(addr->ipv4.sin_addr.s_addr);
1442
1443
0
        if ((type & PJ_ADDR_TYPE_DISABLED) &&
1444
0
            (a & (pj_uint32_t)MASK4_DISABLED)==(pj_uint32_t)ADDR4_DISABLED)
1445
0
        {
1446
0
            return PJ_TRUE;
1447
0
        }
1448
1449
0
        if ((type & PJ_ADDR_TYPE_LOOPBACK) &&
1450
0
            (a & (pj_uint32_t)MASK4_LOOPBACK)==(pj_uint32_t)ADDR4_LOOPBACK)
1451
0
        {
1452
0
            return PJ_TRUE;
1453
0
        }
1454
1455
0
        if ((type & PJ_ADDR_TYPE_LINK_LOCAL) &&
1456
0
            (a & (pj_uint32_t)MASK4_LINKLOCAL)==(pj_uint32_t)ADDR4_LINKLOCAL)
1457
0
        {
1458
0
            return PJ_TRUE;
1459
0
        }
1460
1461
0
        if (type & PJ_ADDR_TYPE_PRIVATE) {
1462
0
            pj_uint8_t b1 = (pj_uint8_t)(a >> 24);
1463
0
            pj_uint8_t b2 = (pj_uint8_t)((a >> 16) & 0x0ff);;
1464
1465
            /* 10.0.0.0/8 */
1466
0
            if (b1 == 10)
1467
0
                return PJ_TRUE;
1468
1469
            /* 172.16.0.0/12 or 172.16.0.0-172.31.255.255 */
1470
0
            if ((b1 == 172) && (b2 >= 16) && (b2 <= 31))
1471
0
                return PJ_TRUE;
1472
1473
            /* 192.168.0.0/16 */
1474
0
            if ((b1 == 192) && (b2 == 168))
1475
0
                return PJ_TRUE;
1476
0
        }
1477
1478
0
        if ((type & PJ_ADDR_TYPE_MULTICAST) &&
1479
0
            (a & (pj_uint32_t)MASK4_MULTICAST)==(pj_uint32_t)ADDR4_MULTICAST)
1480
0
        {
1481
0
            return PJ_TRUE;
1482
0
        }
1483
1484
0
    } else /* if (af == PJ_AF_INET6) */ {
1485
1486
0
        if (type & PJ_ADDR_TYPE_DISABLED) {
1487
            /* ::/128 */
1488
0
            pj_uint8_t saddr[16] = {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1489
0
            if (pj_memcmp(saddr, &addr->ipv6.sin6_addr, 16) == 0)
1490
0
                return PJ_TRUE;
1491
0
        }
1492
1493
0
        if (type & PJ_ADDR_TYPE_LOOPBACK) {
1494
            /* ::1/128 */
1495
0
            pj_uint8_t saddr[16] = {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
1496
0
            if (pj_memcmp(saddr, &addr->ipv6.sin6_addr, 16) == 0)
1497
0
                return PJ_TRUE;
1498
0
        }
1499
1500
0
        if (type & PJ_ADDR_TYPE_LINK_LOCAL) {
1501
            /* fe80::/64 */
1502
0
            pj_uint8_t saddr[16] = {0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1503
0
            if (pj_memcmp(saddr, &addr->ipv6.sin6_addr, 8) == 0)
1504
0
                return PJ_TRUE;
1505
0
        }
1506
1507
0
        if (type & PJ_ADDR_TYPE_PRIVATE) {
1508
            /* fc00::/7 */
1509
0
            if ((addr->ipv6.sin6_addr.s6_addr[0] & 0xfe) == 0xfc)
1510
0
                return PJ_TRUE;
1511
0
        }
1512
1513
0
        if (type & PJ_ADDR_TYPE_MULTICAST) {
1514
            /* ff00::/8 */
1515
0
            if (addr->ipv6.sin6_addr.s6_addr[0] == 0xff)
1516
0
                return PJ_TRUE;
1517
0
        }
1518
0
    }
1519
1520
0
    return PJ_FALSE;
1521
0
}
1522
1523
1524
/* Only need to implement these in DLL build */
1525
#if defined(PJ_DLL)
1526
1527
PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void)
1528
{
1529
    return PJ_AF_UNSPEC;
1530
}
1531
1532
PJ_DEF(pj_uint16_t) pj_AF_UNIX(void)
1533
{
1534
    return PJ_AF_UNIX;
1535
}
1536
1537
PJ_DEF(pj_uint16_t) pj_AF_INET(void)
1538
{
1539
    return PJ_AF_INET;
1540
}
1541
1542
PJ_DEF(pj_uint16_t) pj_AF_INET6(void)
1543
{
1544
    return PJ_AF_INET6;
1545
}
1546
1547
PJ_DEF(pj_uint16_t) pj_AF_PACKET(void)
1548
{
1549
    return PJ_AF_PACKET;
1550
}
1551
1552
PJ_DEF(pj_uint16_t) pj_AF_IRDA(void)
1553
{
1554
    return PJ_AF_IRDA;
1555
}
1556
1557
PJ_DEF(int) pj_SOCK_STREAM(void)
1558
{
1559
    return PJ_SOCK_STREAM;
1560
}
1561
1562
PJ_DEF(int) pj_SOCK_DGRAM(void)
1563
{
1564
    return PJ_SOCK_DGRAM;
1565
}
1566
1567
PJ_DEF(int) pj_SOCK_RAW(void)
1568
{
1569
    return PJ_SOCK_RAW;
1570
}
1571
1572
PJ_DEF(int) pj_SOCK_RDM(void)
1573
{
1574
    return PJ_SOCK_RDM;
1575
}
1576
1577
PJ_DEF(int) pj_SOCK_CLOEXEC(void)
1578
{
1579
    return PJ_SOCK_CLOEXEC;
1580
}
1581
1582
PJ_DEF(pj_uint16_t) pj_SOL_SOCKET(void)
1583
{
1584
    return PJ_SOL_SOCKET;
1585
}
1586
1587
PJ_DEF(pj_uint16_t) pj_SOL_IP(void)
1588
{
1589
    return PJ_SOL_IP;
1590
}
1591
1592
PJ_DEF(pj_uint16_t) pj_SOL_TCP(void)
1593
{
1594
    return PJ_SOL_TCP;
1595
}
1596
1597
PJ_DEF(pj_uint16_t) pj_SOL_UDP(void)
1598
{
1599
    return PJ_SOL_UDP;
1600
}
1601
1602
PJ_DEF(pj_uint16_t) pj_SOL_IPV6(void)
1603
{
1604
    return PJ_SOL_IPV6;
1605
}
1606
1607
PJ_DEF(int) pj_IP_TOS(void)
1608
{
1609
    return PJ_IP_TOS;
1610
}
1611
1612
PJ_DEF(int) pj_IPTOS_LOWDELAY(void)
1613
{
1614
    return PJ_IPTOS_LOWDELAY;
1615
}
1616
1617
PJ_DEF(int) pj_IPTOS_THROUGHPUT(void)
1618
{
1619
    return PJ_IPTOS_THROUGHPUT;
1620
}
1621
1622
PJ_DEF(int) pj_IPTOS_RELIABILITY(void)
1623
{
1624
    return PJ_IPTOS_RELIABILITY;
1625
}
1626
1627
PJ_DEF(int) pj_IPTOS_MINCOST(void)
1628
{
1629
    return PJ_IPTOS_MINCOST;
1630
}
1631
1632
PJ_DEF(int) pj_IPV6_TCLASS(void)
1633
{
1634
    return PJ_IPV6_TCLASS;
1635
}
1636
1637
PJ_DEF(pj_uint16_t) pj_SO_TYPE(void)
1638
{
1639
    return PJ_SO_TYPE;
1640
}
1641
1642
PJ_DEF(pj_uint16_t) pj_SO_RCVBUF(void)
1643
{
1644
    return PJ_SO_RCVBUF;
1645
}
1646
1647
PJ_DEF(pj_uint16_t) pj_SO_SNDBUF(void)
1648
{
1649
    return PJ_SO_SNDBUF;
1650
}
1651
1652
PJ_DEF(pj_uint16_t) pj_TCP_NODELAY(void)
1653
{
1654
    return PJ_TCP_NODELAY;
1655
}
1656
1657
PJ_DEF(pj_uint16_t) pj_SO_REUSEADDR(void)
1658
{
1659
    return PJ_SO_REUSEADDR;
1660
}
1661
1662
PJ_DEF(pj_uint16_t) pj_SO_NOSIGPIPE(void)
1663
{
1664
    return PJ_SO_NOSIGPIPE;
1665
}
1666
1667
PJ_DEF(pj_uint16_t) pj_SO_PRIORITY(void)
1668
{
1669
    return PJ_SO_PRIORITY;
1670
}
1671
1672
PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_IF(void)
1673
{
1674
    return PJ_IP_MULTICAST_IF;
1675
}
1676
1677
PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_TTL(void)
1678
{
1679
    return PJ_IP_MULTICAST_TTL;
1680
}
1681
1682
PJ_DEF(pj_uint16_t) pj_IP_MULTICAST_LOOP(void)
1683
{
1684
    return PJ_IP_MULTICAST_LOOP;
1685
}
1686
1687
PJ_DEF(pj_uint16_t) pj_IP_ADD_MEMBERSHIP(void)
1688
{
1689
    return PJ_IP_ADD_MEMBERSHIP;
1690
}
1691
1692
PJ_DEF(pj_uint16_t) pj_IP_DROP_MEMBERSHIP(void)
1693
{
1694
    return PJ_IP_DROP_MEMBERSHIP;
1695
}
1696
1697
PJ_DEF(int) pj_MSG_OOB(void)
1698
{
1699
    return PJ_MSG_OOB;
1700
}
1701
1702
PJ_DEF(int) pj_MSG_PEEK(void)
1703
{
1704
    return PJ_MSG_PEEK;
1705
}
1706
1707
PJ_DEF(int) pj_MSG_DONTROUTE(void)
1708
{
1709
    return PJ_MSG_DONTROUTE;
1710
}
1711
1712
#endif  /* PJ_DLL */
1713