Coverage Report

Created: 2025-08-28 07:07

/src/pjsip/pjlib/src/pj/sock_bsd.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/os.h>
21
#include <pj/assert.h>
22
#include <pj/string.h>
23
#include <pj/compat/socket.h>
24
#include <pj/addr_resolv.h>
25
#include <pj/errno.h>
26
#include <pj/unicode.h>
27
28
#if 0
29
    /* Enable some tracing */
30
    #include <pj/log.h>
31
    #define TRACE_(arg) PJ_LOG(4,arg)
32
#else
33
    #define TRACE_(arg)
34
#endif
35
36
#define THIS_FILE       "sock_bsd.c"
37
38
/*
39
 * Address families conversion.
40
 * The values here are indexed based on pj_addr_family.
41
 */
42
const pj_uint16_t PJ_AF_UNSPEC  = AF_UNSPEC;
43
const pj_uint16_t PJ_AF_UNIX    = AF_UNIX;
44
const pj_uint16_t PJ_AF_INET    = AF_INET;
45
const pj_uint16_t PJ_AF_INET6   = AF_INET6;
46
#ifdef AF_PACKET
47
const pj_uint16_t PJ_AF_PACKET  = AF_PACKET;
48
#else
49
const pj_uint16_t PJ_AF_PACKET  = 0xFFFF;
50
#endif
51
#ifdef AF_IRDA
52
const pj_uint16_t PJ_AF_IRDA    = AF_IRDA;
53
#else
54
const pj_uint16_t PJ_AF_IRDA    = 0xFFFF;
55
#endif
56
57
/*
58
 * Socket types conversion.
59
 * The values here are indexed based on pj_sock_type
60
 */
61
const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
62
const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
63
const pj_uint16_t PJ_SOCK_RAW   = SOCK_RAW;
64
const pj_uint16_t PJ_SOCK_RDM   = SOCK_RDM;
65
66
#if defined(SOCK_CLOEXEC)
67
const int PJ_SOCK_CLOEXEC = SOCK_CLOEXEC;
68
#elif defined(PJ_WIN32) || defined(PJ_WIN64)
69
const int PJ_SOCK_CLOEXEC = 0;
70
#else
71
/*
72
 * On some unix-like platforms (eg. macos), SOCK_CLOEXEC is not defined,
73
 * It can use #pj_set_cloexec_flag() to set socket close-on-exec flag.
74
 *
75
 * Set PJ_SOCK_CLOEXEC to a non-zero value,
76
 * together with the macro SOCK_CLOEXEC to determine whether it should
77
 * set socket close-on-exec flag.
78
 *  #if !defined(SOCK_CLOEXEC)
79
 *       if (type & pj_SOCK_CLOEXEC() == pj_SOCK_CLOEXEC()) {
80
 *             // set close-on-exec flag
81
 *       }
82
 *  #endif
83
 */
84
const int PJ_SOCK_CLOEXEC = 02000000;
85
#endif
86
87
/*
88
 * Socket level values.
89
 */
90
const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
91
#if (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64) || \
92
      (defined (IPPROTO_IP))
93
const pj_uint16_t PJ_SOL_IP     = IPPROTO_IP;
94
#elif defined(SOL_IP)
95
const pj_uint16_t PJ_SOL_IP     = SOL_IP;
96
#else
97
const pj_uint16_t PJ_SOL_IP     = 0;
98
#endif /* SOL_IP */
99
100
#if defined(SOL_TCP)
101
const pj_uint16_t PJ_SOL_TCP    = SOL_TCP;
102
#elif defined(IPPROTO_TCP)
103
const pj_uint16_t PJ_SOL_TCP    = IPPROTO_TCP;
104
#elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
105
const pj_uint16_t PJ_SOL_TCP    = IPPROTO_TCP;
106
#else
107
const pj_uint16_t PJ_SOL_TCP    = 6;
108
#endif /* SOL_TCP */
109
110
#ifdef SOL_UDP
111
const pj_uint16_t PJ_SOL_UDP    = SOL_UDP;
112
#elif defined(IPPROTO_UDP)
113
const pj_uint16_t PJ_SOL_UDP    = IPPROTO_UDP;
114
#elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
115
const pj_uint16_t PJ_SOL_UDP    = IPPROTO_UDP;
116
#else
117
const pj_uint16_t PJ_SOL_UDP    = 17;
118
#endif /* SOL_UDP */
119
120
#ifdef SOL_IPV6
121
const pj_uint16_t PJ_SOL_IPV6   = SOL_IPV6;
122
#elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
123
#   if defined(IPPROTO_IPV6) || (_WIN32_WINNT >= 0x0501)
124
        const pj_uint16_t PJ_SOL_IPV6   = IPPROTO_IPV6;
