blob: fa5eaff88c6856f159d0183bc7fd9b0308728790 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C)2003-2007 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;
118
119
Benny Prijono57dc48b2006-12-25 06:39:33 +0000120/* recv() and send() flags */
121const int PJ_MSG_OOB = MSG_OOB;
122const int PJ_MSG_PEEK = MSG_PEEK;
123const int PJ_MSG_DONTROUTE = MSG_DONTROUTE;
124
125
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000126#if 0
127static void CHECK_ADDR_LEN(const pj_sockaddr *addr, int len)
128{
129 pj_sockaddr *a = (pj_sockaddr*)addr;
130 pj_assert((a->addr.sa_family==PJ_AF_INET && len==sizeof(pj_sockaddr_in)) ||
131 (a->addr.sa_family==PJ_AF_INET6 && len==sizeof(pj_sockaddr_in6)));
132
133}
134#else
135#define CHECK_ADDR_LEN(addr,len)
136#endif
137
Benny Prijono9033e312005-11-21 02:08:39 +0000138/*
139 * Convert 16-bit value from network byte order to host byte order.
140 */
141PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
142{
143 return ntohs(netshort);
144}
145
146/*
147 * Convert 16-bit value from host byte order to network byte order.
148 */
149PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
150{
151 return htons(hostshort);
152}
153
154/*
155 * Convert 32-bit value from network byte order to host byte order.
156 */
157PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
158{
159 return ntohl(netlong);
160}
161
162/*
163 * Convert 32-bit value from host byte order to network byte order.
164 */
165PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
166{
167 return htonl(hostlong);
168}
169
170/*
171 * Convert an Internet host address given in network byte order
172 * to string in standard numbers and dots notation.
173 */
174PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
175{
176#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
177 return inet_ntoa(*(struct in_addr*)&inaddr);
178#else
179 struct in_addr addr;
180 addr.s_addr = inaddr.s_addr;
181 return inet_ntoa(addr);
182#endif
183}
184
185/*
186 * This function converts the Internet host address cp from the standard
187 * numbers-and-dots notation into binary data and stores it in the structure
188 * that inp points to.
189 */
190PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
191{
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000192 char tempaddr[PJ_INET_ADDRSTRLEN];
Benny Prijono9033e312005-11-21 02:08:39 +0000193
194 /* Initialize output with PJ_INADDR_NONE.
195 * Some apps relies on this instead of the return value
196 * (and anyway the return value is quite confusing!)
197 */
198 inp->s_addr = PJ_INADDR_NONE;
199
200 /* Caution:
201 * this function might be called with cp->slen >= 16
202 * (i.e. when called with hostname to check if it's an IP addr).
203 */
204 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000205 if (cp->slen >= PJ_INET_ADDRSTRLEN) {
Benny Prijono9033e312005-11-21 02:08:39 +0000206 return 0;
207 }
208
209 pj_memcpy(tempaddr, cp->ptr, cp->slen);
210 tempaddr[cp->slen] = '\0';
211
212#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
213 return inet_aton(tempaddr, (struct in_addr*)inp);
214#else
215 inp->s_addr = inet_addr(tempaddr);
216 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
217#endif
218}
219
220/*
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000221 * Convert text to IPv4/IPv6 address.
222 */
223PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
224{
225 char tempaddr[PJ_INET6_ADDRSTRLEN];
226
Benny Prijono62b86eb2007-12-01 08:52:57 +0000227 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000228 PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);
229
230 /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be
231 * compatible with pj_inet_aton()
232 */
233 if (af==PJ_AF_INET) {
234 ((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
235 }
236
237 /* Caution:
238 * this function might be called with cp->slen >= 46
239 * (i.e. when called with hostname to check if it's an IP addr).
240 */
241 if (src->slen >= PJ_INET6_ADDRSTRLEN) {
242 return PJ_ENAMETOOLONG;
243 }
244
245 pj_memcpy(tempaddr, src->ptr, src->slen);
246 tempaddr[src->slen] = '\0';
247
248#if defined(PJ_SOCK_HAS_INET_PTON) && PJ_SOCK_HAS_INET_PTON != 0
249 /*
250 * Implementation using inet_pton()
251 */
252 if (inet_pton(af, tempaddr, dst) != 1) {
253 pj_status_t status = pj_get_netos_error();
254 if (status == PJ_SUCCESS)
255 status = PJ_EUNKNOWN;
256
257 return status;
258 }
259
260 return PJ_SUCCESS;
261
262#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
263 /*
264 * Implementation on Windows, using WSAStringToAddress().
265 * Should also work on Unicode systems.
266 */
267 {
268 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
269 pj_sockaddr sock_addr;
270 int addr_len = sizeof(sock_addr);
271 int rc;
272
273 sock_addr.addr.sa_family = (pj_uint16_t)af;
274 rc = WSAStringToAddress(
275 PJ_STRING_TO_NATIVE(tempaddr,wtempaddr,sizeof(wtempaddr)),
276 af, NULL, (LPSOCKADDR)&sock_addr, &addr_len);
277 if (rc != 0) {
278 pj_status_t status = pj_get_netos_error();
279 if (status == PJ_SUCCESS)
280 status = PJ_EUNKNOWN;
281
282 return status;
283 }
284
285 if (sock_addr.addr.sa_family == PJ_AF_INET) {
286 pj_memcpy(dst, &sock_addr.ipv4.sin_addr, 4);
287 return PJ_SUCCESS;
288 } else if (sock_addr.addr.sa_family == PJ_AF_INET6) {
289 pj_memcpy(dst, &sock_addr.ipv6.sin6_addr, 16);
290 return PJ_SUCCESS;
291 } else {
292 pj_assert(!"Shouldn't happen");
293 return PJ_EBUG;
294 }
295 }
296#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
297 /* IPv6 support is disabled, just return error without raising assertion */
298 return PJ_EIPV6NOTSUP;
299#else
300 pj_assert(!"Not supported");
301 return PJ_EIPV6NOTSUP;
302#endif
303}
304
305/*
306 * Convert IPv4/IPv6 address to text.
307 */
308PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src,
309 char *dst, int size)
310
311{
312 PJ_ASSERT_RETURN(src && dst && size, PJ_EINVAL);
Benny Prijono444ef3f2007-11-20 09:47:32 +0000313
314 *dst = '\0';
315
Benny Prijono62b86eb2007-12-01 08:52:57 +0000316 PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000317
318#if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0
319 /*
320 * Implementation using inet_ntop()
321 */
322 if (inet_ntop(af, src, dst, size) == NULL) {
323 pj_status_t status = pj_get_netos_error();
324 if (status == PJ_SUCCESS)
325 status = PJ_EUNKNOWN;
326
327 return status;
328 }
329
330 return PJ_SUCCESS;
331
332#elif defined(PJ_WIN32) || defined(PJ_WIN32_WINCE)
333 /*
334 * Implementation on Windows, using WSAAddressToString().
335 * Should also work on Unicode systems.
336 */
337 {
338 PJ_DECL_UNICODE_TEMP_BUF(wtempaddr,PJ_INET6_ADDRSTRLEN)
339 pj_sockaddr sock_addr;
340 DWORD addr_len, addr_str_len;
341 int rc;
342
343 pj_bzero(&sock_addr, sizeof(sock_addr));
344 sock_addr.addr.sa_family = (pj_uint16_t)af;
345 if (af == PJ_AF_INET) {
346 if (size < PJ_INET_ADDRSTRLEN)
347 return PJ_ETOOSMALL;
348 pj_memcpy(&sock_addr.ipv4.sin_addr, src, 4);
349 addr_len = sizeof(pj_sockaddr_in);
350 addr_str_len = PJ_INET_ADDRSTRLEN;
351 } else if (af == PJ_AF_INET6) {
352 if (size < PJ_INET6_ADDRSTRLEN)
353 return PJ_ETOOSMALL;
354 pj_memcpy(&sock_addr.ipv6.sin6_addr, src, 16);
355 addr_len = sizeof(pj_sockaddr_in6);
356 addr_str_len = PJ_INET6_ADDRSTRLEN;
357 } else {
358 pj_assert(!"Unsupported address family");
Benny Prijono62b86eb2007-12-01 08:52:57 +0000359 return PJ_EAFNOTSUP;
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000360 }
361
362#if PJ_NATIVE_STRING_IS_UNICODE
363 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
Benny Prijonoab872f22008-01-04 17:56:28 +0000364 NULL, wtempaddr, &addr_str_len);
Benny Prijonoc16c6e32007-11-18 14:53:47 +0000365 if (rc == 0) {
366 pj_unicode_to_ansi(wtempaddr, wcslen(wtempaddr), dst, size);
367 }
368#else
369 rc = WSAAddressToString((LPSOCKADDR)&sock_addr, addr_len,
370 NULL, dst, &addr_str_len);
371#endif
372
373 if (rc != 0) {
374 pj_status_t status = pj_get_netos_error();
375 if (status == PJ_SUCCESS)
376 status = PJ_EUNKNOWN;
377
378 return status;
379 }
380
381 return PJ_SUCCESS;
382 }
383
384#elif !defined(PJ_HAS_IPV6) || PJ_HAS_IPV6==0
385 /* IPv6 support is disabled, just return error without raising assertion */
386 return PJ_EIPV6NOTSUP;
387#else
388 pj_assert(!"Not supported");
389 return PJ_EIPV6NOTSUP;
390#endif
391}
392
393/*
Benny Prijono9033e312005-11-21 02:08:39 +0000394 * Get hostname.
395 */
396PJ_DEF(const pj_str_t*) pj_gethostname(void)
397{
398 static char buf[PJ_MAX_HOSTNAME];
399 static pj_str_t hostname;
400
401 PJ_CHECK_STACK();
402
403 if (hostname.ptr == NULL) {
404 hostname.ptr = buf;
405 if (gethostname(buf, sizeof(buf)) != 0) {
406 hostname.ptr[0] = '\0';
407 hostname.slen = 0;
408 } else {
409 hostname.slen = strlen(buf);
410 }
411 }
412 return &hostname;
413}
414
Benny Prijono9033e312005-11-21 02:08:39 +0000415#if defined(PJ_WIN32)
416/*
417 * Create new socket/endpoint for communication and returns a descriptor.
418 */
419PJ_DEF(pj_status_t) pj_sock_socket(int af,
420 int type,
421 int proto,
422 pj_sock_t *sock)
423{
424 PJ_CHECK_STACK();
425
426 /* Sanity checks. */
427 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
428 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
429 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
430
431 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
432
433 if (*sock == PJ_INVALID_SOCKET)
434 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
435 else
436 return PJ_SUCCESS;
437}
438
439#else
440/*
441 * Create new socket/endpoint for communication and returns a descriptor.
442 */
443PJ_DEF(pj_status_t) pj_sock_socket(int af,
444 int type,
445 int proto,
446 pj_sock_t *sock)
447{
448
449 PJ_CHECK_STACK();
450
451 /* Sanity checks. */
452 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
453 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
454 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
455
456 *sock = socket(af, type, proto);
457 if (*sock == PJ_INVALID_SOCKET)
458 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
459 else
460 return PJ_SUCCESS;
461}
462#endif
463
Benny Prijono9033e312005-11-21 02:08:39 +0000464/*
465 * Bind socket.
466 */
467PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
468 const pj_sockaddr_t *addr,
469 int len)
470{
471 PJ_CHECK_STACK();
472
Benny Prijonoa1e69682007-05-11 15:14:34 +0000473 PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000474
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000475 CHECK_ADDR_LEN(addr, len);
476
Benny Prijono9033e312005-11-21 02:08:39 +0000477 if (bind(sock, (struct sockaddr*)addr, len) != 0)
478 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
479 else
480 return PJ_SUCCESS;
481}
482
483
484/*
485 * Bind socket.
486 */
487PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
488 pj_uint32_t addr32,
489 pj_uint16_t port)
490{
491 pj_sockaddr_in addr;
492
493 PJ_CHECK_STACK();
494
Benny Prijono62b86eb2007-12-01 08:52:57 +0000495 PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in));
Benny Prijono9033e312005-11-21 02:08:39 +0000496 addr.sin_family = PJ_AF_INET;
Benny Prijonoac623b32006-07-03 15:19:31 +0000497 pj_bzero(addr.sin_zero, sizeof(addr.sin_zero));
Benny Prijono9033e312005-11-21 02:08:39 +0000498 addr.sin_addr.s_addr = pj_htonl(addr32);
499 addr.sin_port = pj_htons(port);
500
501 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
502}
503
504
505/*
506 * Close socket.
507 */
508PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
509{
510 int rc;
511
512 PJ_CHECK_STACK();
Benny Prijono9cf138e2006-01-19 03:58:29 +0000513#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
514 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000515 rc = closesocket(sock);
516#else
517 rc = close(sock);
518#endif
519
520 if (rc != 0)
521 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
522 else
523 return PJ_SUCCESS;
524}
525
526/*
527 * Get remote's name.
528 */
529PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
530 pj_sockaddr_t *addr,
531 int *namelen)
532{
533 PJ_CHECK_STACK();
534 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
535 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000536 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000537 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000538 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000539 }
Benny Prijono9033e312005-11-21 02:08:39 +0000540}
541
542/*
543 * Get socket name.
544 */
545PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
546 pj_sockaddr_t *addr,
547 int *namelen)
548{
549 PJ_CHECK_STACK();
550 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
551 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000552 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000553 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijono9033e312005-11-21 02:08:39 +0000554 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000555 }
Benny Prijono9033e312005-11-21 02:08:39 +0000556}
557
558/*
559 * Send data
560 */
561PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
562 const void *buf,
563 pj_ssize_t *len,
564 unsigned flags)
565{
566 PJ_CHECK_STACK();
567 PJ_ASSERT_RETURN(len, PJ_EINVAL);
568
569 *len = send(sock, (const char*)buf, *len, flags);
570
571 if (*len < 0)
572 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
573 else
574 return PJ_SUCCESS;
575}
576
577
578/*
579 * Send data.
580 */
581PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
582 const void *buf,
583 pj_ssize_t *len,
584 unsigned flags,
585 const pj_sockaddr_t *to,
586 int tolen)
587{
588 PJ_CHECK_STACK();
589 PJ_ASSERT_RETURN(len, PJ_EINVAL);
Benny Prijono5f55a1f2007-12-05 05:08:29 +0000590
591 CHECK_ADDR_LEN(to, tolen);
Benny Prijono9033e312005-11-21 02:08:39 +0000592
593 *len = sendto(sock, (const char*)buf, *len, flags,
594 (const struct sockaddr*)to, tolen);
595
596 if (*len < 0)
597 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
598 else
599 return PJ_SUCCESS;
600}
601
602/*
603 * Receive data.
604 */
605PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
606 void *buf,
607 pj_ssize_t *len,
608 unsigned flags)
609{
610 PJ_CHECK_STACK();
611 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
612
613 *len = recv(sock, (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 * Receive data.
623 */
624PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
625 void *buf,
626 pj_ssize_t *len,
627 unsigned flags,
628 pj_sockaddr_t *from,
629 int *fromlen)
630{
631 PJ_CHECK_STACK();
632 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
633 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
634
635 *len = recvfrom(sock, (char*)buf, *len, flags,
636 (struct sockaddr*)from, (socklen_t*)fromlen);
637
638 if (*len < 0)
639 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000640 else {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000641 PJ_SOCKADDR_RESET_LEN(from);
Benny Prijono9033e312005-11-21 02:08:39 +0000642 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000643 }
Benny Prijono9033e312005-11-21 02:08:39 +0000644}
645
646/*
647 * Get socket option.
648 */
649PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
650 pj_uint16_t level,
651 pj_uint16_t optname,
652 void *optval,
653 int *optlen)
654{
655 PJ_CHECK_STACK();
656 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
657
658 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
659 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
660 else
661 return PJ_SUCCESS;
662}
663
664/*
665 * Set socket option.
666 */
667PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
668 pj_uint16_t level,
669 pj_uint16_t optname,
670 const void *optval,
671 int optlen)
672{
673 PJ_CHECK_STACK();
674 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
675 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
676 else
677 return PJ_SUCCESS;
678}
679
680/*
Benny Prijono3d327302006-02-08 11:14:03 +0000681 * Connect socket.
682 */
683PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
684 const pj_sockaddr_t *addr,
685 int namelen)
686{
687 PJ_CHECK_STACK();
688 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
689 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
690 else
691 return PJ_SUCCESS;
692}
693
694
695/*
Benny Prijono9033e312005-11-21 02:08:39 +0000696 * Shutdown socket.
697 */
698#if PJ_HAS_TCP
699PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
700 int how)
701{
702 PJ_CHECK_STACK();
703 if (shutdown(sock, how) != 0)
704 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
705 else
706 return PJ_SUCCESS;
707}
708
709/*
710 * Start listening to incoming connections.
711 */
712PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
713 int backlog)
714{
715 PJ_CHECK_STACK();
716 if (listen(sock, backlog) != 0)
717 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
718 else
719 return PJ_SUCCESS;
720}
721
722/*
Benny Prijono9033e312005-11-21 02:08:39 +0000723 * Accept incoming connections
724 */
725PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
726 pj_sock_t *newsock,
727 pj_sockaddr_t *addr,
728 int *addrlen)
729{
730 PJ_CHECK_STACK();
731 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
732
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000733#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
734 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000735 PJ_SOCKADDR_SET_LEN(addr, *addrlen);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000736 }
737#endif
738
Benny Prijono9033e312005-11-21 02:08:39 +0000739 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
740 if (*newsock==PJ_INVALID_SOCKET)
741 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000742 else {
743
744#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0
745 if (addr) {
Benny Prijono62b86eb2007-12-01 08:52:57 +0000746 PJ_SOCKADDR_RESET_LEN(addr);
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000747 }
748#endif
749
Benny Prijono9033e312005-11-21 02:08:39 +0000750 return PJ_SUCCESS;
Benny Prijonoe67d99a2006-03-20 12:39:24 +0000751 }
Benny Prijono9033e312005-11-21 02:08:39 +0000752}
753#endif /* PJ_HAS_TCP */
754
755