9bd0356f7dcf190a44f6b17ce81fde82e667c19a
[asterisk/asterisk.git] / res / pjproject / pjlib / src / pj / sock_bsd.c
1 /* $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  */
33 const pj_uint16_t PJ_AF_UNSPEC  = AF_UNSPEC;
34 const pj_uint16_t PJ_AF_UNIX    = AF_UNIX;
35 const pj_uint16_t PJ_AF_INET    = AF_INET;
36 const pj_uint16_t PJ_AF_INET6   = AF_INET6;
37 #ifdef AF_PACKET
38 const pj_uint16_t PJ_AF_PACKET  = AF_PACKET;
39 #else
40 const pj_uint16_t PJ_AF_PACKET  = 0xFFFF;
41 #endif
42 #ifdef AF_IRDA
43 const pj_uint16_t PJ_AF_IRDA    = AF_IRDA;
44 #else
45 const 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  */
52 const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
53 const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
54 const pj_uint16_t PJ_SOCK_RAW   = SOCK_RAW;
55 const pj_uint16_t PJ_SOCK_RDM   = SOCK_RDM;
56
57 /*
58  * Socket level values.
59  */
60 const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
61 #ifdef SOL_IP
62 const pj_uint16_t PJ_SOL_IP     = SOL_IP;
63 #elif defined(PJ_WIN32) && PJ_WIN32
64 const pj_uint16_t PJ_SOL_IP     = IPPROTO_IP;
65 #else
66 const pj_uint16_t PJ_SOL_IP     = 0;
67 #endif /* SOL_IP */
68
69 #if defined(SOL_TCP)
70 const pj_uint16_t PJ_SOL_TCP    = SOL_TCP;
71 #elif defined(IPPROTO_TCP)
72 const pj_uint16_t PJ_SOL_TCP    = IPPROTO_TCP;
73 #elif defined(PJ_WIN32) && PJ_WIN32
74 const pj_uint16_t PJ_SOL_TCP    = IPPROTO_TCP;
75 #else
76 const pj_uint16_t PJ_SOL_TCP    = 6;
77 #endif /* SOL_TCP */
78
79 #ifdef SOL_UDP
80 const pj_uint16_t PJ_SOL_UDP    = SOL_UDP;
81 #elif defined(IPPROTO_UDP)
82 const pj_uint16_t PJ_SOL_UDP    = IPPROTO_UDP;
83 #elif defined(PJ_WIN32) && PJ_WIN32
84 const pj_uint16_t PJ_SOL_UDP    = IPPROTO_UDP;
85 #else
86 const pj_uint16_t PJ_SOL_UDP    = 17;
87 #endif /* SOL_UDP */
88
89 #ifdef SOL_IPV6
90 const pj_uint16_t PJ_SOL_IPV6   = SOL_IPV6;
91 #elif defined(PJ_WIN32) && PJ_WIN32
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
98 const pj_uint16_t PJ_SOL_IPV6   = 41;
99 #endif /* SOL_IPV6 */
100
101 /* IP_TOS */
102 #ifdef IP_TOS
103 const pj_uint16_t PJ_IP_TOS     = IP_TOS;
104 #else
105 const pj_uint16_t PJ_IP_TOS     = 1;
106 #endif
107
108
109 /* TOS settings (declared in netinet/ip.h) */
110 #ifdef IPTOS_LOWDELAY
111 const pj_uint16_t PJ_IPTOS_LOWDELAY     = IPTOS_LOWDELAY;
112 #else
113 const pj_uint16_t PJ_IPTOS_LOWDELAY     = 0x10;
114 #endif
115 #ifdef IPTOS_THROUGHPUT
116 const pj_uint16_t PJ_IPTOS_THROUGHPUT   = IPTOS_THROUGHPUT;
117 #else
118 const pj_uint16_t PJ_IPTOS_THROUGHPUT   = 0x08;
119 #endif
120 #ifdef IPTOS_RELIABILITY
121 const pj_uint16_t PJ_IPTOS_RELIABILITY  = IPTOS_RELIABILITY;
122 #else
123 const pj_uint16_t PJ_IPTOS_RELIABILITY  = 0x04;
124 #endif
125 #ifdef IPTOS_MINCOST
126 const pj_uint16_t PJ_IPTOS_MINCOST      = IPTOS_MINCOST;
127 #else
128 const pj_uint16_t PJ_IPTOS_MINCOST      = 0x02;
129 #endif
130
131
132 /* optname values. */
133 const pj_uint16_t PJ_SO_TYPE    = SO_TYPE;
134 const pj_uint16_t PJ_SO_RCVBUF  = SO_RCVBUF;
135 const pj_uint16_t PJ_SO_SNDBUF  = SO_SNDBUF;
136 const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
137 const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
138 #ifdef SO_NOSIGPIPE
139 const pj_uint16_t PJ_SO_NOSIGPIPE = SO_NOSIGPIPE;
140 #else
141 const pj_uint16_t PJ_SO_NOSIGPIPE = 0xFFFF;
142 #endif
143 #if defined(SO_PRIORITY)
144 const pj_uint16_t PJ_SO_PRIORITY = SO_PRIORITY;
145 #else
146 /* This is from Linux, YMMV */
147 const 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
152 const pj_uint16_t PJ_IP_MULTICAST_IF    = IP_MULTICAST_IF;
153 const pj_uint16_t PJ_IP_MULTICAST_TTL   = IP_MULTICAST_TTL;
154 const pj_uint16_t PJ_IP_MULTICAST_LOOP  = IP_MULTICAST_LOOP;
155 const pj_uint16_t PJ_IP_ADD_MEMBERSHIP  = IP_ADD_MEMBERSHIP;
156 const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
157 #else
158 const pj_uint16_t PJ_IP_MULTICAST_IF    = 0xFFFF;
159 const pj_uint16_t PJ_IP_MULTICAST_TTL   = 0xFFFF;
160 const pj_uint16_t PJ_IP_MULTICAST_LOOP  = 0xFFFF;
161 const pj_uint16_t PJ_IP_ADD_MEMBERSHIP  = 0xFFFF;
162 const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
163 #endif
164
165 /* recv() and send() flags */
166 const int PJ_MSG_OOB            = MSG_OOB;
167 const int PJ_MSG_PEEK           = MSG_PEEK;
168 const int PJ_MSG_DONTROUTE      = MSG_DONTROUTE;
169
170
171 #if 0
172 static 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  */
186 PJ_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  */
194 PJ_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  */
202 PJ_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  */
210 PJ_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  */
219 PJ_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  */
235 PJ_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  */
268 PJ_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_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  */
357 PJ_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_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  */
445 PJ_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)
465 /*
466  * Create new socket/endpoint for communication and returns a descriptor.
467  */
468 PJ_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((unsigned)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  */
518 PJ_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  */
555 PJ_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  */
575 PJ_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  */
596 PJ_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_WIN32_WINCE) && PJ_WIN32_WINCE!=0
603     rc = closesocket(sock);
604 #else
605     rc = close(sock);
606 #endif
607
608     if (rc != 0)
609         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
610     else
611         return PJ_SUCCESS;
612 }
613
614 /*
615  * Get remote's name.
616  */
617 PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
618                                          pj_sockaddr_t *addr,
619                                          int *namelen)
620 {
621     PJ_CHECK_STACK();
622     if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
623         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
624     else {
625         PJ_SOCKADDR_RESET_LEN(addr);
626         return PJ_SUCCESS;
627     }
628 }
629
630 /*
631  * Get socket name.
632  */
633 PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
634                                          pj_sockaddr_t *addr,
635                                          int *namelen)
636 {
637     PJ_CHECK_STACK();
638     if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
639         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
640     else {
641         PJ_SOCKADDR_RESET_LEN(addr);
642         return PJ_SUCCESS;
643     }
644 }
645
646 /*
647  * Send data
648  */
649 PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
650                                  const void *buf,
651                                  pj_ssize_t *len,
652                                  unsigned flags)
653 {
654     PJ_CHECK_STACK();
655     PJ_ASSERT_RETURN(len, PJ_EINVAL);
656
657     *len = send(sock, (const char*)buf, *len, flags);
658
659     if (*len < 0)
660         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
661     else
662         return PJ_SUCCESS;
663 }
664
665
666 /*
667  * Send data.
668  */
669 PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
670                                    const void *buf,
671                                    pj_ssize_t *len,
672                                    unsigned flags,
673                                    const pj_sockaddr_t *to,
674                                    int tolen)
675 {
676     PJ_CHECK_STACK();
677     PJ_ASSERT_RETURN(len, PJ_EINVAL);
678     
679     CHECK_ADDR_LEN(to, tolen);
680
681     *len = sendto(sock, (const char*)buf, *len, flags, 
682                   (const struct sockaddr*)to, tolen);
683
684     if (*len < 0) 
685         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
686     else 
687         return PJ_SUCCESS;
688 }
689
690 /*
691  * Receive data.
692  */
693 PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
694                                  void *buf,
695                                  pj_ssize_t *len,
696                                  unsigned flags)
697 {
698     PJ_CHECK_STACK();
699     PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
700
701     *len = recv(sock, (char*)buf, *len, flags);
702
703     if (*len < 0) 
704         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
705     else
706         return PJ_SUCCESS;
707 }
708
709 /*
710  * Receive data.
711  */
712 PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
713                                      void *buf,
714                                      pj_ssize_t *len,
715                                      unsigned flags,
716                                      pj_sockaddr_t *from,
717                                      int *fromlen)
718 {
719     PJ_CHECK_STACK();
720     PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
721     PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
722
723     *len = recvfrom(sock, (char*)buf, *len, flags, 
724                     (struct sockaddr*)from, (socklen_t*)fromlen);
725
726     if (*len < 0) 
727         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
728     else {
729         PJ_SOCKADDR_RESET_LEN(from);
730         return PJ_SUCCESS;
731     }
732 }
733
734 /*
735  * Get socket option.
736  */
737 PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
738                                         pj_uint16_t level,
739                                         pj_uint16_t optname,
740                                         void *optval,
741                                         int *optlen)
742 {
743     PJ_CHECK_STACK();
744     PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
745
746     if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
747         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
748     else
749         return PJ_SUCCESS;
750 }
751
752 /*
753  * Set socket option.
754  */
755 PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
756                                         pj_uint16_t level,
757                                         pj_uint16_t optname,
758                                         const void *optval,
759                                         int optlen)
760 {
761     PJ_CHECK_STACK();
762     if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
763         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
764     else
765         return PJ_SUCCESS;
766 }
767
768 /*
769  * Connect socket.
770  */
771 PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
772                                      const pj_sockaddr_t *addr,
773                                      int namelen)
774 {
775     PJ_CHECK_STACK();
776     if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
777         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
778     else
779         return PJ_SUCCESS;
780 }
781
782
783 /*
784  * Shutdown socket.
785  */
786 #if PJ_HAS_TCP
787 PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
788                                       int how)
789 {
790     PJ_CHECK_STACK();
791     if (shutdown(sock, how) != 0)
792         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
793     else
794         return PJ_SUCCESS;
795 }
796
797 /*
798  * Start listening to incoming connections.
799  */
800 PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
801                                     int backlog)
802 {
803     PJ_CHECK_STACK();
804     if (listen(sock, backlog) != 0)
805         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
806     else
807         return PJ_SUCCESS;
808 }
809
810 /*
811  * Accept incoming connections
812  */
813 PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
814                                     pj_sock_t *newsock,
815                                     pj_sockaddr_t *addr,
816                                     int *addrlen)
817 {
818     PJ_CHECK_STACK();
819     PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
820
821 #if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
822     if (addr) {
823         PJ_SOCKADDR_SET_LEN(addr, *addrlen);
824     }
825 #endif
826     
827     *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
828     if (*newsock==PJ_INVALID_SOCKET)
829         return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
830     else {
831         
832 #if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
833         if (addr) {
834             PJ_SOCKADDR_RESET_LEN(addr);
835         }
836 #endif
837             
838         return PJ_SUCCESS;
839     }
840 }
841 #endif  /* PJ_HAS_TCP */
842
843