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