125
#   else
126
        const pj_uint16_t PJ_SOL_IPV6   = 41;
127
#   endif
128
#else
129
const pj_uint16_t PJ_SOL_IPV6   = 41;
130
#endif /* SOL_IPV6 */
131
132
/* IP_TOS */
133
#ifdef IP_TOS
134
const pj_uint16_t PJ_IP_TOS     = IP_TOS;
135
#else
136
const pj_uint16_t PJ_IP_TOS     = 1;
137
#endif
138
139
140
/* TOS settings (declared in netinet/ip.h) */
141
#ifdef IPTOS_LOWDELAY
142
const pj_uint16_t PJ_IPTOS_LOWDELAY     = IPTOS_LOWDELAY;
143
#else
144
const pj_uint16_t PJ_IPTOS_LOWDELAY     = 0x10;
145
#endif
146
#ifdef IPTOS_THROUGHPUT
147
const pj_uint16_t PJ_IPTOS_THROUGHPUT   = IPTOS_THROUGHPUT;
148
#else
149
const pj_uint16_t PJ_IPTOS_THROUGHPUT   = 0x08;
150
#endif
151
#ifdef IPTOS_RELIABILITY
152
const pj_uint16_t PJ_IPTOS_RELIABILITY  = IPTOS_RELIABILITY;
153
#else
154
const pj_uint16_t PJ_IPTOS_RELIABILITY  = 0x04;
155
#endif
156
#ifdef IPTOS_MINCOST
157
const pj_uint16_t PJ_IPTOS_MINCOST      = IPTOS_MINCOST;
158
#else
159
const pj_uint16_t PJ_IPTOS_MINCOST      = 0x02;
160
#endif
161
162
163
/* IPV6_TCLASS */
164
#ifdef IPV6_TCLASS
165
const pj_uint16_t PJ_IPV6_TCLASS = IPV6_TCLASS;
166
#else
167
const pj_uint16_t PJ_IPV6_TCLASS = 0xFFFF;
168
#endif
169
170
171
/* optname values. */
172
const pj_uint16_t PJ_SO_TYPE    = SO_TYPE;
173
const pj_uint16_t PJ_SO_RCVBUF  = SO_RCVBUF;
174
const pj_uint16_t PJ_SO_SNDBUF  = SO_SNDBUF;
175
const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
176
const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
177
#ifdef SO_NOSIGPIPE
178
const pj_uint16_t PJ_SO_NOSIGPIPE = SO_NOSIGPIPE;
179
#else
180
const pj_uint16_t PJ_SO_NOSIGPIPE = 0xFFFF;
181
#endif
182
#if defined(SO_PRIORITY)
183
const pj_uint16_t PJ_SO_PRIORITY = SO_PRIORITY;
184
#else
185
/* This is from Linux, YMMV */
186
const pj_uint16_t PJ_SO_PRIORITY = 12;
187
#endif
188
189
/* Multicasting is not supported e.g. in PocketPC 2003 SDK */
190
#ifdef IP_MULTICAST_IF
191
const pj_uint16_t PJ_IP_MULTICAST_IF    = IP_MULTICAST_IF;
192
const pj_uint16_t PJ_IP_MULTICAST_TTL   = IP_MULTICAST_TTL;
193
const pj_uint16_t PJ_IP_MULTICAST_LOOP  = IP_MULTICAST_LOOP;
194
const pj_uint16_t PJ_IP_ADD_MEMBERSHIP  = IP_ADD_MEMBERSHIP;
195
const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
196
#else
197
const pj_uint16_t PJ_IP_MULTICAST_IF    = 0xFFFF;
198
const pj_uint16_t PJ_IP_MULTICAST_TTL   = 0xFFFF;
199
const pj_uint16_t PJ_IP_MULTICAST_LOOP  = 0xFFFF;
200
const pj_uint16_t PJ_IP_ADD_MEMBERSHIP  = 0xFFFF;
201
const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
202
#endif
203
204
/* recv() and send() flags */
205
const int PJ_MSG_OOB            = MSG_OOB;
206
const int PJ_MSG_PEEK           = MSG_PEEK;
207
const int PJ_MSG_DONTROUTE      = MSG_DONTROUTE;
208
209
210
#if 0
211
static void CHECK_ADDR_LEN(const pj_sockaddr *addr, int len)
212
{
213
    pj_sockaddr *a = (pj_sockaddr*)addr;
214
    pj_assert((a->addr.sa_family==PJ_AF_INET && len==sizeof(pj_sockaddr_in)) ||
215
              (a->addr.sa_family==PJ_AF_INET6 && len==sizeof(pj_sockaddr_in6)));
216
217
}
218
#else
219
#define CHECK_ADDR_LEN(addr,len)
220
#endif
221
222
/*
223
 * Convert 16-bit value from network byte order to host byte order.
224
 */
