blob: aef2ff8a6c0d16233ae77d0d69235f10dee6512d [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00005 *
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>
Benny Prijonoc16c6e32007-11-18 14:53:47 +000027#include <pj/unicode.h>
Benny Prijono9033e312005-11-21 02:08:39 +000028
29/*
30 * Address families conversion.
Benny Prijono42c5b9e2006-05-10 19:24:40 +000031 * The values here are indexed based on pj_addr_family.
Benny Prijono9033e312005-11-21 02:08:39 +000032 */
Benny Prijonoc16c6e32007-11-18 14:53:47 +000033const pj_uint16_t PJ_AF_UNSPEC = AF_UNSPEC;
Benny Prijono9033e312005-11-21 02:08:39 +000034const 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.
Benny Prijono42c5b9e2006-05-10 19:24:40 +000050 * The values here are indexed based on pj_sock_type
Benny Prijono9033e312005-11-21 02:08:39 +000051 */
Benny Prijono87a00892007-02-01 00:33:12 +000052const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
Benny Prijono9033e312005-11-21 02:08:39 +000053const 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;
Benny Prijonodb04cd52009-10-15 03:48:20 +000063#elif defined(PJ_WIN32) && PJ_WIN32
64const pj_uint16_t PJ_SOL_IP = IPPROTO_IP;
Benny Prijono9033e312005-11-21 02:08:39 +000065#else
Benny Prijono4d79b0f2009-10-25 09:02:07 +000066const pj_uint16_t PJ_SOL_IP = 0;
Benny Prijono9033e312005-11-21 02:08:39 +000067#endif /* SOL_IP */
Benny Prijonodb04cd52009-10-15 03:48:20 +000068
Benny Prijono9033e312005-11-21 02:08:39 +000069#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;
Benny Prijonodb04cd52009-10-15 03:48:20 +000073#elif defined(PJ_WIN32) && PJ_WIN32
74const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
Benny Prijono0de9e2b2007-10-21 11:49:48 +000075#else
Benny Prijono4d79b0f2009-10-25 09:02:07 +000076const pj_uint16_t PJ_SOL_TCP = 6;
Benny Prijono9033e312005-11-21 02:08:39 +000077#endif /* SOL_TCP */
Benny Prijonodb04cd52009-10-15 03:48:20 +000078
Benny Prijono9033e312005-11-21 02:08:39 +000079#ifdef SOL_UDP
80const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
Benny Prijono78531d72009-10-24 02:18:27 +000081#elif defined(IPPROTO_UDP)
82const pj_uint16_t PJ_SOL_UDP = IPPROTO_UDP;
Benny Prijonodb04cd52009-10-15 03:48:20 +000083#elif defined(PJ_WIN32) && PJ_WIN32
84const pj_uint16_t PJ_SOL_UDP = IPPROTO_UDP;
Benny Prijono9033e312005-11-21 02:08:39 +000085#else
Benny Prijono4d79b0f2009-10-25 09:02:07 +000086const pj_uint16_t PJ_SOL_UDP = 17;
Benny Prijonodb04cd52009-10-15 03:48:20 +000087#endif /* SOL_UDP */
88
Benny Prijono9033e312005-11-21 02:08:39 +000089#ifdef SOL_IPV6
90const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
Benny Prijonodb04cd52009-10-15 03:48:20 +000091#elif defined(PJ_WIN32) && PJ_WIN32
Benny Prijono72748d02009-10-20 01:24:42 +000092# 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
Benny Prijono9033e312005-11-21 02:08:39 +000097#else
Benny Prijono4d79b0f2009-10-25 09:02:07 +000098const pj_uint16_t PJ_SOL_IPV6 = 41;
Benny Prijonodb04cd52009-10-15 03:48:20 +000099#endif /* SOL_IPV6 */
Benny Prijono9033e312005-11-21 02:08:39 +0000100
Benny Prijono87a00892007-02-01 00:33:12 +0000101/* 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
Benny Prijono9033e312005-11-21 02:08:39 +0000132/* 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;
Benny Prijonodb04cd52009-10-15 03:48:20 +0000136const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
137const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
Benny Prijono4d79b0f2009-10-25 09:02:07 +0000138#if defined(SO_PRIORITY)
139const pj_uint16_t PJ_SO_PRIORITY = SO_PRIORITY;
140#else
141/* This is from Linux, YMMV */
142const pj_uint16_t PJ_SO_PRIORITY = 12;
143#endif
Benny Prijonodb04cd52009-10-15 03:48:20 +0000144
Benny Prijonoe2746132008-09-27 13:16:35 +0000145/* Multicasting is not supported e.g. in PocketPC 2003 SDK */
146#ifdef IP_MULTICAST_IF
Benny Prijono513d1352008-09-27 09:35:34 +0000147const pj_uint16_t PJ_IP_MULTICAST_IF = IP_MULTICAST_IF;
148const pj_uint16_t PJ_IP_MULTICAST_TTL = IP_MULTICAST_TTL;
149const pj_uint16_t PJ_IP_MULTICAST_LOOP = IP_MULTICAST_LOOP;
150const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = IP_ADD_MEMBERSHIP;
151const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
Benny Prijonoe2746132008-09-27 13:16:35 +0000152#else
153const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
154const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
155const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
156const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
157const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
158#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000159
Benny Prijono57dc48b2006-12-25 06:39:33 +0000160/* recv() and send() flags */
161const int PJ_MSG_OOB = MSG_OOB;
162const int PJ_MSG_PEEK = MSG_PEEK;
163const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
164
165
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000166#if 0
167static void CHECK_ADDR_LEN(const pj_sockaddr *addr, int len)
168{
169 pj_sockaddr *a = (pj_sockaddr*)addr;
170 pj_assert((a->addr.sa_family==PJ_AF_INET && len==sizeof(pj_sockaddr_in)) ||
171 (a->addr.sa_family==PJ_AF_INET6 && len==sizeof(pj_sockaddr_in6)));
172
173}
174#else
175#define CHECK_ADDR_LEN(addr,len)
176#endif
177
Benny Prijono9033e312005-11-21 02:08:39 +0000178/*
179 * Convert 16-bit value from network byte order to host byte order.
180 */
181PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
182{
183 return ntohs(netshort);
184}
185
186/*
187 * Convert 16-bit value from host byte order to network byte order.
188 */
189PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
190{
191 return htons(hostshort);
192}
193
194/*
195 * Convert 32-bit value from network byte order to host byte order.
196 */
197PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
198{
199 return ntohl(netlong);
200}
201
202/*
203 * Convert 32-bit value from host byte order to network byte order.
204 */
205PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
206{
207 return htonl(hostlong);
208}
209
210/*
211 * Convert an Internet host address given in network byte order
212 * to string in standard numbers and dots notation.
213 */
214PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
215{
216#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
217 return inet_ntoa(*(struct in_addr*)&inaddr);
218#else
219 struct in_addr addr;
220 addr.s_addr = inaddr.s_addr;
221 return inet_ntoa(addr);
222#endif
223}
224
225/*
226 * This function converts the Internet host address cp from the standard
227 * numbers-and-dots notation into binary data and stores it in the structure
228 * that inp points to.
229 */
230PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
231{
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000232 char tempaddr[PJ_INET_ADDRSTRLEN];
Benny Prijono9033e312005-11-21 02:08:39 +0000233
234 /* Initialize output with PJ_INADDR_NONE.
235 * Some apps relies on this instead of the return value
236 * (and anyway the return value is quite confusing!)
237 */
238 inp->s_addr = PJ_INADDR_NONE;
239
240 /* Caution:
241 * this function might be called with cp->slen >= 16
242 * (i.e. when called with hostname to check if it's an IP addr).
243 */
244 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000245 if (cp->slen >= PJ_INET_ADDRSTRLEN) {
Benny Prijono9033e312005-11-21 02:08:39 +0000246 return 0;
247 }
248
249 pj_memcpy(tempaddr, cp->ptr, cp->slen);
250 tempaddr[cp->slen] = '\0';
251
252#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
253 return inet_aton(tempaddr, (struct in_addr*)inp);
254#else
255 inp->s_addr = inet_addr(tempaddr);
256 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
257#endif
258}
259
260/*
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000261 * Convert text to IPv4/IPv6 address.
262 */
263PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
264{
265 char tempaddr[PJ_INET6_ADDRSTRLEN];
266
Benny Prijono62b86eb2007-12-01 08:52:57 +0000267 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000268 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
269
270 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
271 * compatible with pj_inet_aton()
272 */
273 if (af==PJ_AF_INET) {
274 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
275 }
276
277 /* Caution:
278 * this function might be called with cp->slen >= 46
279 * (i.e. when called with hostname to check if it's an IP addr).
280 */
281 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
282 return PJ_ENAMETOOLONG;
283 }
284
285 pj_memcpy(tempaddr, src->ptr, src->slen);
286 tempaddr[src->slen] = '\0';
287
288#if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
289 /*
290 * Implementation using inet_pton()
291 */
292 if (inet_pton(af, tempaddr, dst) != 1) {
293 pj_status_t status = pj_get_netos_error();
294 if (status == PJ_SUCCESS)
295 status = PJ_EUNKNOWN;
296
297 return status;
298 }
299
300 return PJ_SUCCESS;
301
302#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
303 /*
304 * Implementation on Windows, using WSAStringToAddress().
305 * Should also work on Unicode systems.
306 */
307 {
308 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
309 pj_sockaddr sock_addr;
310 int addr_len = sizeof(sock_addr);
311 int rc;
312
313 sock_addr.addr.sa_family = (pj_uint16_t)af;
314 rc = WSAStringToAddress(
315 PJ_STRING_TO_NATIVE(tempaddr,wtempaddr,sizeof(wtempaddr)),
316 af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
317 if (rc != 0) {
Benny Prijonoa199cb72008-12-19 14:36:08 +0000318 /* If you get rc 130022 Invalid argument (WSAEINVAL) with IPv6,
319 * check that you have IPv6 enabled (install it in the network
320 * adapter).
321 */
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000322 pj_status_t status = pj_get_netos_error();
323 if (status == PJ_SUCCESS)
324 status = PJ_EUNKNOWN;
325
326 return status;
327 }
328
329 if (sock_addr.addr.sa_family == PJ_AF_INET) {
330 pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
331 return PJ_SUCCESS;
332 } else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
333 pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
334 return PJ_SUCCESS;
335 } else {
336 pj_assert(!"Shouldn't happen");
337 return PJ_EBUG;
338 }
339 }
340#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
341 /* IPv6 support is disabled, just return error without raising assertion */
342 return PJ_EIPV6NOTSUP;
343#else
344 pj_assert(!"Not supported");
345 return PJ_EIPV6NOTSUP;
346#endif
347}
348
349/*
350 * Convert IPv4/IPv6 address to text.
351 */
352PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
353 char *dst, int size)
354
355{
356 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
Benny Prijono444ef3f2007-11-20 09:47:32 +0000357
358 *dst = '\0';
359
Benny Prijono62b86eb2007-12-01 08:52:57 +0000360 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000361
362#if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
363 /*
364 * Implementation using inet_ntop()
365 */
366 if (inet_ntop(af, src, dst, size) == NULL) {
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 return PJ_SUCCESS;
375
376#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
377 /*
378 * Implementation on Windows, using WSAAddressToString().
379 * Should also work on Unicode systems.
380 */
381 {
382 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
383 pj_sockaddr sock_addr;
384 DWORD addr_len, addr_str_len;
385 int rc;
386
387 pj_bzero(&sock_addr, sizeof(sock_addr));
388 sock_addr.addr.sa_family = (pj_uint16_t)af;
389 if (af == PJ_AF_INET) {
390 if (size < PJ_INET_ADDRSTRLEN)
391 return PJ_ETOOSMALL;
392 pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
393 addr_len = sizeof(pj_sockaddr_in);
394 addr_str_len = PJ_INET_ADDRSTRLEN;
395 } else if (af == PJ_AF_INET6) {
396 if (size < PJ_INET6_ADDRSTRLEN)
397 return PJ_ETOOSMALL;
398 pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
399 addr_len = sizeof(pj_sockaddr_in6);
400 addr_str_len = PJ_INET6_ADDRSTRLEN;
401 } else {
402 pj_assert(!"Unsupported address family");
Benny Prijono62b86eb2007-12-01 08:52:57 +0000403 return PJ_EAFNOTSUP;
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000404 }
405
406#if PJ_NATIVE_STRING_IS_UNICODE
407 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
Benny Prijonoab872f22008-01-04 17:56:28 +0000408 NULL, wtempaddr, &addr_str_len);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000409 if (rc == 0) {
410 pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
411 }
412#else
413 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
414 NULL, dst, &addr_str_len);
415#endif
416
417 if (rc != 0) {
418 pj_status_t status = pj_get_netos_error();
419 if (status == PJ_SUCCESS)
420 status = PJ_EUNKNOWN;
421
422 return status;
423 }
424
425 return PJ_SUCCESS;
426 }
427
428#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
429 /* IPv6 support is disabled, just return error without raising assertion */
430 return PJ_EIPV6NOTSUP;
431#else
432 pj_assert(!"Not supported");
433 return PJ_EIPV6NOTSUP;
434#endif
435}
436
437/*
Benny Prijono9033e312005-11-21 02:08:39 +0000438 * Get hostname.
439 */
440PJ_DEF(const pj_str_t*) pj_gethostname(void)
441{
442 static char buf[PJ_MAX_HOSTNAME];
443 static pj_str_t hostname;
444
445 PJ_CHECK_STACK();
446
447 if (hostname.ptr == NULL) {
448 hostname.ptr = buf;
449 if (gethostname(buf, sizeof(buf)) != 0) {
450 hostname.ptr[0] = '\0';
451 hostname.slen = 0;
452 } else {
Sauw Mingd39818b2010-07-15 13:32:11 +0000453 hostname.slen = strlen(buf);
454#if defined(PJ_GETHOSTNAME_APPEND_LOCAL_SUFFIX) && \
455 PJ_GETHOSTNAME_APPEND_LOCAL_SUFFIX!=0
456 {
457 const pj_str_t suffix = {".local", 6};
458
459 if (hostname.slen < suffix.slen ||
460 pj_ansi_strnicmp(hostname.ptr + hostname.slen -
461 suffix.slen, suffix.ptr, suffix.slen))
462 {
463 if (hostname.slen + suffix.slen + 1 < sizeof(buf))
464 pj_strcat(&hostname, &suffix);
465 else
466 hostname.slen = 0;
467 hostname.ptr[hostname.slen] = '\0';
468 }
469 }
470#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000471 }
472 }
473 return &hostname;
474}
475
Benny Prijono9033e312005-11-21 02:08:39 +0000476#if defined(PJ_WIN32)
477/*
478 * Create new socket/endpoint for communication and returns a descriptor.
479 */
480PJ_DEF(pj_status_t) pj_sock_socket(int af,
481 int type,
482 int proto,
483 pj_sock_t *sock)
484{
485 PJ_CHECK_STACK();
486
487 /* Sanity checks. */
488 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
489 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
490 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
491
492 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
493
494 if (*sock == PJ_INVALID_SOCKET)
495 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
496 else
497 return PJ_SUCCESS;
498}
499
500#else
501/*
502 * Create new socket/endpoint for communication and returns a descriptor.
503 */
504PJ_DEF(pj_status_t) pj_sock_socket(int af,
505 int type,
506 int proto,
507 pj_sock_t *sock)
508{
509
510 PJ_CHECK_STACK();
511
512 /* Sanity checks. */
513 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
514 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
515 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
Sauw Mingbe3771a2010-08-27 06:46:29 +0000516
Benny Prijono9033e312005-11-21 02:08:39 +0000517 *sock = socket(af, type, proto);
518 if (*sock == PJ_INVALID_SOCKET)
519 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Sauw Mingbe3771a2010-08-27 06:46:29 +0000520 else {
521#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
522 PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
523 pj_int32_t val = 1;
524 if (type == pj_SOCK_DGRAM()) {
525 pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), SO_NOSIGPIPE,
526 &val, sizeof(val));
527 }
528#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000529 return PJ_SUCCESS;
Sauw Mingbe3771a2010-08-27 06:46:29 +0000530 }
Benny Prijono9033e312005-11-21 02:08:39 +0000531}
532#endif
533
Benny Prijono9033e312005-11-21 02:08:39 +0000534/*
535 * Bind socket.
536 */
537PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
538 const pj_sockaddr_t *addr,
539 int len)
540{
541 PJ_CHECK_STACK();
542
Benny Prijonoa1e69682007-05-11 15:14:34 +0000543 PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000544
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000545 CHECK_ADDR_LEN(addr, len);
546
Benny Prijono9033e312005-11-21 02:08:39 +0000547 if (bind(sock, (struct sockaddr*)addr, len) != 0)
548 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
549 else
550 return PJ_SUCCESS;
551}
552
553
554/*
555 * Bind socket.
556 */
557PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
558 pj_uint32_t addr32,
559 pj_uint16_t port)
560{
561 pj_sockaddr_in addr;
562
563 PJ_CHECK_STACK();
564
Benny Prijono62b86eb2007-12-01 08:52:57 +0000565 PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
Benny Prijono9033e312005-11-21 02:08:39 +0000566 addr.sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000567 pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000568 addr.sin_addr.s_addr = pj_htonl(addr32);
569 addr.sin_port = pj_htons(port);
570
571 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
572}
573
574
575/*
576 * Close socket.
577 */
578PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
579{
580 int rc;
581
582 PJ_CHECK_STACK();
Benny Prijono9cf138e2006-01-19 03:58:29 +0000583#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
584 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000585 rc = closesocket(sock);
586#else
587 rc = close(sock);
588#endif
589
590 if (rc != 0)
591 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
592 else
593 return PJ_SUCCESS;
594}
595
596/*
597 * Get remote's name.
598 */
599PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
600 pj_sockaddr_t *addr,
601 int *namelen)
602{
603 PJ_CHECK_STACK();
604 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
605 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000606 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000607 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000608 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000609 }
Benny Prijono9033e312005-11-21 02:08:39 +0000610}
611
612/*
613 * Get socket name.
614 */
615PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
616 pj_sockaddr_t *addr,
617 int *namelen)
618{
619 PJ_CHECK_STACK();
620 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
621 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000622 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000623 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000624 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000625 }
Benny Prijono9033e312005-11-21 02:08:39 +0000626}
627
628/*
629 * Send data
630 */
631PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
632 const void *buf,
633 pj_ssize_t *len,
634 unsigned flags)
635{
636 PJ_CHECK_STACK();
637 PJ_ASSERT_RETURN(len, PJ_EINVAL);
638
639 *len = send(sock, (const char*)buf, *len, flags);
640
641 if (*len < 0)
642 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
643 else
644 return PJ_SUCCESS;
645}
646
647
648/*
649 * Send data.
650 */
651PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
652 const void *buf,
653 pj_ssize_t *len,
654 unsigned flags,
655 const pj_sockaddr_t *to,
656 int tolen)
657{
658 PJ_CHECK_STACK();
659 PJ_ASSERT_RETURN(len, PJ_EINVAL);
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000660
661 CHECK_ADDR_LEN(to, tolen);
Benny Prijono9033e312005-11-21 02:08:39 +0000662
663 *len = sendto(sock, (const char*)buf, *len, flags,
664 (const struct sockaddr*)to, tolen);
665
666 if (*len < 0)
667 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
668 else
669 return PJ_SUCCESS;
670}
671
672/*
673 * Receive data.
674 */
675PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
676 void *buf,
677 pj_ssize_t *len,
678 unsigned flags)
679{
680 PJ_CHECK_STACK();
681 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
682
683 *len = recv(sock, (char*)buf, *len, flags);
684
685 if (*len < 0)
686 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
687 else
688 return PJ_SUCCESS;
689}
690
691/*
692 * Receive data.
693 */
694PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
695 void *buf,
696 pj_ssize_t *len,
697 unsigned flags,
698 pj_sockaddr_t *from,
699 int *fromlen)
700{
701 PJ_CHECK_STACK();
702 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
703 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
704
705 *len = recvfrom(sock, (char*)buf, *len, flags,
706 (struct sockaddr*)from, (socklen_t*)fromlen);
707
708 if (*len < 0)
709 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000710 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000711 PJ_SOCKADDR_RESET_LEN(from);
Benny Prijono9033e312005-11-21 02:08:39 +0000712 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000713 }
Benny Prijono9033e312005-11-21 02:08:39 +0000714}
715
716/*
717 * Get socket option.
718 */
719PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
720 pj_uint16_t level,
721 pj_uint16_t optname,
722 void *optval,
723 int *optlen)
724{
725 PJ_CHECK_STACK();
726 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
727
728 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
729 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
730 else
731 return PJ_SUCCESS;
732}
733
734/*
735 * Set socket option.
736 */
737PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
738 pj_uint16_t level,
739 pj_uint16_t optname,
740 const void *optval,
741 int optlen)
742{
743 PJ_CHECK_STACK();
744 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
745 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
746 else
747 return PJ_SUCCESS;
748}
749
750/*
Benny Prijono3d327302006-02-08 11:14:03 +0000751 * Connect socket.
752 */
753PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
754 const pj_sockaddr_t *addr,
755 int namelen)
756{
757 PJ_CHECK_STACK();
758 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
759 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
760 else
761 return PJ_SUCCESS;
762}
763
764
765/*
Benny Prijono9033e312005-11-21 02:08:39 +0000766 * Shutdown socket.
767 */
768#if PJ_HAS_TCP
769PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
770 int how)
771{
772 PJ_CHECK_STACK();
773 if (shutdown(sock, how) != 0)
774 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
775 else
776 return PJ_SUCCESS;
777}
778
779/*
780 * Start listening to incoming connections.
781 */
782PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
783 int backlog)
784{
785 PJ_CHECK_STACK();
786 if (listen(sock, backlog) != 0)
787 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
788 else
789 return PJ_SUCCESS;
790}
791
792/*
Benny Prijono9033e312005-11-21 02:08:39 +0000793 * Accept incoming connections
794 */
795PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
796 pj_sock_t *newsock,
797 pj_sockaddr_t *addr,
798 int *addrlen)
799{
800 PJ_CHECK_STACK();
801 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
802
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000803#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
804 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000805 PJ_SOCKADDR_SET_LEN(addr, *addrlen);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000806 }
807#endif
808
Benny Prijono9033e312005-11-21 02:08:39 +0000809 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
810 if (*newsock==PJ_INVALID_SOCKET)
811 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000812 else {
813
814#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
815 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000816 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000817 }
818#endif
819
Benny Prijono9033e312005-11-21 02:08:39 +0000820 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000821 }
Benny Prijono9033e312005-11-21 02:08:39 +0000822}
823#endif /* PJ_HAS_TCP */
824
825