blob: 83a5497e45ee51b1ef24a01aa4bfef48e01ef95e [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
66const pj_uint16_t PJ_SOL_IP = 0xFFFF;
67#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
76const pj_uint16_t PJ_SOL_TCP = 0xFFFF;
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 Prijonodb04cd52009-10-15 03:48:20 +000081#elif defined(PJ_WIN32) && PJ_WIN32
82const pj_uint16_t PJ_SOL_UDP = IPPROTO_UDP;
Benny Prijono9033e312005-11-21 02:08:39 +000083#else
84const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
Benny Prijonodb04cd52009-10-15 03:48:20 +000085#endif /* SOL_UDP */
86
Benny Prijono9033e312005-11-21 02:08:39 +000087#ifdef SOL_IPV6
88const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
Benny Prijonodb04cd52009-10-15 03:48:20 +000089#elif defined(PJ_WIN32) && PJ_WIN32
Benny Prijono72748d02009-10-20 01:24:42 +000090# if defined(IPPROTO_IPV6) || (_WIN32_WINNT >= 0x0501)
91 const pj_uint16_t PJ_SOL_IPV6 = IPPROTO_IPV6;
92# else
93 const pj_uint16_t PJ_SOL_IPV6 = 41;
94# endif
Benny Prijono9033e312005-11-21 02:08:39 +000095#else
96const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
Benny Prijonodb04cd52009-10-15 03:48:20 +000097#endif /* SOL_IPV6 */
Benny Prijono9033e312005-11-21 02:08:39 +000098
Benny Prijono87a00892007-02-01 00:33:12 +000099/* IP_TOS */
100#ifdef IP_TOS
101const pj_uint16_t PJ_IP_TOS = IP_TOS;
102#else
103const pj_uint16_t PJ_IP_TOS = 1;
104#endif
105
106
107/* TOS settings (declared in netinet/ip.h) */
108#ifdef IPTOS_LOWDELAY
109const pj_uint16_t PJ_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
110#else
111const pj_uint16_t PJ_IPTOS_LOWDELAY = 0x10;
112#endif
113#ifdef IPTOS_THROUGHPUT
114const pj_uint16_t PJ_IPTOS_THROUGHPUT = IPTOS_THROUGHPUT;
115#else
116const pj_uint16_t PJ_IPTOS_THROUGHPUT = 0x08;
117#endif
118#ifdef IPTOS_RELIABILITY
119const pj_uint16_t PJ_IPTOS_RELIABILITY = IPTOS_RELIABILITY;
120#else
121const pj_uint16_t PJ_IPTOS_RELIABILITY = 0x04;
122#endif
123#ifdef IPTOS_MINCOST
124const pj_uint16_t PJ_IPTOS_MINCOST = IPTOS_MINCOST;
125#else
126const pj_uint16_t PJ_IPTOS_MINCOST = 0x02;
127#endif
128
129
Benny Prijono9033e312005-11-21 02:08:39 +0000130/* optname values. */
131const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
132const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
133const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
Benny Prijonodb04cd52009-10-15 03:48:20 +0000134const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
135const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
136
Benny Prijonoe2746132008-09-27 13:16:35 +0000137/* Multicasting is not supported e.g. in PocketPC 2003 SDK */
138#ifdef IP_MULTICAST_IF
Benny Prijono513d1352008-09-27 09:35:34 +0000139const pj_uint16_t PJ_IP_MULTICAST_IF = IP_MULTICAST_IF;
140const pj_uint16_t PJ_IP_MULTICAST_TTL = IP_MULTICAST_TTL;
141const pj_uint16_t PJ_IP_MULTICAST_LOOP = IP_MULTICAST_LOOP;
142const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = IP_ADD_MEMBERSHIP;
143const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
Benny Prijonoe2746132008-09-27 13:16:35 +0000144#else
145const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
146const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
147const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
148const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
149const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
150#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000151
Benny Prijono57dc48b2006-12-25 06:39:33 +0000152/* recv() and send() flags */
153const int PJ_MSG_OOB = MSG_OOB;
154const int PJ_MSG_PEEK = MSG_PEEK;
155const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
156
157
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000158#if 0
159static void CHECK_ADDR_LEN(const pj_sockaddr *addr, int len)
160{
161 pj_sockaddr *a = (pj_sockaddr*)addr;
162 pj_assert((a->addr.sa_family==PJ_AF_INET && len==sizeof(pj_sockaddr_in)) ||
163 (a->addr.sa_family==PJ_AF_INET6 && len==sizeof(pj_sockaddr_in6)));
164
165}
166#else
167#define CHECK_ADDR_LEN(addr,len)
168#endif
169
Benny Prijono9033e312005-11-21 02:08:39 +0000170/*
171 * Convert 16-bit value from network byte order to host byte order.
172 */
173PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
174{
175 return ntohs(netshort);
176}
177
178/*
179 * Convert 16-bit value from host byte order to network byte order.
180 */
181PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
182{
183 return htons(hostshort);
184}
185
186/*
187 * Convert 32-bit value from network byte order to host byte order.
188 */
189PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
190{
191 return ntohl(netlong);
192}
193
194/*
195 * Convert 32-bit value from host byte order to network byte order.
196 */
197PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
198{
199 return htonl(hostlong);
200}
201
202/*
203 * Convert an Internet host address given in network byte order
204 * to string in standard numbers and dots notation.
205 */
206PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
207{
208#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
209 return inet_ntoa(*(struct in_addr*)&inaddr);
210#else
211 struct in_addr addr;
212 addr.s_addr = inaddr.s_addr;
213 return inet_ntoa(addr);
214#endif
215}
216
217/*
218 * This function converts the Internet host address cp from the standard
219 * numbers-and-dots notation into binary data and stores it in the structure
220 * that inp points to.
221 */
222PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
223{
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000224 char tempaddr[PJ_INET_ADDRSTRLEN];
Benny Prijono9033e312005-11-21 02:08:39 +0000225
226 /* Initialize output with PJ_INADDR_NONE.
227 * Some apps relies on this instead of the return value
228 * (and anyway the return value is quite confusing!)
229 */
230 inp->s_addr = PJ_INADDR_NONE;
231
232 /* Caution:
233 * this function might be called with cp->slen >= 16
234 * (i.e. when called with hostname to check if it's an IP addr).
235 */
236 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000237 if (cp->slen >= PJ_INET_ADDRSTRLEN) {
Benny Prijono9033e312005-11-21 02:08:39 +0000238 return 0;
239 }
240
241 pj_memcpy(tempaddr, cp->ptr, cp->slen);
242 tempaddr[cp->slen] = '\0';
243
244#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
245 return inet_aton(tempaddr, (struct in_addr*)inp);
246#else
247 inp->s_addr = inet_addr(tempaddr);
248 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
249#endif
250}
251
252/*
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000253 * Convert text to IPv4/IPv6 address.
254 */
255PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
256{
257 char tempaddr[PJ_INET6_ADDRSTRLEN];
258
Benny Prijono62b86eb2007-12-01 08:52:57 +0000259 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000260 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
261
262 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
263 * compatible with pj_inet_aton()
264 */
265 if (af==PJ_AF_INET) {
266 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
267 }
268
269 /* Caution:
270 * this function might be called with cp->slen >= 46
271 * (i.e. when called with hostname to check if it's an IP addr).
272 */
273 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
274 return PJ_ENAMETOOLONG;
275 }
276
277 pj_memcpy(tempaddr, src->ptr, src->slen);
278 tempaddr[src->slen] = '\0';
279
280#if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
281 /*
282 * Implementation using inet_pton()
283 */
284 if (inet_pton(af, tempaddr, dst) != 1) {
285 pj_status_t status = pj_get_netos_error();
286 if (status == PJ_SUCCESS)
287 status = PJ_EUNKNOWN;
288
289 return status;
290 }
291
292 return PJ_SUCCESS;
293
294#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
295 /*
296 * Implementation on Windows, using WSAStringToAddress().
297 * Should also work on Unicode systems.
298 */
299 {
300 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
301 pj_sockaddr sock_addr;
302 int addr_len = sizeof(sock_addr);
303 int rc;
304
305 sock_addr.addr.sa_family = (pj_uint16_t)af;
306 rc = WSAStringToAddress(
307 PJ_STRING_TO_NATIVE(tempaddr,wtempaddr,sizeof(wtempaddr)),
308 af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
309 if (rc != 0) {
Benny Prijonoa199cb72008-12-19 14:36:08 +0000310 /* If you get rc 130022 Invalid argument (WSAEINVAL) with IPv6,
311 * check that you have IPv6 enabled (install it in the network
312 * adapter).
313 */
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000314 pj_status_t status = pj_get_netos_error();
315 if (status == PJ_SUCCESS)
316 status = PJ_EUNKNOWN;
317
318 return status;
319 }
320
321 if (sock_addr.addr.sa_family == PJ_AF_INET) {
322 pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
323 return PJ_SUCCESS;
324 } else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
325 pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
326 return PJ_SUCCESS;
327 } else {
328 pj_assert(!"Shouldn't happen");
329 return PJ_EBUG;
330 }
331 }
332#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
333 /* IPv6 support is disabled, just return error without raising assertion */
334 return PJ_EIPV6NOTSUP;
335#else
336 pj_assert(!"Not supported");
337 return PJ_EIPV6NOTSUP;
338#endif
339}
340
341/*
342 * Convert IPv4/IPv6 address to text.
343 */
344PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
345 char *dst, int size)
346
347{
348 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
Benny Prijono444ef3f2007-11-20 09:47:32 +0000349
350 *dst = '\0';
351
Benny Prijono62b86eb2007-12-01 08:52:57 +0000352 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000353
354#if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
355 /*
356 * Implementation using inet_ntop()
357 */
358 if (inet_ntop(af, src, dst, size) == NULL) {
359 pj_status_t status = pj_get_netos_error();
360 if (status == PJ_SUCCESS)
361 status = PJ_EUNKNOWN;
362
363 return status;
364 }
365
366 return PJ_SUCCESS;
367
368#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
369 /*
370 * Implementation on Windows, using WSAAddressToString().
371 * Should also work on Unicode systems.
372 */
373 {
374 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
375 pj_sockaddr sock_addr;
376 DWORD addr_len, addr_str_len;
377 int rc;
378
379 pj_bzero(&sock_addr, sizeof(sock_addr));
380 sock_addr.addr.sa_family = (pj_uint16_t)af;
381 if (af == PJ_AF_INET) {
382 if (size < PJ_INET_ADDRSTRLEN)
383 return PJ_ETOOSMALL;
384 pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
385 addr_len = sizeof(pj_sockaddr_in);
386 addr_str_len = PJ_INET_ADDRSTRLEN;
387 } else if (af == PJ_AF_INET6) {
388 if (size < PJ_INET6_ADDRSTRLEN)
389 return PJ_ETOOSMALL;
390 pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
391 addr_len = sizeof(pj_sockaddr_in6);
392 addr_str_len = PJ_INET6_ADDRSTRLEN;
393 } else {
394 pj_assert(!"Unsupported address family");
Benny Prijono62b86eb2007-12-01 08:52:57 +0000395 return PJ_EAFNOTSUP;
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000396 }
397
398#if PJ_NATIVE_STRING_IS_UNICODE
399 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
Benny Prijonoab872f22008-01-04 17:56:28 +0000400 NULL, wtempaddr, &addr_str_len);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000401 if (rc == 0) {
402 pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
403 }
404#else
405 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
406 NULL, dst, &addr_str_len);
407#endif
408
409 if (rc != 0) {
410 pj_status_t status = pj_get_netos_error();
411 if (status == PJ_SUCCESS)
412 status = PJ_EUNKNOWN;
413
414 return status;
415 }
416
417 return PJ_SUCCESS;
418 }
419
420#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
421 /* IPv6 support is disabled, just return error without raising assertion */
422 return PJ_EIPV6NOTSUP;
423#else
424 pj_assert(!"Not supported");
425 return PJ_EIPV6NOTSUP;
426#endif
427}
428
429/*
Benny Prijono9033e312005-11-21 02:08:39 +0000430 * Get hostname.
431 */
432PJ_DEF(const pj_str_t*) pj_gethostname(void)
433{
434 static char buf[PJ_MAX_HOSTNAME];
435 static pj_str_t hostname;
436
437 PJ_CHECK_STACK();
438
439 if (hostname.ptr == NULL) {
440 hostname.ptr = buf;
441 if (gethostname(buf, sizeof(buf)) != 0) {
442 hostname.ptr[0] = '\0';
443 hostname.slen = 0;
444 } else {
445 hostname.slen = strlen(buf);
446 }
447 }
448 return &hostname;
449}
450
Benny Prijono9033e312005-11-21 02:08:39 +0000451#if defined(PJ_WIN32)
452/*
453 * Create new socket/endpoint for communication and returns a descriptor.
454 */
455PJ_DEF(pj_status_t) pj_sock_socket(int af,
456 int type,
457 int proto,
458 pj_sock_t *sock)
459{
460 PJ_CHECK_STACK();
461
462 /* Sanity checks. */
463 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
464 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
465 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
466
467 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
468
469 if (*sock == PJ_INVALID_SOCKET)
470 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
471 else
472 return PJ_SUCCESS;
473}
474
475#else
476/*
477 * Create new socket/endpoint for communication and returns a descriptor.
478 */
479PJ_DEF(pj_status_t) pj_sock_socket(int af,
480 int type,
481 int proto,
482 pj_sock_t *sock)
483{
484
485 PJ_CHECK_STACK();
486
487 /* Sanity checks. */
488 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
489 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
490 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
491
492 *sock = socket(af, type, proto);
493 if (*sock == PJ_INVALID_SOCKET)
494 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
495 else
496 return PJ_SUCCESS;
497}
498#endif
499
Benny Prijono9033e312005-11-21 02:08:39 +0000500/*
501 * Bind socket.
502 */
503PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
504 const pj_sockaddr_t *addr,
505 int len)
506{
507 PJ_CHECK_STACK();
508
Benny Prijonoa1e69682007-05-11 15:14:34 +0000509 PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000510
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000511 CHECK_ADDR_LEN(addr, len);
512
Benny Prijono9033e312005-11-21 02:08:39 +0000513 if (bind(sock, (struct sockaddr*)addr, len) != 0)
514 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
515 else
516 return PJ_SUCCESS;
517}
518
519
520/*
521 * Bind socket.
522 */
523PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
524 pj_uint32_t addr32,
525 pj_uint16_t port)
526{
527 pj_sockaddr_in addr;
528
529 PJ_CHECK_STACK();
530
Benny Prijono62b86eb2007-12-01 08:52:57 +0000531 PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
Benny Prijono9033e312005-11-21 02:08:39 +0000532 addr.sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000533 pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000534 addr.sin_addr.s_addr = pj_htonl(addr32);
535 addr.sin_port = pj_htons(port);
536
537 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
538}
539
540
541/*
542 * Close socket.
543 */
544PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
545{
546 int rc;
547
548 PJ_CHECK_STACK();
Benny Prijono9cf138e2006-01-19 03:58:29 +0000549#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
550 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000551 rc = closesocket(sock);
552#else
553 rc = close(sock);
554#endif
555
556 if (rc != 0)
557 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
558 else
559 return PJ_SUCCESS;
560}
561
562/*
563 * Get remote's name.
564 */
565PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
566 pj_sockaddr_t *addr,
567 int *namelen)
568{
569 PJ_CHECK_STACK();
570 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
571 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000572 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000573 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000574 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000575 }
Benny Prijono9033e312005-11-21 02:08:39 +0000576}
577
578/*
579 * Get socket name.
580 */
581PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
582 pj_sockaddr_t *addr,
583 int *namelen)
584{
585 PJ_CHECK_STACK();
586 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
587 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000588 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000589 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000590 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000591 }
Benny Prijono9033e312005-11-21 02:08:39 +0000592}
593
594/*
595 * Send data
596 */
597PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
598 const void *buf,
599 pj_ssize_t *len,
600 unsigned flags)
601{
602 PJ_CHECK_STACK();
603 PJ_ASSERT_RETURN(len, PJ_EINVAL);
604
605 *len = send(sock, (const char*)buf, *len, flags);
606
607 if (*len < 0)
608 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
609 else
610 return PJ_SUCCESS;
611}
612
613
614/*
615 * Send data.
616 */
617PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
618 const void *buf,
619 pj_ssize_t *len,
620 unsigned flags,
621 const pj_sockaddr_t *to,
622 int tolen)
623{
624 PJ_CHECK_STACK();
625 PJ_ASSERT_RETURN(len, PJ_EINVAL);
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000626
627 CHECK_ADDR_LEN(to, tolen);
Benny Prijono9033e312005-11-21 02:08:39 +0000628
629 *len = sendto(sock, (const char*)buf, *len, flags,
630 (const struct sockaddr*)to, tolen);
631
632 if (*len < 0)
633 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
634 else
635 return PJ_SUCCESS;
636}
637
638/*
639 * Receive data.
640 */
641PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
642 void *buf,
643 pj_ssize_t *len,
644 unsigned flags)
645{
646 PJ_CHECK_STACK();
647 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
648
649 *len = recv(sock, (char*)buf, *len, flags);
650
651 if (*len < 0)
652 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
653 else
654 return PJ_SUCCESS;
655}
656
657/*
658 * Receive data.
659 */
660PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
661 void *buf,
662 pj_ssize_t *len,
663 unsigned flags,
664 pj_sockaddr_t *from,
665 int *fromlen)
666{
667 PJ_CHECK_STACK();
668 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
669 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
670
671 *len = recvfrom(sock, (char*)buf, *len, flags,
672 (struct sockaddr*)from, (socklen_t*)fromlen);
673
674 if (*len < 0)
675 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000676 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000677 PJ_SOCKADDR_RESET_LEN(from);
Benny Prijono9033e312005-11-21 02:08:39 +0000678 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000679 }
Benny Prijono9033e312005-11-21 02:08:39 +0000680}
681
682/*
683 * Get socket option.
684 */
685PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
686 pj_uint16_t level,
687 pj_uint16_t optname,
688 void *optval,
689 int *optlen)
690{
691 PJ_CHECK_STACK();
692 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
693
694 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
695 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
696 else
697 return PJ_SUCCESS;
698}
699
700/*
701 * Set socket option.
702 */
703PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
704 pj_uint16_t level,
705 pj_uint16_t optname,
706 const void *optval,
707 int optlen)
708{
709 PJ_CHECK_STACK();
710 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
711 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
712 else
713 return PJ_SUCCESS;
714}
715
716/*
Benny Prijono3d327302006-02-08 11:14:03 +0000717 * Connect socket.
718 */
719PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
720 const pj_sockaddr_t *addr,
721 int namelen)
722{
723 PJ_CHECK_STACK();
724 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
725 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
726 else
727 return PJ_SUCCESS;
728}
729
730
731/*
Benny Prijono9033e312005-11-21 02:08:39 +0000732 * Shutdown socket.
733 */
734#if PJ_HAS_TCP
735PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
736 int how)
737{
738 PJ_CHECK_STACK();
739 if (shutdown(sock, how) != 0)
740 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
741 else
742 return PJ_SUCCESS;
743}
744
745/*
746 * Start listening to incoming connections.
747 */
748PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
749 int backlog)
750{
751 PJ_CHECK_STACK();
752 if (listen(sock, backlog) != 0)
753 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
754 else
755 return PJ_SUCCESS;
756}
757
758/*
Benny Prijono9033e312005-11-21 02:08:39 +0000759 * Accept incoming connections
760 */
761PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
762 pj_sock_t *newsock,
763 pj_sockaddr_t *addr,
764 int *addrlen)
765{
766 PJ_CHECK_STACK();
767 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
768
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000769#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
770 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000771 PJ_SOCKADDR_SET_LEN(addr, *addrlen);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000772 }
773#endif
774
Benny Prijono9033e312005-11-21 02:08:39 +0000775 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
776 if (*newsock==PJ_INVALID_SOCKET)
777 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000778 else {
779
780#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
781 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000782 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000783 }
784#endif
785
Benny Prijono9033e312005-11-21 02:08:39 +0000786 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000787 }
Benny Prijono9033e312005-11-21 02:08:39 +0000788}
789#endif /* PJ_HAS_TCP */
790
791