Coverage Report

Created: 2024-02-11 06:40

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