225
PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
226
0
{
227
0
    return ntohs(netshort);
228
0
}
229
230
/*
231
 * Convert 16-bit value from host byte order to network byte order.
232
 */
233
PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
234
0
{
235
0
    return htons(hostshort);
236
0
}
237
238
/*
239
 * Convert 32-bit value from network byte order to host byte order.
240
 */
241
PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
242
0
{
243
0
    return ntohl(netlong);
244
0
}
245
246
/*
247
 * Convert 32-bit value from host byte order to network byte order.
248
 */
249
PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
250
0
{
251
0
    return htonl(hostlong);
252
0
}
253
254
/*
255
 * Convert an Internet host address given in network byte order
256
 * to string in standard numbers and dots notation.
257
 */
258
PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
259
0
{
260
#if 0
261
    return inet_ntoa(*(struct in_addr*)&inaddr);
262
#else
263
0
    struct in_addr addr;
264
    //addr.s_addr = inaddr.s_addr;
265
0
    pj_memcpy(&addr, &inaddr, sizeof(addr));
266
0
    return inet_ntoa(addr);
267
0
#endif
268
0
}
269
270
/*
271
 * This function converts the Internet host address cp from the standard
272
 * numbers-and-dots notation into binary data and stores it in the structure
273
 * that inp points to. 
274
 */
275
PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, pj_in_addr *inp)
276
0
{
277
0
    char tempaddr[PJ_INET_ADDRSTRLEN];
278
279
    /* Initialize output with PJ_INADDR_NONE.
280
     * Some apps relies on this instead of the return value
281
     * (and anyway the return value is quite confusing!)
282
     */
283
0
    inp->s_addr = PJ_INADDR_NONE;
284
285
    /* Caution:
286
     *  this function might be called with cp->slen >= 16
287
     *  (i.e. when called with hostname to check if it's an IP addr).
288
     */
289
0
    PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
290
0
    if (cp->slen >= PJ_INET_ADDRSTRLEN) {
291
0
        return 0;
292
0
    }
293
294
0
    pj_memcpy(tempaddr, cp->ptr, cp->slen);
295
0
    tempaddr[cp->slen] = '\0';
296
297
0
#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
298
0
    return inet_aton(tempaddr, (struct in_addr*)inp);
299
#else
300
    inp->s_addr = inet_addr(tempaddr);
301
    return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
302
#endif
303
0
}
304
305
/*
306
 * Convert text to IPv4/IPv6 address.
307
 */
