blob: 36761bce3c722bd58f5867551b7ca47b19ca691a [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 {
453 hostname.slen = strlen(buf);
454 }
455 }
456 return &hostname;
457}
458
Benny Prijono9033e312005-11-21 02:08:39 +0000459#if defined(PJ_WIN32)
460/*
461 * Create new socket/endpoint for communication and returns a descriptor.
462 */
463PJ_DEF(pj_status_t) pj_sock_socket(int af,
464 int type,
465 int proto,
466 pj_sock_t *sock)
467{
468 PJ_CHECK_STACK();
469
470 /* Sanity checks. */
471 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
472 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
473 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
474
475 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
476
477 if (*sock == PJ_INVALID_SOCKET)
478 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
479 else
480 return PJ_SUCCESS;
481}
482
483#else
484/*
485 * Create new socket/endpoint for communication and returns a descriptor.
486 */
487PJ_DEF(pj_status_t) pj_sock_socket(int af,
488 int type,
489 int proto,
490 pj_sock_t *sock)
491{
492
493 PJ_CHECK_STACK();
494
495 /* Sanity checks. */
496 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
497 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
498 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
499
500 *sock = socket(af, type, proto);
501 if (*sock == PJ_INVALID_SOCKET)
502 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
503 else
504 return PJ_SUCCESS;
505}
506#endif
507
Benny Prijono9033e312005-11-21 02:08:39 +0000508/*
509 * Bind socket.
510 */
511PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
512 const pj_sockaddr_t *addr,
513 int len)
514{
515 PJ_CHECK_STACK();
516
Benny Prijonoa1e69682007-05-11 15:14:34 +0000517 PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000518
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000519 CHECK_ADDR_LEN(addr, len);
520
Benny Prijono9033e312005-11-21 02:08:39 +0000521 if (bind(sock, (struct sockaddr*)addr, len) != 0)
522 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
523 else
524 return PJ_SUCCESS;
525}
526
527
528/*
529 * Bind socket.
530 */
531PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
532 pj_uint32_t addr32,
533 pj_uint16_t port)
534{
535 pj_sockaddr_in addr;
536
537 PJ_CHECK_STACK();
538
Benny Prijono62b86eb2007-12-01 08:52:57 +0000539 PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
Benny Prijono9033e312005-11-21 02:08:39 +0000540 addr.sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000541 pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000542 addr.sin_addr.s_addr = pj_htonl(addr32);
543 addr.sin_port = pj_htons(port);
544
545 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
546}
547
548
549/*
550 * Close socket.
551 */
552PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
553{
554 int rc;
555
556 PJ_CHECK_STACK();
Benny Prijono9cf138e2006-01-19 03:58:29 +0000557#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
558 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000559 rc = closesocket(sock);
560#else
561 rc = close(sock);
562#endif
563
564 if (rc != 0)
565 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
566 else
567 return PJ_SUCCESS;
568}
569
570/*
571 * Get remote's name.
572 */
573PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
574 pj_sockaddr_t *addr,
575 int *namelen)
576{
577 PJ_CHECK_STACK();
578 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
579 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000580 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000581 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000582 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000583 }
Benny Prijono9033e312005-11-21 02:08:39 +0000584}
585
586/*
587 * Get socket name.
588 */
589PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
590 pj_sockaddr_t *addr,
591 int *namelen)
592{
593 PJ_CHECK_STACK();
594 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
595 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000596 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000597 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000598 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000599 }
Benny Prijono9033e312005-11-21 02:08:39 +0000600}
601
602/*
603 * Send data
604 */
605PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
606 const void *buf,
607 pj_ssize_t *len,
608 unsigned flags)
609{
610 PJ_CHECK_STACK();
611 PJ_ASSERT_RETURN(len, PJ_EINVAL);
612
613 *len = send(sock, (const char*)buf, *len, flags);
614
615 if (*len < 0)
616 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
617 else
618 return PJ_SUCCESS;
619}
620
621
622/*
623 * Send data.
624 */
625PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
626 const void *buf,
627 pj_ssize_t *len,
628 unsigned flags,
629 const pj_sockaddr_t *to,
630 int tolen)
631{
632 PJ_CHECK_STACK();
633 PJ_ASSERT_RETURN(len, PJ_EINVAL);
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000634
635 CHECK_ADDR_LEN(to, tolen);
Benny Prijono9033e312005-11-21 02:08:39 +0000636
637 *len = sendto(sock, (const char*)buf, *len, flags,
638 (const struct sockaddr*)to, tolen);
639
640 if (*len < 0)
641 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
642 else
643 return PJ_SUCCESS;
644}
645
646/*
647 * Receive data.
648 */
649PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
650 void *buf,
651 pj_ssize_t *len,
652 unsigned flags)
653{
654 PJ_CHECK_STACK();
655 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
656
657 *len = recv(sock, (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 * Receive data.
667 */
668PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
669 void *buf,
670 pj_ssize_t *len,
671 unsigned flags,
672 pj_sockaddr_t *from,
673 int *fromlen)
674{
675 PJ_CHECK_STACK();
676 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
677 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
678
679 *len = recvfrom(sock, (char*)buf, *len, flags,
680 (struct sockaddr*)from, (socklen_t*)fromlen);
681
682 if (*len < 0)
683 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000684 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000685 PJ_SOCKADDR_RESET_LEN(from);
Benny Prijono9033e312005-11-21 02:08:39 +0000686 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000687 }
Benny Prijono9033e312005-11-21 02:08:39 +0000688}
689
690/*
691 * Get socket option.
692 */
693PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
694 pj_uint16_t level,
695 pj_uint16_t optname,
696 void *optval,
697 int *optlen)
698{
699 PJ_CHECK_STACK();
700 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
701
702 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
703 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
704 else
705 return PJ_SUCCESS;
706}
707
708/*
709 * Set socket option.
710 */
711PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
712 pj_uint16_t level,
713 pj_uint16_t optname,
714 const void *optval,
715 int optlen)
716{
717 PJ_CHECK_STACK();
718 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
719 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
720 else
721 return PJ_SUCCESS;
722}
723
724/*
Benny Prijono3d327302006-02-08 11:14:03 +0000725 * Connect socket.
726 */
727PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
728 const pj_sockaddr_t *addr,
729 int namelen)
730{
731 PJ_CHECK_STACK();
732 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
733 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
734 else
735 return PJ_SUCCESS;
736}
737
738
739/*
Benny Prijono9033e312005-11-21 02:08:39 +0000740 * Shutdown socket.
741 */
742#if PJ_HAS_TCP
743PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
744 int how)
745{
746 PJ_CHECK_STACK();
747 if (shutdown(sock, how) != 0)
748 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
749 else
750 return PJ_SUCCESS;
751}
752
753/*
754 * Start listening to incoming connections.
755 */
756PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
757 int backlog)
758{
759 PJ_CHECK_STACK();
760 if (listen(sock, backlog) != 0)
761 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
762 else
763 return PJ_SUCCESS;
764}
765
766/*
Benny Prijono9033e312005-11-21 02:08:39 +0000767 * Accept incoming connections
768 */
769PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
770 pj_sock_t *newsock,
771 pj_sockaddr_t *addr,
772 int *addrlen)
773{
774 PJ_CHECK_STACK();
775 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
776
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000777#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
778 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000779 PJ_SOCKADDR_SET_LEN(addr, *addrlen);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000780 }
781#endif
782
Benny Prijono9033e312005-11-21 02:08:39 +0000783 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
784 if (*newsock==PJ_INVALID_SOCKET)
785 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000786 else {
787
788#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
789 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000790 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000791 }
792#endif
793
Benny Prijono9033e312005-11-21 02:08:39 +0000794 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000795 }
Benny Prijono9033e312005-11-21 02:08:39 +0000796}
797#endif /* PJ_HAS_TCP */
798
799