blob: 21c10d195e7ecfc4ff45c301a77c4f238fa310bd [file] [log] [blame]
Benny Prijono4766ffe2005-11-01 17:56:59 +00001/* $Id$
Benny Prijonodd859a62005-11-01 16:42:51 +00002 */
3#include <pj/sock.h>
4#include <pj/os.h>
5#include <pj/assert.h>
6#include <pj/string.h>
7#include <pj/compat/socket.h>
8#include <pj/addr_resolv.h>
9#include <pj/errno.h>
10
11/*
12 * Address families conversion.
13 * The values here are indexed based on pj_addr_family-0xFF00.
14 */
15const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
16const pj_uint16_t PJ_AF_INET = AF_INET;
17const pj_uint16_t PJ_AF_INET6 = AF_INET6;
18#ifdef AF_PACKET
19const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
20#else
21const pj_uint16_t PJ_AF_PACKET = 0xFFFF;
22#endif
23#ifdef AF_IRDA
24const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
25#else
26const pj_uint16_t PJ_AF_IRDA = 0xFFFF;
27#endif
28
29/*
30 * Socket types conversion.
31 * The values here are indexed based on pj_sock_type-0xFF00
32 */
33const pj_uint16_t PJ_SOCK_STREAM = SOCK_STREAM;
34const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
35const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
36const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
37
38/*
39 * Socket level values.
40 */
41const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
42#ifdef SOL_IP
43const pj_uint16_t PJ_SOL_IP = SOL_IP;
44#else
45const pj_uint16_t PJ_SOL_IP = 0xFFFF;
46#endif /* SOL_IP */
47#if defined(SOL_TCP)
48const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
49#elif defined(IPPROTO_TCP)
50const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP;
51#endif /* SOL_TCP */
52#ifdef SOL_UDP
53const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
54#else
55const pj_uint16_t PJ_SOL_UDP = 0xFFFF;
56#endif
57#ifdef SOL_IPV6
58const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
59#else
60const pj_uint16_t PJ_SOL_IPV6 = 0xFFFF;
61#endif
Benny Prijono4d974f32005-11-06 13:32:11 +000062
63/* optname values. */
64const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
65const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
66const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
67
Benny Prijonodd859a62005-11-01 16:42:51 +000068
69/*
70 * Convert 16-bit value from network byte order to host byte order.
71 */
72PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
73{
74 return ntohs(netshort);
75}
76
77/*
78 * Convert 16-bit value from host byte order to network byte order.
79 */
80PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
81{
82 return htons(hostshort);
83}
84
85/*
86 * Convert 32-bit value from network byte order to host byte order.
87 */
88PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
89{
90 return ntohl(netlong);
91}
92
93/*
94 * Convert 32-bit value from host byte order to network byte order.
95 */
96PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
97{
98 return htonl(hostlong);
99}
100
101/*
102 * Convert an Internet host address given in network byte order
103 * to string in standard numbers and dots notation.
104 */
105PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
106{
Benny Prijonobc986152005-11-06 16:50:38 +0000107 struct in_addr addr;
108 addr.s_addr = inaddr.s_addr;
109 return inet_ntoa(addr);
Benny Prijonodd859a62005-11-01 16:42:51 +0000110}
111
112/*
113 * This function converts the Internet host address cp from the standard
114 * numbers-and-dots notation into binary data and stores it in the structure
115 * that inp points to.
116 */
117PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
118{
119 char tempaddr[16];
120
121 /* Initialize output with PJ_INADDR_NONE.
122 * Some apps relies on this instead of the return value
123 * (and anyway the return value is quite confusing!)
124 */
125 inp->s_addr = PJ_INADDR_NONE;
126
127 /* Caution:
128 * this function might be called with cp->slen >= 16
129 * (i.e. when called with hostname to check if it's an IP addr).
130 */
131 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
132 if (cp->slen >= 16) {
133 return 0;
134 }
135
136 pj_memcpy(tempaddr, cp->ptr, cp->slen);
137 tempaddr[cp->slen] = '\0';
138
139#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
140 return inet_aton(tempaddr, (struct in_addr*)inp);
141#else
142 inp->s_addr = inet_addr(tempaddr);
143 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
144#endif
145}
146
147/*
148 * Convert address string with numbers and dots to binary IP address.
149 */
150PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
151{
152 pj_in_addr addr;
153
154 pj_inet_aton(cp, &addr);
155 return addr;
156}
157
158/*
159 * Set the IP address of an IP socket address from string address,
160 * with resolving the host if necessary. The string address may be in a
161 * standard numbers and dots notation or may be a hostname. If hostname
162 * is specified, then the function will resolve the host into the IP
163 * address.
164 */
165PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
166 const pj_str_t *str_addr)
167{
168 PJ_CHECK_STACK();
169
170 PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME,
171 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
172
173 addr->sin_family = AF_INET;
174
175 if (str_addr && str_addr->slen) {
176 addr->sin_addr = pj_inet_addr(str_addr);
177 if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
178 pj_hostent he;
179 pj_status_t rc;
180
181 rc = pj_gethostbyname(str_addr, &he);
182 if (rc == 0) {
183 addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
184 } else {
185 addr->sin_addr.s_addr = PJ_INADDR_NONE;
186 return rc;
187 }
188 }
189
190 } else {
191 addr->sin_addr.s_addr = 0;
192 }
193
194 return PJ_SUCCESS;
195}
196
197/*
198 * Set the IP address and port of an IP socket address.
199 * The string address may be in a standard numbers and dots notation or
200 * may be a hostname. If hostname is specified, then the function will
201 * resolve the host into the IP address.
202 */
203PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
204 const pj_str_t *str_addr,
205 pj_uint16_t port)
206{
207 PJ_ASSERT_RETURN(addr && str_addr,
208 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
209
210 addr->sin_family = PJ_AF_INET;
211 pj_sockaddr_in_set_port(addr, port);
212 return pj_sockaddr_in_set_str_addr(addr, str_addr);
213}
214
215
216/*
217 * Get hostname.
218 */
219PJ_DEF(const pj_str_t*) pj_gethostname(void)
220{
221 static char buf[PJ_MAX_HOSTNAME];
222 static pj_str_t hostname;
223
224 PJ_CHECK_STACK();
225
226 if (hostname.ptr == NULL) {
227 hostname.ptr = buf;
228 if (gethostname(buf, sizeof(buf)) != 0) {
229 hostname.ptr[0] = '\0';
230 hostname.slen = 0;
231 } else {
232 hostname.slen = strlen(buf);
233 }
234 }
235 return &hostname;
236}
237
238/*
239 * Get first IP address associated with the hostname.
240 */
241PJ_DEF(pj_in_addr) pj_gethostaddr(void)
242{
243 pj_sockaddr_in addr;
244 const pj_str_t *hostname = pj_gethostname();
245
246 pj_sockaddr_in_set_str_addr(&addr, hostname);
247 return addr.sin_addr;
248}
249
250
251#if defined(PJ_WIN32)
252/*
253 * Create new socket/endpoint for communication and returns a descriptor.
254 */
255PJ_DEF(pj_status_t) pj_sock_socket(int af,
256 int type,
257 int proto,
258 pj_sock_t *sock)
259{
260 PJ_CHECK_STACK();
261
262 /* Sanity checks. */
263 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
264 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
265 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
266
267 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
268
269 if (*sock == PJ_INVALID_SOCKET)
270 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
271 else
272 return PJ_SUCCESS;
273}
274
275#else
276/*
277 * Create new socket/endpoint for communication and returns a descriptor.
278 */
279PJ_DEF(pj_status_t) pj_sock_socket(int af,
280 int type,
281 int proto,
282 pj_sock_t *sock)
283{
284
285 PJ_CHECK_STACK();
286
287 /* Sanity checks. */
288 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
289 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
290 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
291
292 *sock = socket(af, type, proto);
293 if (*sock == PJ_INVALID_SOCKET)
294 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
295 else
296 return PJ_SUCCESS;
297}
298#endif
299
300
301/*
302 * Bind socket.
303 */
304PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
305 const pj_sockaddr_t *addr,
306 int len)
307{
308 PJ_CHECK_STACK();
309
310 PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);
311
312 if (bind(sock, (struct sockaddr*)addr, len) != 0)
313 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
314 else
315 return PJ_SUCCESS;
316}
317
318
319/*
320 * Bind socket.
321 */
322PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
323 pj_uint32_t addr32,
324 pj_uint16_t port)
325{
326 pj_sockaddr_in addr;
327
328 PJ_CHECK_STACK();
329
330 addr.sin_family = PJ_AF_INET;
331 addr.sin_addr.s_addr = pj_htonl(addr32);
332 addr.sin_port = pj_htons(port);
333
334 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
335}
336
337
338/*
339 * Close socket.
340 */
341PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
342{
343 int rc;
344
345 PJ_CHECK_STACK();
346#if defined(PJ_WIN32) && PJ_WIN32==1
347 rc = closesocket(sock);
348#else
349 rc = close(sock);
350#endif
351
352 if (rc != 0)
353 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
354 else
355 return PJ_SUCCESS;
356}
357
358/*
359 * Get remote's name.
360 */
361PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
362 pj_sockaddr_t *addr,
363 int *namelen)
364{
365 PJ_CHECK_STACK();
366 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
367 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
368 else
369 return PJ_SUCCESS;
370}
371
372/*
373 * Get socket name.
374 */
375PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
376 pj_sockaddr_t *addr,
377 int *namelen)
378{
379 PJ_CHECK_STACK();
380 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
381 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
382 else
383 return PJ_SUCCESS;
384}
385
386/*
387 * Send data
388 */
389PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
390 const void *buf,
391 pj_ssize_t *len,
392 unsigned flags)
393{
394 PJ_CHECK_STACK();
395 PJ_ASSERT_RETURN(len, PJ_EINVAL);
396
397 *len = send(sock, (const char*)buf, *len, flags);
398
399 if (*len < 0)
400 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
401 else
402 return PJ_SUCCESS;
403}
404
405
406/*
407 * Send data.
408 */
409PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
410 const void *buf,
411 pj_ssize_t *len,
412 unsigned flags,
413 const pj_sockaddr_t *to,
414 int tolen)
415{
416 PJ_CHECK_STACK();
417 PJ_ASSERT_RETURN(len, PJ_EINVAL);
418
419 *len = sendto(sock, (const char*)buf, *len, flags,
420 (const struct sockaddr*)to, tolen);
421
422 if (*len < 0)
423 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
424 else
425 return PJ_SUCCESS;
426}
427
428/*
429 * Receive data.
430 */
431PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
432 void *buf,
433 pj_ssize_t *len,
434 unsigned flags)
435{
436 PJ_CHECK_STACK();
437 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
438
439 *len = recv(sock, (char*)buf, *len, flags);
440
441 if (*len < 0)
442 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
443 else
444 return PJ_SUCCESS;
445}
446
447/*
448 * Receive data.
449 */
450PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
451 void *buf,
452 pj_ssize_t *len,
453 unsigned flags,
454 pj_sockaddr_t *from,
455 int *fromlen)
456{
457 PJ_CHECK_STACK();
458 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
459 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
460
461 *len = recvfrom(sock, (char*)buf, *len, flags,
462 (struct sockaddr*)from, (socklen_t*)fromlen);
463
464 if (*len < 0)
465 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
466 else
467 return PJ_SUCCESS;
468}
469
470/*
471 * Get socket option.
472 */
473PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
Benny Prijono4d974f32005-11-06 13:32:11 +0000474 pj_uint16_t level,
475 pj_uint16_t optname,
Benny Prijonodd859a62005-11-01 16:42:51 +0000476 void *optval,
477 int *optlen)
478{
479 PJ_CHECK_STACK();
480 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
481
482 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
483 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
484 else
485 return PJ_SUCCESS;
486}
487
488/*
489 * Set socket option.
490 */
491PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
Benny Prijono4d974f32005-11-06 13:32:11 +0000492 pj_uint16_t level,
493 pj_uint16_t optname,
Benny Prijonodd859a62005-11-01 16:42:51 +0000494 const void *optval,
495 int optlen)
496{
497 PJ_CHECK_STACK();
498 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
499 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
500 else
501 return PJ_SUCCESS;
502}
503
504/*
505 * Shutdown socket.
506 */
507#if PJ_HAS_TCP
508PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
509 int how)
510{
511 PJ_CHECK_STACK();
512 if (shutdown(sock, how) != 0)
513 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
514 else
515 return PJ_SUCCESS;
516}
517
518/*
519 * Start listening to incoming connections.
520 */
521PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
522 int backlog)
523{
524 PJ_CHECK_STACK();
525 if (listen(sock, backlog) != 0)
526 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
527 else
528 return PJ_SUCCESS;
529}
530
531/*
532 * Connect socket.
533 */
534PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
535 const pj_sockaddr_t *addr,
536 int namelen)
537{
538 PJ_CHECK_STACK();
539 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
540 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
541 else
542 return PJ_SUCCESS;
543}
544
545/*
546 * Accept incoming connections
547 */
548PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
549 pj_sock_t *newsock,
550 pj_sockaddr_t *addr,
551 int *addrlen)
552{
553 PJ_CHECK_STACK();
554 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
555
556 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
557 if (*newsock==PJ_INVALID_SOCKET)
558 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
559 else
560 return PJ_SUCCESS;
561}
562#endif /* PJ_HAS_TCP */
563
564