308
PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
309
0
{
310
0
    char tempaddr[PJ_INET6_ADDRSTRLEN];
311
312
0
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
313
0
    PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
314
315
    /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be 
316
     * compatible with pj_inet_aton()
317
     */
318
0
    if (af==PJ_AF_INET) {
319
0
        ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
320
0
    }
321
322
    /* Caution:
323
     *  this function might be called with cp->slen >= 46
324
     *  (i.e. when called with hostname to check if it's an IP addr).
325
     */
326
0
    if (src->slen >= PJ_INET6_ADDRSTRLEN) {
327
0
        return PJ_ENAMETOOLONG;
328
0
    }
329
330
0
    pj_memcpy(tempaddr, src->ptr, src->slen);
331
0
    tempaddr[src->slen] = '\0';
332
333
0
#if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
334
    /*
335
     * Implementation using inet_pton()
336
     */
337
0
    if (inet_pton(af, tempaddr, dst) != 1) {
338
0
        pj_status_t status = pj_get_netos_error();
339
0
        if (status == PJ_SUCCESS)
340
0
            status = PJ_EUNKNOWN;
341
342
0
        return status;
343
0
    }
344
345
0
    return PJ_SUCCESS;
346
347
#elif defined(PJ_WIN32) || defined(PJ_WIN64) || defined(PJ_WIN32_WINCE)
348
    /*
349
     * Implementation on Windows, using WSAStringToAddress().
350
     * Should also work on Unicode systems.
351
     */
352
    {
353
        PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
354
        pj_sockaddr sock_addr;
355
        int addr_len = sizeof(sock_addr);
356
        int rc;
357
358
        sock_addr.addr.sa_family = (pj_uint16_t)af;
359
        rc = WSAStringToAddress(
360
                PJ_STRING_TO_NATIVE(tempaddr,wtempaddr,sizeof(wtempaddr)), 
361
                af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
362
        if (rc != 0) {
363
            /* If you get rc 130022 Invalid argument (WSAEINVAL) with IPv6,
364
             * check that you have IPv6 enabled (install it in the network
365
             * adapter).
366
             */
367
            pj_status_t status = pj_get_netos_error();
368
            if (status == PJ_SUCCESS)
369
                status = PJ_EUNKNOWN;
370
371
            return status;
372
        }
373
374
        if (sock_addr.addr.sa_family == PJ_AF_INET) {
375
            pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
376
            return PJ_SUCCESS;
377
        } else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
378
            pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
379
            return PJ_SUCCESS;
380
        } else {
381
            pj_assert(!"Shouldn't happen");
382
            return PJ_EBUG;
383
        }
384
    }
385
#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
386
    /* IPv6 support is disabled, just return error without raising assertion */
387
    return PJ_EIPV6NOTSUP;
388
#else
389
    pj_assert(!"Not supported");
390
    return PJ_EIPV6NOTSUP;
391
#endif
392
0
}
393
394
/*
395
 * Convert IPv4/IPv6 address to text.
396
 */
397
PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
398
                                 char *dst, int size)
399
400
0
{
401
0
    PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
402
403
0
    *dst = '\0';
404
405
0
    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
406
407
0
#if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
408
    /*
409
     * Implementation using inet_ntop()
410
     */
411
0
    if (inet_ntop(af, src, dst, size) == NULL) {
412
0
        pj_status_t status = pj_get_netos_error();
413
0
        if (status == PJ_SUCCESS)
414
0
            status = PJ_EUNKNOWN;
415
416
0
        return status;
417
0
    }
418
419
0
    return PJ_SUCCESS;
420
421
#elif defined(PJ_WIN32) || defined(PJ_WIN64) || defined(PJ_WIN32_WINCE)
422
    /*
423
     * Implementation on Windows, using WSAAddressToString().
424
     * Should also work on Unicode systems.
425
     */
426
    {
427
        PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
428
        pj_sockaddr sock_addr;
429
        DWORD addr_len, addr_str_len;
430
        int rc;
431
432
        pj_bzero(&sock_addr, sizeof(sock_addr));
433
        sock_addr.addr.sa_family = (pj_uint16_t)af;
434
        if (af == PJ_AF_INET) {
435
            if (size < PJ_INET_ADDRSTRLEN)
436
                return PJ_ETOOSMALL;
437
            pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
438
            addr_len = sizeof(pj_sockaddr_in);
439
            addr_str_len = PJ_INET_ADDRSTRLEN;
440
        } else if (af == PJ_AF_INET6) {
441
            if (size < PJ_INET6_ADDRSTRLEN)
442
                return PJ_ETOOSMALL;
443
            pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
444
            addr_len = sizeof(pj_sockaddr_in6);
445
            addr_str_len = PJ_INET6_ADDRSTRLEN;
446
        } else {
447
            pj_assert(!"Unsupported address family");
448
            return PJ_EAFNOTSUP;
449
        }
450
451
#if PJ_NATIVE_STRING_IS_UNICODE
452
        rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
453
                                NULL, wtempaddr, &addr_str_len);
454
        if (rc == 0) {
455
            pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
456
        }
457
#else
458
        rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
459
                                NULL, dst, &addr_str_len);
