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