blob: 831a2579aff2a6ff88f506b05d32f66d6a2ec388 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C)2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/sock.h>
20#include <pj/os.h>
21#include <pj/assert.h>
22#include <pj/string.h>
23#include <pj/compat/socket.h>
24#include <pj/addr_resolv.h>
25#include <pj/errno.h>
Benny Prijonoc16c6e32007-11-18 14:53:47 +000026#include <pj/unicode.h>
Benny Prijono9033e312005-11-21 02:08:39 +000027
28/*
29 * Address families conversion.
Benny Prijono42c5b9e2006-05-10 19:24:40 +000030 * The values here are indexed based on pj_addr_family.
Benny Prijono9033e312005-11-21 02:08:39 +000031 */
Benny Prijonoc16c6e32007-11-18 14:53:47 +000032const pj_uint16_t PJ_AF_UNSPEC = AF_UNSPEC;
Benny Prijono9033e312005-11-21 02:08:39 +000033const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
34const pj_uint16_t PJ_AF_INET = AF_INET;
35const pj_uint16_t PJ_AF_INET6 = AF_INET6;
36#ifdef AF_PACKET
37const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
38#else
39const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
40#endif
41#ifdef AF_IRDA
42const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
43#else
44const pj_uint16_t PJ_AF_IRDA = 0xFFFF;
45#endif
46
47/*
48 * Socket types conversion.
Benny Prijono42c5b9e2006-05-10 19:24:40 +000049 * The values here are indexed based on pj_sock_type
Benny Prijono9033e312005-11-21 02:08:39 +000050 */
Benny Prijono87a00892007-02-01 00:33:12 +000051const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
Benny Prijono9033e312005-11-21 02:08:39 +000052const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
53const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
54const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
55
56/*
57 * Socket level values.
58 */
59const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
60#ifdef SOL_IP
61const pj_uint16_t PJ_SOL_IP = SOL_IP;
62#else
63const pj_uint16_t PJ_SOL_IP = 0xFFFF;
64#endif /* SOL_IP */
65#if defined(SOL_TCP)
66const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
67#elif defined(IPPROTO_TCP)
68const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
Benny Prijono0de9e2b2007-10-21 11:49:48 +000069#else
70const pj_uint16_t PJ_SOL_TCP = 0xFFFF;
Benny Prijono9033e312005-11-21 02:08:39 +000071#endif /* SOL_TCP */
72#ifdef SOL_UDP
73const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
74#else
75const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
76#endif
77#ifdef SOL_IPV6
78const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
79#else
80const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
81#endif
82
Benny Prijono87a00892007-02-01 00:33:12 +000083/* IP_TOS */
84#ifdef IP_TOS
85const pj_uint16_t PJ_IP_TOS = IP_TOS;
86#else
87const pj_uint16_t PJ_IP_TOS = 1;
88#endif
89
90
91/* TOS settings (declared in netinet/ip.h) */
92#ifdef IPTOS_LOWDELAY
93const pj_uint16_t PJ_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
94#else
95const pj_uint16_t PJ_IPTOS_LOWDELAY = 0x10;
96#endif
97#ifdef IPTOS_THROUGHPUT
98const pj_uint16_t PJ_IPTOS_THROUGHPUT = IPTOS_THROUGHPUT;
99#else
100const pj_uint16_t PJ_IPTOS_THROUGHPUT = 0x08;
101#endif
102#ifdef IPTOS_RELIABILITY
103const pj_uint16_t PJ_IPTOS_RELIABILITY = IPTOS_RELIABILITY;
104#else
105const pj_uint16_t PJ_IPTOS_RELIABILITY = 0x04;
106#endif
107#ifdef IPTOS_MINCOST
108const pj_uint16_t PJ_IPTOS_MINCOST = IPTOS_MINCOST;
109#else
110const pj_uint16_t PJ_IPTOS_MINCOST = 0x02;
111#endif
112
113
Benny Prijono9033e312005-11-21 02:08:39 +0000114/* optname values. */
115const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
116const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
117const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
Benny Prijonoe2746132008-09-27 13:16:35 +0000118/* Multicasting is not supported e.g. in PocketPC 2003 SDK */
119#ifdef IP_MULTICAST_IF
Benny Prijono513d1352008-09-27 09:35:34 +0000120const pj_uint16_t PJ_IP_MULTICAST_IF = IP_MULTICAST_IF;
121const pj_uint16_t PJ_IP_MULTICAST_TTL = IP_MULTICAST_TTL;
122const pj_uint16_t PJ_IP_MULTICAST_LOOP = IP_MULTICAST_LOOP;
123const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = IP_ADD_MEMBERSHIP;
124const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
Benny Prijonoe2746132008-09-27 13:16:35 +0000125#else
126const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
127const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
128const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
129const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
130const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
131#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000132
Benny Prijono57dc48b2006-12-25 06:39:33 +0000133/* recv() and send() flags */
134const int PJ_MSG_OOB = MSG_OOB;
135const int PJ_MSG_PEEK = MSG_PEEK;
136const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
137
138
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000139#if 0
140static void CHECK_ADDR_LEN(const pj_sockaddr *addr, int len)
141{
142 pj_sockaddr *a = (pj_sockaddr*)addr;
143 pj_assert((a->addr.sa_family==PJ_AF_INET && len==sizeof(pj_sockaddr_in)) ||
144 (a->addr.sa_family==PJ_AF_INET6 && len==sizeof(pj_sockaddr_in6)));
145
146}
147#else
148#define CHECK_ADDR_LEN(addr,len)
149#endif
150
Benny Prijono9033e312005-11-21 02:08:39 +0000151/*
152 * Convert 16-bit value from network byte order to host byte order.
153 */
154PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
155{
156 return ntohs(netshort);
157}
158
159/*
160 * Convert 16-bit value from host byte order to network byte order.
161 */
162PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
163{
164 return htons(hostshort);
165}
166
167/*
168 * Convert 32-bit value from network byte order to host byte order.
169 */
170PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
171{
172 return ntohl(netlong);
173}
174
175/*
176 * Convert 32-bit value from host byte order to network byte order.
177 */
178PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
179{
180 return htonl(hostlong);
181}
182
183/*
184 * Convert an Internet host address given in network byte order
185 * to string in standard numbers and dots notation.
186 */
187PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
188{
189#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
190 return inet_ntoa(*(struct in_addr*)&inaddr);
191#else
192 struct in_addr addr;
193 addr.s_addr = inaddr.s_addr;
194 return inet_ntoa(addr);
195#endif
196}
197
198/*
199 * This function converts the Internet host address cp from the standard
200 * numbers-and-dots notation into binary data and stores it in the structure
201 * that inp points to.
202 */
203PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
204{
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000205 char tempaddr[PJ_INET_ADDRSTRLEN];
Benny Prijono9033e312005-11-21 02:08:39 +0000206
207 /* Initialize output with PJ_INADDR_NONE.
208 * Some apps relies on this instead of the return value
209 * (and anyway the return value is quite confusing!)
210 */
211 inp->s_addr = PJ_INADDR_NONE;
212
213 /* Caution:
214 * this function might be called with cp->slen >= 16
215 * (i.e. when called with hostname to check if it's an IP addr).
216 */
217 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000218 if (cp->slen >= PJ_INET_ADDRSTRLEN) {
Benny Prijono9033e312005-11-21 02:08:39 +0000219 return 0;
220 }
221
222 pj_memcpy(tempaddr, cp->ptr, cp->slen);
223 tempaddr[cp->slen] = '\0';
224
225#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
226 return inet_aton(tempaddr, (struct in_addr*)inp);
227#else
228 inp->s_addr = inet_addr(tempaddr);
229 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
230#endif
231}
232
233/*
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000234 * Convert text to IPv4/IPv6 address.
235 */
236PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
237{
238 char tempaddr[PJ_INET6_ADDRSTRLEN];
239
Benny Prijono62b86eb2007-12-01 08:52:57 +0000240 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000241 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
242
243 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
244 * compatible with pj_inet_aton()
245 */
246 if (af==PJ_AF_INET) {
247 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
248 }
249
250 /* Caution:
251 * this function might be called with cp->slen >= 46
252 * (i.e. when called with hostname to check if it's an IP addr).
253 */
254 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
255 return PJ_ENAMETOOLONG;
256 }
257
258 pj_memcpy(tempaddr, src->ptr, src->slen);
259 tempaddr[src->slen] = '\0';
260
261#if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
262 /*
263 * Implementation using inet_pton()
264 */
265 if (inet_pton(af, tempaddr, dst) != 1) {
266 pj_status_t status = pj_get_netos_error();
267 if (status == PJ_SUCCESS)
268 status = PJ_EUNKNOWN;
269
270 return status;
271 }
272
273 return PJ_SUCCESS;
274
275#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
276 /*
277 * Implementation on Windows, using WSAStringToAddress().
278 * Should also work on Unicode systems.
279 */
280 {
281 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
282 pj_sockaddr sock_addr;
283 int addr_len = sizeof(sock_addr);
284 int rc;
285
286 sock_addr.addr.sa_family = (pj_uint16_t)af;
287 rc = WSAStringToAddress(
288 PJ_STRING_TO_NATIVE(tempaddr,wtempaddr,sizeof(wtempaddr)),
289 af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
290 if (rc != 0) {
Benny Prijonoa199cb72008-12-19 14:36:08 +0000291 /* If you get rc 130022 Invalid argument (WSAEINVAL) with IPv6,
292 * check that you have IPv6 enabled (install it in the network
293 * adapter).
294 */
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000295 pj_status_t status = pj_get_netos_error();
296 if (status == PJ_SUCCESS)
297 status = PJ_EUNKNOWN;
298
299 return status;
300 }
301
302 if (sock_addr.addr.sa_family == PJ_AF_INET) {
303 pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
304 return PJ_SUCCESS;
305 } else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
306 pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
307 return PJ_SUCCESS;
308 } else {
309 pj_assert(!"Shouldn't happen");
310 return PJ_EBUG;
311 }
312 }
313#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
314 /* IPv6 support is disabled, just return error without raising assertion */
315 return PJ_EIPV6NOTSUP;
316#else
317 pj_assert(!"Not supported");
318 return PJ_EIPV6NOTSUP;
319#endif
320}
321
322/*
323 * Convert IPv4/IPv6 address to text.
324 */
325PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
326 char *dst, int size)
327
328{
329 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
Benny Prijono444ef3f2007-11-20 09:47:32 +0000330
331 *dst = '\0';
332
Benny Prijono62b86eb2007-12-01 08:52:57 +0000333 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000334
335#if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
336 /*
337 * Implementation using inet_ntop()
338 */
339 if (inet_ntop(af, src, dst, size) == NULL) {
340 pj_status_t status = pj_get_netos_error();
341 if (status == PJ_SUCCESS)
342 status = PJ_EUNKNOWN;
343
344 return status;
345 }
346
347 return PJ_SUCCESS;
348
349#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
350 /*
351 * Implementation on Windows, using WSAAddressToString().
352 * Should also work on Unicode systems.
353 */
354 {
355 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
356 pj_sockaddr sock_addr;
357 DWORD addr_len, addr_str_len;
358 int rc;
359
360 pj_bzero(&sock_addr, sizeof(sock_addr));
361 sock_addr.addr.sa_family = (pj_uint16_t)af;
362 if (af == PJ_AF_INET) {
363 if (size < PJ_INET_ADDRSTRLEN)
364 return PJ_ETOOSMALL;
365 pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
366 addr_len = sizeof(pj_sockaddr_in);
367 addr_str_len = PJ_INET_ADDRSTRLEN;
368 } else if (af == PJ_AF_INET6) {
369 if (size < PJ_INET6_ADDRSTRLEN)
370 return PJ_ETOOSMALL;
371 pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
372 addr_len = sizeof(pj_sockaddr_in6);
373 addr_str_len = PJ_INET6_ADDRSTRLEN;
374 } else {
375 pj_assert(!"Unsupported address family");
Benny Prijono62b86eb2007-12-01 08:52:57 +0000376 return PJ_EAFNOTSUP;
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000377 }
378
379#if PJ_NATIVE_STRING_IS_UNICODE
380 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
Benny Prijonoab872f22008-01-04 17:56:28 +0000381 NULL, wtempaddr, &addr_str_len);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000382 if (rc == 0) {
383 pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
384 }
385#else
386 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
387 NULL, dst, &addr_str_len);
388#endif
389
390 if (rc != 0) {
391 pj_status_t status = pj_get_netos_error();
392 if (status == PJ_SUCCESS)
393 status = PJ_EUNKNOWN;
394
395 return status;
396 }
397
398 return PJ_SUCCESS;
399 }
400
401#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
402 /* IPv6 support is disabled, just return error without raising assertion */
403 return PJ_EIPV6NOTSUP;
404#else
405 pj_assert(!"Not supported");
406 return PJ_EIPV6NOTSUP;
407#endif
408}
409
410/*
Benny Prijono9033e312005-11-21 02:08:39 +0000411 * Get hostname.
412 */
413PJ_DEF(const pj_str_t*) pj_gethostname(void)
414{
415 static char buf[PJ_MAX_HOSTNAME];
416 static pj_str_t hostname;
417
418 PJ_CHECK_STACK();
419
420 if (hostname.ptr == NULL) {
421 hostname.ptr = buf;
422 if (gethostname(buf, sizeof(buf)) != 0) {
423 hostname.ptr[0] = '\0';
424 hostname.slen = 0;
425 } else {
426 hostname.slen = strlen(buf);
427 }
428 }
429 return &hostname;
430}
431
Benny Prijono9033e312005-11-21 02:08:39 +0000432#if defined(PJ_WIN32)
433/*
434 * Create new socket/endpoint for communication and returns a descriptor.
435 */
436PJ_DEF(pj_status_t) pj_sock_socket(int af,
437 int type,
438 int proto,
439 pj_sock_t *sock)
440{
441 PJ_CHECK_STACK();
442
443 /* Sanity checks. */
444 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
445 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
446 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
447
448 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
449
450 if (*sock == PJ_INVALID_SOCKET)
451 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
452 else
453 return PJ_SUCCESS;
454}
455
456#else
457/*
458 * Create new socket/endpoint for communication and returns a descriptor.
459 */
460PJ_DEF(pj_status_t) pj_sock_socket(int af,
461 int type,
462 int proto,
463 pj_sock_t *sock)
464{
465
466 PJ_CHECK_STACK();
467
468 /* Sanity checks. */
469 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
470 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
471 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
472
473 *sock = socket(af, type, proto);
474 if (*sock == PJ_INVALID_SOCKET)
475 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
476 else
477 return PJ_SUCCESS;
478}
479#endif
480
Benny Prijono9033e312005-11-21 02:08:39 +0000481/*
482 * Bind socket.
483 */
484PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
485 const pj_sockaddr_t *addr,
486 int len)
487{
488 PJ_CHECK_STACK();
489
Benny Prijonoa1e69682007-05-11 15:14:34 +0000490 PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000491
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000492 CHECK_ADDR_LEN(addr, len);
493
Benny Prijono9033e312005-11-21 02:08:39 +0000494 if (bind(sock, (struct sockaddr*)addr, len) != 0)
495 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
496 else
497 return PJ_SUCCESS;
498}
499
500
501/*
502 * Bind socket.
503 */
504PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
505 pj_uint32_t addr32,
506 pj_uint16_t port)
507{
508 pj_sockaddr_in addr;
509
510 PJ_CHECK_STACK();
511
Benny Prijono62b86eb2007-12-01 08:52:57 +0000512 PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
Benny Prijono9033e312005-11-21 02:08:39 +0000513 addr.sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000514 pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000515 addr.sin_addr.s_addr = pj_htonl(addr32);
516 addr.sin_port = pj_htons(port);
517
518 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
519}
520
521
522/*
523 * Close socket.
524 */
525PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
526{
527 int rc;
528
529 PJ_CHECK_STACK();
Benny Prijono9cf138e2006-01-19 03:58:29 +0000530#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
531 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000532 rc = closesocket(sock);
533#else
534 rc = close(sock);
535#endif
536
537 if (rc != 0)
538 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
539 else
540 return PJ_SUCCESS;
541}
542
543/*
544 * Get remote's name.
545 */
546PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
547 pj_sockaddr_t *addr,
548 int *namelen)
549{
550 PJ_CHECK_STACK();
551 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
552 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000553 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000554 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000555 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000556 }
Benny Prijono9033e312005-11-21 02:08:39 +0000557}
558
559/*
560 * Get socket name.
561 */
562PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
563 pj_sockaddr_t *addr,
564 int *namelen)
565{
566 PJ_CHECK_STACK();
567 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
568 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000569 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000570 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000571 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000572 }
Benny Prijono9033e312005-11-21 02:08:39 +0000573}
574
575/*
576 * Send data
577 */
578PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
579 const void *buf,
580 pj_ssize_t *len,
581 unsigned flags)
582{
583 PJ_CHECK_STACK();
584 PJ_ASSERT_RETURN(len, PJ_EINVAL);
585
586 *len = send(sock, (const char*)buf, *len, flags);
587
588 if (*len < 0)
589 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
590 else
591 return PJ_SUCCESS;
592}
593
594
595/*
596 * Send data.
597 */
598PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
599 const void *buf,
600 pj_ssize_t *len,
601 unsigned flags,
602 const pj_sockaddr_t *to,
603 int tolen)
604{
605 PJ_CHECK_STACK();
606 PJ_ASSERT_RETURN(len, PJ_EINVAL);
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000607
608 CHECK_ADDR_LEN(to, tolen);
Benny Prijono9033e312005-11-21 02:08:39 +0000609
610 *len = sendto(sock, (const char*)buf, *len, flags,
611 (const struct sockaddr*)to, tolen);
612
613 if (*len < 0)
614 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
615 else
616 return PJ_SUCCESS;
617}
618
619/*
620 * Receive data.
621 */
622PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
623 void *buf,
624 pj_ssize_t *len,
625 unsigned flags)
626{
627 PJ_CHECK_STACK();
628 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
629
630 *len = recv(sock, (char*)buf, *len, flags);
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_recvfrom(pj_sock_t sock,
642 void *buf,
643 pj_ssize_t *len,
644 unsigned flags,
645 pj_sockaddr_t *from,
646 int *fromlen)
647{
648 PJ_CHECK_STACK();
649 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
650 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
651
652 *len = recvfrom(sock, (char*)buf, *len, flags,
653 (struct sockaddr*)from, (socklen_t*)fromlen);
654
655 if (*len < 0)
656 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000657 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000658 PJ_SOCKADDR_RESET_LEN(from);
Benny Prijono9033e312005-11-21 02:08:39 +0000659 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000660 }
Benny Prijono9033e312005-11-21 02:08:39 +0000661}
662
663/*
664 * Get socket option.
665 */
666PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
667 pj_uint16_t level,
668 pj_uint16_t optname,
669 void *optval,
670 int *optlen)
671{
672 PJ_CHECK_STACK();
673 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
674
675 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
676 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
677 else
678 return PJ_SUCCESS;
679}
680
681/*
682 * Set socket option.
683 */
684PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
685 pj_uint16_t level,
686 pj_uint16_t optname,
687 const void *optval,
688 int optlen)
689{
690 PJ_CHECK_STACK();
691 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
692 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
693 else
694 return PJ_SUCCESS;
695}
696
697/*
Benny Prijono3d327302006-02-08 11:14:03 +0000698 * Connect socket.
699 */
700PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
701 const pj_sockaddr_t *addr,
702 int namelen)
703{
704 PJ_CHECK_STACK();
705 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
706 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
707 else
708 return PJ_SUCCESS;
709}
710
711
712/*
Benny Prijono9033e312005-11-21 02:08:39 +0000713 * Shutdown socket.
714 */
715#if PJ_HAS_TCP
716PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
717 int how)
718{
719 PJ_CHECK_STACK();
720 if (shutdown(sock, how) != 0)
721 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
722 else
723 return PJ_SUCCESS;
724}
725
726/*
727 * Start listening to incoming connections.
728 */
729PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
730 int backlog)
731{
732 PJ_CHECK_STACK();
733 if (listen(sock, backlog) != 0)
734 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
735 else
736 return PJ_SUCCESS;
737}
738
739/*
Benny Prijono9033e312005-11-21 02:08:39 +0000740 * Accept incoming connections
741 */
742PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
743 pj_sock_t *newsock,
744 pj_sockaddr_t *addr,
745 int *addrlen)
746{
747 PJ_CHECK_STACK();
748 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
749
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000750#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
751 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000752 PJ_SOCKADDR_SET_LEN(addr, *addrlen);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000753 }
754#endif
755
Benny Prijono9033e312005-11-21 02:08:39 +0000756 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
757 if (*newsock==PJ_INVALID_SOCKET)
758 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000759 else {
760
761#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
762 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000763 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000764 }
765#endif
766
Benny Prijono9033e312005-11-21 02:08:39 +0000767 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000768 }
Benny Prijono9033e312005-11-21 02:08:39 +0000769}
770#endif /* PJ_HAS_TCP */
771
772