460
#endif
461
462
        if (rc != 0) {
463
            pj_status_t status = pj_get_netos_error();
464
            if (status == PJ_SUCCESS)
465
                status = PJ_EUNKNOWN;
466
467
            return status;
468
        }
469
470
        return PJ_SUCCESS;
471
    }
472
473
#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
474
    /* IPv6 support is disabled, just return error without raising assertion */
475
    return PJ_EIPV6NOTSUP;
476
#else
477
    pj_assert(!"Not supported");
478
    return PJ_EIPV6NOTSUP;
479
#endif
480
0
}
481
482
/*
483
 * Get hostname.
484
 */
485
PJ_DEF(const pj_str_t*) pj_gethostname(void)
486
0
{
487
0
    static char buf[PJ_MAX_HOSTNAME];
488
0
    static pj_str_t hostname;
489
490
0
    PJ_CHECK_STACK();
491
492
0
    if (hostname.ptr == NULL) {
493
0
        hostname.ptr = buf;
494
0
        if (gethostname(buf, sizeof(buf)) != 0) {
495
0
            hostname.ptr[0] = '\0';
496
0
            hostname.slen = 0;
497
0
        } else {
498
0
            hostname.slen = strlen(buf);
499
0
        }
500
0
    }
501
0
    return &hostname;
502
0
}
503
504
#if defined(PJ_WIN32) || defined(PJ_WIN64)
505
/*
506
 * Create new socket/endpoint for communication and returns a descriptor.
507
 */
508
PJ_DEF(pj_status_t) pj_sock_socket(int af, 
509
                                   int type, 
510
                                   int proto,
511
                                   pj_sock_t *sock)
