blob: b5a30fadc782043bf19ed609ae12885c6bd24f7d [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;
63#else
64const pj_uint16_t PJ_SOL_IP = 0xFFFF;
65#endif /* SOL_IP */
66#if defined(SOL_TCP)
67const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
68#elif defined(IPPROTO_TCP)
69const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
Benny Prijono0de9e2b2007-10-21 11:49:48 +000070#else
71const pj_uint16_t PJ_SOL_TCP = 0xFFFF;
Benny Prijono9033e312005-11-21 02:08:39 +000072#endif /* SOL_TCP */
73#ifdef SOL_UDP
74const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
75#else
76const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
77#endif
78#ifdef SOL_IPV6
79const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
80#else
81const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
82#endif
83
Benny Prijono87a00892007-02-01 00:33:12 +000084/* IP_TOS */
85#ifdef IP_TOS
86const pj_uint16_t PJ_IP_TOS = IP_TOS;
87#else
88const pj_uint16_t PJ_IP_TOS = 1;
89#endif
90
91
92/* TOS settings (declared in netinet/ip.h) */
93#ifdef IPTOS_LOWDELAY
94const pj_uint16_t PJ_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
95#else
96const pj_uint16_t PJ_IPTOS_LOWDELAY = 0x10;
97#endif
98#ifdef IPTOS_THROUGHPUT
99const pj_uint16_t PJ_IPTOS_THROUGHPUT = IPTOS_THROUGHPUT;
100#else
101const pj_uint16_t PJ_IPTOS_THROUGHPUT = 0x08;
102#endif
103#ifdef IPTOS_RELIABILITY
104const pj_uint16_t PJ_IPTOS_RELIABILITY = IPTOS_RELIABILITY;
105#else
106const pj_uint16_t PJ_IPTOS_RELIABILITY = 0x04;
107#endif
108#ifdef IPTOS_MINCOST
109const pj_uint16_t PJ_IPTOS_MINCOST = IPTOS_MINCOST;
110#else
111const pj_uint16_t PJ_IPTOS_MINCOST = 0x02;
112#endif
113
114
Benny Prijono9033e312005-11-21 02:08:39 +0000115/* optname values. */
116const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
117const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
118const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
Benny Prijonoe2746132008-09-27 13:16:35 +0000119/* Multicasting is not supported e.g. in PocketPC 2003 SDK */
120#ifdef IP_MULTICAST_IF
Benny Prijono513d1352008-09-27 09:35:34 +0000121const pj_uint16_t PJ_IP_MULTICAST_IF = IP_MULTICAST_IF;
122const pj_uint16_t PJ_IP_MULTICAST_TTL = IP_MULTICAST_TTL;
123const pj_uint16_t PJ_IP_MULTICAST_LOOP = IP_MULTICAST_LOOP;
124const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = IP_ADD_MEMBERSHIP;
125const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = IP_DROP_MEMBERSHIP;
Benny Prijonoe2746132008-09-27 13:16:35 +0000126#else
127const pj_uint16_t PJ_IP_MULTICAST_IF = 0xFFFF;
128const pj_uint16_t PJ_IP_MULTICAST_TTL = 0xFFFF;
129const pj_uint16_t PJ_IP_MULTICAST_LOOP = 0xFFFF;
130const pj_uint16_t PJ_IP_ADD_MEMBERSHIP = 0xFFFF;
131const pj_uint16_t PJ_IP_DROP_MEMBERSHIP = 0xFFFF;
132#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000133
Benny Prijono57dc48b2006-12-25 06:39:33 +0000134/* recv() and send() flags */
135const int PJ_MSG_OOB = MSG_OOB;
136const int PJ_MSG_PEEK = MSG_PEEK;
137const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
138
139
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000140#if 0
141static void CHECK_ADDR_LEN(const pj_sockaddr *addr, int len)
142{
143 pj_sockaddr *a = (pj_sockaddr*)addr;
144 pj_assert((a->addr.sa_family==PJ_AF_INET && len==sizeof(pj_sockaddr_in)) ||
145 (a->addr.sa_family==PJ_AF_INET6 && len==sizeof(pj_sockaddr_in6)));
146
147}
148#else
149#define CHECK_ADDR_LEN(addr,len)
150#endif
151
Benny Prijono9033e312005-11-21 02:08:39 +0000152/*
153 * Convert 16-bit value from network byte order to host byte order.
154 */
155PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
156{
157 return ntohs(netshort);
158}
159
160/*
161 * Convert 16-bit value from host byte order to network byte order.
162 */
163PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
164{
165 return htons(hostshort);
166}
167
168/*
169 * Convert 32-bit value from network byte order to host byte order.
170 */
171PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
172{
173 return ntohl(netlong);
174}
175
176/*
177 * Convert 32-bit value from host byte order to network byte order.
178 */
179PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
180{
181 return htonl(hostlong);
182}
183
184/*
185 * Convert an Internet host address given in network byte order
186 * to string in standard numbers and dots notation.
187 */
188PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
189{
190#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
191 return inet_ntoa(*(struct in_addr*)&inaddr);
192#else
193 struct in_addr addr;
194 addr.s_addr = inaddr.s_addr;
195 return inet_ntoa(addr);
196#endif
197}
198
199/*
200 * This function converts the Internet host address cp from the standard
201 * numbers-and-dots notation into binary data and stores it in the structure
202 * that inp points to.
203 */
204PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
205{
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000206 char tempaddr[PJ_INET_ADDRSTRLEN];
Benny Prijono9033e312005-11-21 02:08:39 +0000207
208 /* Initialize output with PJ_INADDR_NONE.
209 * Some apps relies on this instead of the return value
210 * (and anyway the return value is quite confusing!)
211 */
212 inp->s_addr = PJ_INADDR_NONE;
213
214 /* Caution:
215 * this function might be called with cp->slen >= 16
216 * (i.e. when called with hostname to check if it's an IP addr).
217 */
218 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000219 if (cp->slen >= PJ_INET_ADDRSTRLEN) {
Benny Prijono9033e312005-11-21 02:08:39 +0000220 return 0;
221 }
222
223 pj_memcpy(tempaddr, cp->ptr, cp->slen);
224 tempaddr[cp->slen] = '\0';
225
226#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
227 return inet_aton(tempaddr, (struct in_addr*)inp);
228#else
229 inp->s_addr = inet_addr(tempaddr);
230 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
231#endif
232}
233
234/*
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000235 * Convert text to IPv4/IPv6 address.
236 */
237PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
238{
239 char tempaddr[PJ_INET6_ADDRSTRLEN];
240
Benny Prijono62b86eb2007-12-01 08:52:57 +0000241 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000242 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
243
244 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
245 * compatible with pj_inet_aton()
246 */
247 if (af==PJ_AF_INET) {
248 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
249 }
250
251 /* Caution:
252 * this function might be called with cp->slen >= 46
253 * (i.e. when called with hostname to check if it's an IP addr).
254 */
255 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
256 return PJ_ENAMETOOLONG;
257 }
258
259 pj_memcpy(tempaddr, src->ptr, src->slen);
260 tempaddr[src->slen] = '\0';
261
262#if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
263 /*
264 * Implementation using inet_pton()
265 */
266 if (inet_pton(af, tempaddr, dst) != 1) {
267 pj_status_t status = pj_get_netos_error();
268 if (status == PJ_SUCCESS)
269 status = PJ_EUNKNOWN;
270
271 return status;
272 }
273
274 return PJ_SUCCESS;
275
276#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
277 /*
278 * Implementation on Windows, using WSAStringToAddress().
279 * Should also work on Unicode systems.
280 */
281 {
282 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
283 pj_sockaddr sock_addr;
284 int addr_len = sizeof(sock_addr);
285 int rc;
286
287 sock_addr.addr.sa_family = (pj_uint16_t)af;
288 rc = WSAStringToAddress(
289 PJ_STRING_TO_NATIVE(tempaddr,wtempaddr,sizeof(wtempaddr)),
290 af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
291 if (rc != 0) {
Benny Prijonoa199cb72008-12-19 14:36:08 +0000292 /* If you get rc 130022 Invalid argument (WSAEINVAL) with IPv6,
293 * check that you have IPv6 enabled (install it in the network
294 * adapter).
295 */
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000296 pj_status_t status = pj_get_netos_error();
297 if (status == PJ_SUCCESS)
298 status = PJ_EUNKNOWN;
299
300 return status;
301 }
302
303 if (sock_addr.addr.sa_family == PJ_AF_INET) {
304 pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
305 return PJ_SUCCESS;
306 } else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
307 pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
308 return PJ_SUCCESS;
309 } else {
310 pj_assert(!"Shouldn't happen");
311 return PJ_EBUG;
312 }
313 }
314#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
315 /* IPv6 support is disabled, just return error without raising assertion */
316 return PJ_EIPV6NOTSUP;
317#else
318 pj_assert(!"Not supported");
319 return PJ_EIPV6NOTSUP;
320#endif
321}
322
323/*
324 * Convert IPv4/IPv6 address to text.
325 */
326PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
327 char *dst, int size)
328
329{
330 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
Benny Prijono444ef3f2007-11-20 09:47:32 +0000331
332 *dst = '\0';
333
Benny Prijono62b86eb2007-12-01 08:52:57 +0000334 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000335
336#if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
337 /*
338 * Implementation using inet_ntop()
339 */
340 if (inet_ntop(af, src, dst, size) == NULL) {
341 pj_status_t status = pj_get_netos_error();
342 if (status == PJ_SUCCESS)
343 status = PJ_EUNKNOWN;
344
345 return status;
346 }
347
348 return PJ_SUCCESS;
349
350#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
351 /*
352 * Implementation on Windows, using WSAAddressToString().
353 * Should also work on Unicode systems.
354 */
355 {
356 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
357 pj_sockaddr sock_addr;
358 DWORD addr_len, addr_str_len;
359 int rc;
360
361 pj_bzero(&sock_addr, sizeof(sock_addr));
362 sock_addr.addr.sa_family = (pj_uint16_t)af;
363 if (af == PJ_AF_INET) {
364 if (size < PJ_INET_ADDRSTRLEN)
365 return PJ_ETOOSMALL;
366 pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
367 addr_len = sizeof(pj_sockaddr_in);
368 addr_str_len = PJ_INET_ADDRSTRLEN;
369 } else if (af == PJ_AF_INET6) {
370 if (size < PJ_INET6_ADDRSTRLEN)
371 return PJ_ETOOSMALL;
372 pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
373 addr_len = sizeof(pj_sockaddr_in6);
374 addr_str_len = PJ_INET6_ADDRSTRLEN;
375 } else {
376 pj_assert(!"Unsupported address family");
Benny Prijono62b86eb2007-12-01 08:52:57 +0000377 return PJ_EAFNOTSUP;
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000378 }
379
380#if PJ_NATIVE_STRING_IS_UNICODE
381 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
Benny Prijonoab872f22008-01-04 17:56:28 +0000382 NULL, wtempaddr, &addr_str_len);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000383 if (rc == 0) {
384 pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
385 }
386#else
387 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
388 NULL, dst, &addr_str_len);
389#endif
390
391 if (rc != 0) {
392 pj_status_t status = pj_get_netos_error();
393 if (status == PJ_SUCCESS)
394 status = PJ_EUNKNOWN;
395
396 return status;
397 }
398
399 return PJ_SUCCESS;
400 }
401
402#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
403 /* IPv6 support is disabled, just return error without raising assertion */
404 return PJ_EIPV6NOTSUP;
405#else
406 pj_assert(!"Not supported");
407 return PJ_EIPV6NOTSUP;
408#endif
409}
410
411/*
Benny Prijono9033e312005-11-21 02:08:39 +0000412 * Get hostname.
413 */
414PJ_DEF(const pj_str_t*) pj_gethostname(void)
415{
416 static char buf[PJ_MAX_HOSTNAME];
417 static pj_str_t hostname;
418
419 PJ_CHECK_STACK();
420
421 if (hostname.ptr == NULL) {
422 hostname.ptr = buf;
423 if (gethostname(buf, sizeof(buf)) != 0) {
424 hostname.ptr[0] = '\0';
425 hostname.slen = 0;
426 } else {
427 hostname.slen = strlen(buf);
428 }
429 }
430 return &hostname;
431}
432
Benny Prijono9033e312005-11-21 02:08:39 +0000433#if defined(PJ_WIN32)
434/*
435 * Create new socket/endpoint for communication and returns a descriptor.
436 */
437PJ_DEF(pj_status_t) pj_sock_socket(int af,
438 int type,
439 int proto,
440 pj_sock_t *sock)
441{
442 PJ_CHECK_STACK();
443
444 /* Sanity checks. */
445 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
446 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
447 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
448
449 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
450
451 if (*sock == PJ_INVALID_SOCKET)
452 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
453 else
454 return PJ_SUCCESS;
455}
456
457#else
458/*
459 * Create new socket/endpoint for communication and returns a descriptor.
460 */
461PJ_DEF(pj_status_t) pj_sock_socket(int af,
462 int type,
463 int proto,
464 pj_sock_t *sock)
465{
466
467 PJ_CHECK_STACK();
468
469 /* Sanity checks. */
470 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
471 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
472 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
473
474 *sock = socket(af, type, proto);
475 if (*sock == PJ_INVALID_SOCKET)
476 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
477 else
478 return PJ_SUCCESS;
479}
480#endif
481
Benny Prijono9033e312005-11-21 02:08:39 +0000482/*
483 * Bind socket.
484 */
485PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
486 const pj_sockaddr_t *addr,
487 int len)
488{
489 PJ_CHECK_STACK();
490
Benny Prijonoa1e69682007-05-11 15:14:34 +0000491 PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000492
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000493 CHECK_ADDR_LEN(addr, len);
494
Benny Prijono9033e312005-11-21 02:08:39 +0000495 if (bind(sock, (struct sockaddr*)addr, len) != 0)
496 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
497 else
498 return PJ_SUCCESS;
499}
500
501
502/*
503 * Bind socket.
504 */
505PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
506 pj_uint32_t addr32,
507 pj_uint16_t port)
508{
509 pj_sockaddr_in addr;
510
511 PJ_CHECK_STACK();
512
Benny Prijono62b86eb2007-12-01 08:52:57 +0000513 PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
Benny Prijono9033e312005-11-21 02:08:39 +0000514 addr.sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000515 pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000516 addr.sin_addr.s_addr = pj_htonl(addr32);
517 addr.sin_port = pj_htons(port);
518
519 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
520}
521
522
523/*
524 * Close socket.
525 */
526PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
527{
528 int rc;
529
530 PJ_CHECK_STACK();
Benny Prijono9cf138e2006-01-19 03:58:29 +0000531#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
532 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000533 rc = closesocket(sock);
534#else
535 rc = close(sock);
536#endif
537
538 if (rc != 0)
539 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
540 else
541 return PJ_SUCCESS;
542}
543
544/*
545 * Get remote's name.
546 */
547PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
548 pj_sockaddr_t *addr,
549 int *namelen)
550{
551 PJ_CHECK_STACK();
552 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
553 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000554 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000555 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000556 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000557 }
Benny Prijono9033e312005-11-21 02:08:39 +0000558}
559
560/*
561 * Get socket name.
562 */
563PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
564 pj_sockaddr_t *addr,
565 int *namelen)
566{
567 PJ_CHECK_STACK();
568 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
569 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000570 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000571 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000572 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000573 }
Benny Prijono9033e312005-11-21 02:08:39 +0000574}
575
576/*
577 * Send data
578 */
579PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
580 const void *buf,
581 pj_ssize_t *len,
582 unsigned flags)
583{
584 PJ_CHECK_STACK();
585 PJ_ASSERT_RETURN(len, PJ_EINVAL);
586
587 *len = send(sock, (const char*)buf, *len, flags);
588
589 if (*len < 0)
590 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
591 else
592 return PJ_SUCCESS;
593}
594
595
596/*
597 * Send data.
598 */
599PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
600 const void *buf,
601 pj_ssize_t *len,
602 unsigned flags,
603 const pj_sockaddr_t *to,
604 int tolen)
605{
606 PJ_CHECK_STACK();
607 PJ_ASSERT_RETURN(len, PJ_EINVAL);
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000608
609 CHECK_ADDR_LEN(to, tolen);
Benny Prijono9033e312005-11-21 02:08:39 +0000610
611 *len = sendto(sock, (const char*)buf, *len, flags,
612 (const struct sockaddr*)to, tolen);
613
614 if (*len < 0)
615 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
616 else
617 return PJ_SUCCESS;
618}
619
620/*
621 * Receive data.
622 */
623PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
624 void *buf,
625 pj_ssize_t *len,
626 unsigned flags)
627{
628 PJ_CHECK_STACK();
629 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
630
631 *len = recv(sock, (char*)buf, *len, flags);
632
633 if (*len < 0)
634 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
635 else
636 return PJ_SUCCESS;
637}
638
639/*
640 * Receive data.
641 */
642PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
643 void *buf,
644 pj_ssize_t *len,
645 unsigned flags,
646 pj_sockaddr_t *from,
647 int *fromlen)
648{
649 PJ_CHECK_STACK();
650 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
651 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
652
653 *len = recvfrom(sock, (char*)buf, *len, flags,
654 (struct sockaddr*)from, (socklen_t*)fromlen);
655
656 if (*len < 0)
657 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000658 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000659 PJ_SOCKADDR_RESET_LEN(from);
Benny Prijono9033e312005-11-21 02:08:39 +0000660 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000661 }
Benny Prijono9033e312005-11-21 02:08:39 +0000662}
663
664/*
665 * Get socket option.
666 */
667PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
668 pj_uint16_t level,
669 pj_uint16_t optname,
670 void *optval,
671 int *optlen)
672{
673 PJ_CHECK_STACK();
674 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
675
676 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
677 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
678 else
679 return PJ_SUCCESS;
680}
681
682/*
683 * Set socket option.
684 */
685PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
686 pj_uint16_t level,
687 pj_uint16_t optname,
688 const void *optval,
689 int optlen)
690{
691 PJ_CHECK_STACK();
692 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
693 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
694 else
695 return PJ_SUCCESS;
696}
697
698/*
Benny Prijono3d327302006-02-08 11:14:03 +0000699 * Connect socket.
700 */
701PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
702 const pj_sockaddr_t *addr,
703 int namelen)
704{
705 PJ_CHECK_STACK();
706 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
707 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
708 else
709 return PJ_SUCCESS;
710}
711
712
713/*
Benny Prijono9033e312005-11-21 02:08:39 +0000714 * Shutdown socket.
715 */
716#if PJ_HAS_TCP
717PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
718 int how)
719{
720 PJ_CHECK_STACK();
721 if (shutdown(sock, how) != 0)
722 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
723 else
724 return PJ_SUCCESS;
725}
726
727/*
728 * Start listening to incoming connections.
729 */
730PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
731 int backlog)
732{
733 PJ_CHECK_STACK();
734 if (listen(sock, backlog) != 0)
735 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
736 else
737 return PJ_SUCCESS;
738}
739
740/*
Benny Prijono9033e312005-11-21 02:08:39 +0000741 * Accept incoming connections
742 */
743PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
744 pj_sock_t *newsock,
745 pj_sockaddr_t *addr,
746 int *addrlen)
747{
748 PJ_CHECK_STACK();
749 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
750
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000751#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
752 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000753 PJ_SOCKADDR_SET_LEN(addr, *addrlen);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000754 }
755#endif
756
Benny Prijono9033e312005-11-21 02:08:39 +0000757 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
758 if (*newsock==PJ_INVALID_SOCKET)
759 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000760 else {
761
762#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
763 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000764 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000765 }
766#endif
767
Benny Prijono9033e312005-11-21 02:08:39 +0000768 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000769 }
Benny Prijono9033e312005-11-21 02:08:39 +0000770}
771#endif /* PJ_HAS_TCP */
772
773