512
{
513
    PJ_CHECK_STACK();
514
515
    /* Sanity checks. */
516
    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
517
    PJ_ASSERT_RETURN((SOCKET)PJ_INVALID_SOCKET==INVALID_SOCKET, 
518
                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
519
520
    *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
521
522
    if (*sock == PJ_INVALID_SOCKET) 
523
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
524
    
525
#if PJ_SOCK_DISABLE_WSAECONNRESET && \
526
    (!defined(PJ_WIN32_WINCE) || PJ_WIN32_WINCE==0)
527
528
#ifndef SIO_UDP_CONNRESET
529
    #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
530
#endif
531
532
    /* Disable WSAECONNRESET for UDP.
533
     * See https://github.com/pjsip/pjproject/issues/1197
534
     */
535
    if (type==PJ_SOCK_DGRAM) {
536
        DWORD dwBytesReturned = 0;
537
        BOOL bNewBehavior = FALSE;
538
        DWORD rc;
539
540
        rc = WSAIoctl(*sock, SIO_UDP_CONNRESET,
541
                      &bNewBehavior, sizeof(bNewBehavior),
542
                      NULL, 0, &dwBytesReturned,
543
                      NULL, NULL);
544
545
        if (rc==SOCKET_ERROR) {
546
            // Ignored..
547
        }
548
    }
549
#endif
550
551
    return PJ_SUCCESS;
552
}
553
554
#else
555
/*
556
 * Create new socket/endpoint for communication and returns a descriptor.
557
 */
558
PJ_DEF(pj_status_t) pj_sock_socket(int af, 
559
                                   int type, 
560
                                   int proto, 
561
                                   pj_sock_t *sock)
562
0
{
563
0
    int type0 = type;
564
565
0
    PJ_CHECK_STACK();
566
567
    /* Sanity checks. */
568
0
    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
569
0
    PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1, 
570
0
                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
571
572
#if !defined(SOCK_CLOEXEC)
573
    if ((type0 & pj_SOCK_CLOEXEC()) == pj_SOCK_CLOEXEC())
574
        type &= ~pj_SOCK_CLOEXEC();
575
#else
576
0
    PJ_UNUSED_ARG(type0);
577
0
#endif
578
579
0
    *sock = socket(af, type, proto);
580
0
    TRACE_((THIS_FILE, "Created new socket of type %d: %ld", type, *sock));
581
0
    if (*sock == PJ_INVALID_SOCKET)
582
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
583
0
    else {
584
0
        pj_int32_t val = 1;
585
0
        if ((type & 0xF) == pj_SOCK_STREAM()) {
586
0
            pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_NOSIGPIPE(),
587
0
                               &val, sizeof(val));
588
0
        }
589
0
#if defined(PJ_SOCK_HAS_IPV6_V6ONLY) && PJ_SOCK_HAS_IPV6_V6ONLY != 0
590
0
        if (af == PJ_AF_INET6) {
591
0
            pj_sock_setsockopt(*sock, PJ_SOL_IPV6, IPV6_V6ONLY,
592
0
                               &val, sizeof(val));
593
0
        }
594
0
#endif
595
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
596
    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
597
        if ((type & 0xF) == pj_SOCK_DGRAM()) {
598
            pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), SO_NOSIGPIPE, 
599
                               &val, sizeof(val));
600
        }
601
#endif
602
603
#if !defined(SOCK_CLOEXEC)
604
        if ((type0 & pj_SOCK_CLOEXEC()) == pj_SOCK_CLOEXEC())
605
            pj_set_cloexec_flag((int)(*sock));
606
#endif
607
0
        return PJ_SUCCESS;
608
0
    }
609
0
}
610
#endif
611
612
/*
613
 * Bind socket.
614
 */
615
PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, 
616
                                  const pj_sockaddr_t *addr,
617
                                  int len)
618
0
{
619
0
    PJ_CHECK_STACK();
620
621
0
    PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL);
622
623
0
    CHECK_ADDR_LEN(addr, len);
624
625
0
    if (bind(sock, (struct sockaddr*)addr, len) != 0)
626
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
627
0
    else
628
0
        return PJ_SUCCESS;
629
0
}
630
631
632
/*
633
 * Bind socket.
634
 */
635
PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, 
636
                                     pj_uint32_t addr32,
637
                                     pj_uint16_t port)
638
0
{
639
0
    pj_sockaddr_in addr;
640
641
0
    PJ_CHECK_STACK();
642
643
0
    PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
644
0
    addr.sin_family = PJ_AF_INET;
645
0
    pj_bzero(addr.sin_zero_pad, sizeof(addr.sin_zero_pad));
646
0
    addr.sin_addr.s_addr = pj_htonl(addr32);
647
0
    addr.sin_port = pj_htons(port);
648
649
0
    return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
650
0
}
651
652
653
/*
654
 * Close socket.
655
 */
656
PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
657
0
{
658
0
    int rc;
659
660
0
    PJ_CHECK_STACK();
661
#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
662
    defined(PJ_WIN64) && PJ_WIN64 != 0 || \
663
    defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
664
    rc = closesocket(sock);
665
#else
666
0
    rc = close(sock);
667
0
#endif
668
669
0
    if (rc != 0)
670
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
671
0
    else
672
0
        return PJ_SUCCESS;
673
0
}
674
675
/*
676
 * Get remote's name.
677
 */
678
PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
679
                                         pj_sockaddr_t *addr,
680
                                         int *namelen)
681
0
{
682
0
    PJ_CHECK_STACK();
683
0
    if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
684
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
685
0
    else {
686
0
        PJ_SOCKADDR_RESET_LEN(addr);
687
0
        return PJ_SUCCESS;
688
0
    }
689
0
}
690
691
/*
692
 * Get socket name.
693
 */
694
PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
695
                                         pj_sockaddr_t *addr,
696
                                         int *namelen)
697
0
{
698
0
    PJ_CHECK_STACK();
699
0
    if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
700
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
701
0
    else {
702
0
        PJ_SOCKADDR_RESET_LEN(addr);
703
0
        return PJ_SUCCESS;
704
0
    }
705
0
}
706
707
/*
708
 * Send data
709
 */
710
PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
711
                                 const void *buf,
712
                                 pj_ssize_t *len,
713
                                 unsigned flags)
714
0
{
715
0
    PJ_CHECK_STACK();
716
0
    PJ_ASSERT_RETURN(len, PJ_EINVAL);
717
718
0
#ifdef MSG_NOSIGNAL
719
    /* Suppress SIGPIPE. See https://github.com/pjsip/pjproject/issues/1538 */
720
0
    flags |= MSG_NOSIGNAL;
721
0
#endif
722
723
0
    *len = send(sock, (const char*)buf, (int)(*len), flags);
724
725
0
    if (*len < 0)
726
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
727
0
    else
728
0
        return PJ_SUCCESS;
729
0
}
730
731
732
/*
733
 * Send data.
734
 */
735
PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
736
                                   const void *buf,
737
                                   pj_ssize_t *len,
738
                                   unsigned flags,
739
                                   const pj_sockaddr_t *to,
740
                                   int tolen)
741
0
{
742
0
    PJ_CHECK_STACK();
743
0
    PJ_ASSERT_RETURN(len, PJ_EINVAL);
744
    
745
0
    CHECK_ADDR_LEN(to, tolen);
746
747
0
#ifdef MSG_NOSIGNAL
748
    /* Suppress SIGPIPE. See https://github.com/pjsip/pjproject/issues/1538 */
749
0
    flags |= MSG_NOSIGNAL;
750
0
#endif
751
752
0
    *len = sendto(sock, (const char*)buf, (int)(*len), flags, 
753
0
                  (const struct sockaddr*)to, tolen);
754
755
0
    if (*len < 0) 
756
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
757
0
    else 
758
0
        return PJ_SUCCESS;
759
0
}
760
761
/*
762
 * Receive data.
763
 */
764
PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
765
                                 void *buf,
766
                                 pj_ssize_t *len,
767
                                 unsigned flags)
768
0
{
769
0
    PJ_CHECK_STACK();
770
0
    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
771
772
0
    *len = recv(sock, (char*)buf, (int)(*len), flags);
773
774
0
    if (*len < 0) 
775
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
776
0
    else
777
0
        return PJ_SUCCESS;
778
0
}
779
780
/*
781
 * Receive data.
782
 */
783
PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
784
                                     void *buf,
785
                                     pj_ssize_t *len,
786
                                     unsigned flags,
787
                                     pj_sockaddr_t *from,
788
                                     int *fromlen)
789
0
{
790
0
    PJ_CHECK_STACK();
791
0
    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
792
793
0
    *len = recvfrom(sock, (char*)buf, (int)(*len), flags, 
794
0
                    (struct sockaddr*)from, (socklen_t*)fromlen);
795
796
0
    if (*len < 0) 
797
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
798
0
    else {
799
0
        if (from) {
800
0
            PJ_SOCKADDR_RESET_LEN(from);
801
0
        }
802
0
        return PJ_SUCCESS;
803
0
    }
804
0
}
805
806
/*
807
 * Get socket option.
808
 */
809
PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
810
                                        pj_uint16_t level,
811
                                        pj_uint16_t optname,
812
                                        void *optval,
813
                                        int *optlen)
814
0
{
815
0
    PJ_CHECK_STACK();
816
0
    PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
817
818
0
    if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
819
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
820
0
    else
821
0
        return PJ_SUCCESS;
822
0
}
823
824
/*
825
 * Set socket option.
826
 */
827
PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
828
                                        pj_uint16_t level,
829
                                        pj_uint16_t optname,
830
                                        const void *optval,
831
                                        int optlen)
832
0
{
833
0
    int status;
834
0
    PJ_CHECK_STACK();
835
    
836
#if (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_SUNOS) && PJ_SUNOS)
837
    /* Some opt may still need int value (e.g:SO_EXCLUSIVEADDRUSE in win32). */
838
    status = setsockopt(sock, 
839
                     level, 
840
                     ((optname&0xff00)==0xff00)?(int)optname|0xffff0000:optname,                     
841
                     (const char*)optval, optlen);
842
#else
843
0
    status = setsockopt(sock, level, optname, (const char*)optval, optlen);
844
0
    TRACE_((THIS_FILE, "setsockopt %ld level:%d name:%d val:%d(%d)->%d", sock,
845
0
            level, optname, *((const char *)optval), optlen, status));
846
0
#endif
847
848
0
    if (status != 0)
849
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
850
0
    else
851
0
        return PJ_SUCCESS;
852
0
}
853
854
/*
855
 * Set socket option.
856
 */
857
PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd,
858
                                               const pj_sockopt_params *params)
859
0
{
860
0
    unsigned int i = 0;
861
0
    pj_status_t retval = PJ_SUCCESS;
862
0
    PJ_CHECK_STACK();
863
0
    PJ_ASSERT_RETURN(params, PJ_EINVAL);
864
    
865
0
    for (;i<params->cnt && i<PJ_MAX_SOCKOPT_PARAMS;++i) {
866
0
        pj_status_t status = pj_sock_setsockopt(sockfd, 
867
0
                                        (pj_uint16_t)params->options[i].level,
868
0
                                        (pj_uint16_t)params->options[i].optname,
869
0
                                        params->options[i].optval, 
870
0
                                        params->options[i].optlen);
871
0
        if (status != PJ_SUCCESS) {
872
0
            retval = status;
873
0
            PJ_PERROR(4,(THIS_FILE, status,
874
0
                         "Warning: error applying sock opt %d",
875
0
                         params->options[i].optname));
876
0
        }
877
0
    }
878
879
0
    return retval;
880
0
}
881
882
/*
883
 * Connect socket.
884
 */
885
PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
886
                                     const pj_sockaddr_t *addr,
887
                                     int namelen)
888
0
{
889
0
    PJ_CHECK_STACK();
890
0
    if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
891
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
892
0
    else
893
0
        return PJ_SUCCESS;
894
0
}
895
896
897
/*
898
 * Shutdown socket.
899
 */
900
#if PJ_HAS_TCP
901
PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
902
                                      int how)
903
0
{
904
0
    PJ_CHECK_STACK();
905
0
    if (shutdown(sock, how) != 0)
906
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
907
0
    else
908
0
        return PJ_SUCCESS;
909
0
}
910
911
/*
912
 * Start listening to incoming connections.
913
 */
914
PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
915
                                    int backlog)
916
0
{
917
0
    PJ_CHECK_STACK();
918
0
    if (listen(sock, backlog) != 0)
919
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
920
0
    else
921
0
        return PJ_SUCCESS;
922
0
}
923
924
/*
925
 * Accept incoming connections
926
 */
927
PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
928
                                    pj_sock_t *newsock,
929
                                    pj_sockaddr_t *addr,
930
                                    int *addrlen)
931
0
{
932
0
    PJ_CHECK_STACK();
933
0
    PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
934
935
#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
936
    if (addr) {
937
        PJ_SOCKADDR_SET_LEN(addr, *addrlen);
938
    }
939
#endif
940
    
941
0
    *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
942
0
    if (*newsock==PJ_INVALID_SOCKET)
943
0
        return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
944
0
    else {
945
        
946
#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
947
        if (addr) {
948
            PJ_SOCKADDR_RESET_LEN(addr);
949
        }
950
#endif
951
            
952
0
        return PJ_SUCCESS;
953
0
    }
954
0
}
955
#endif  /* PJ_HAS_TCP */
956
957