blob: 8f1fa1dfe198a9a7903031555d5300436db09c73 [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)
Benny Prijonoce931fd2005-11-06 17:33:51 +0000106{
107#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
108 return inet_ntoa(*(struct in_addr*)&inaddr);
109#else
Benny Prijonobc986152005-11-06 16:50:38 +0000110 struct in_addr addr;
111 addr.s_addr = inaddr.s_addr;
Benny Prijonoce931fd2005-11-06 17:33:51 +0000112 return inet_ntoa(addr);
113#endif
Benny Prijonodd859a62005-11-01 16:42:51 +0000114}
115
116/*
117 * This function converts the Internet host address cp from the standard
118 * numbers-and-dots notation into binary data and stores it in the structure
119 * that inp points to.
120 */
121PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
122{
123 char tempaddr[16];
124
125 /* Initialize output with PJ_INADDR_NONE.
126 * Some apps relies on this instead of the return value
127 * (and anyway the return value is quite confusing!)
128 */
129 inp->s_addr = PJ_INADDR_NONE;
130
131 /* Caution:
132 * this function might be called with cp->slen >= 16
133 * (i.e. when called with hostname to check if it's an IP addr).
134 */
135 PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
136 if (cp->slen >= 16) {
137 return 0;
138 }
139
140 pj_memcpy(tempaddr, cp->ptr, cp->slen);
141 tempaddr[cp->slen] = '\0';
142
143#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
144 return inet_aton(tempaddr, (struct in_addr*)inp);
145#else
146 inp->s_addr = inet_addr(tempaddr);
147 return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
148#endif
149}
150
151/*
152 * Convert address string with numbers and dots to binary IP address.
153 */
154PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
155{
156 pj_in_addr addr;
157
158 pj_inet_aton(cp, &addr);
159 return addr;
160}
161
162/*
163 * Set the IP address of an IP socket address from string address,
164 * with resolving the host if necessary. The string address may be in a
165 * standard numbers and dots notation or may be a hostname. If hostname
166 * is specified, then the function will resolve the host into the IP
167 * address.
168 */
169PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
170 const pj_str_t *str_addr)
171{
172 PJ_CHECK_STACK();
173
174 PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME,
175 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
176
177 addr->sin_family = AF_INET;
178
179 if (str_addr && str_addr->slen) {
180 addr->sin_addr = pj_inet_addr(str_addr);
181 if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
182 pj_hostent he;
183 pj_status_t rc;
184
185 rc = pj_gethostbyname(str_addr, &he);
186 if (rc == 0) {
187 addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
188 } else {
189 addr->sin_addr.s_addr = PJ_INADDR_NONE;
190 return rc;
191 }
192 }
193
194 } else {
195 addr->sin_addr.s_addr = 0;
196 }
197
198 return PJ_SUCCESS;
199}
200
201/*
202 * Set the IP address and port of an IP socket address.
203 * The string address may be in a standard numbers and dots notation or
204 * may be a hostname. If hostname is specified, then the function will
205 * resolve the host into the IP address.
206 */
207PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
208 const pj_str_t *str_addr,
209 pj_uint16_t port)
210{
211 PJ_ASSERT_RETURN(addr && str_addr,
212 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
213
214 addr->sin_family = PJ_AF_INET;
215 pj_sockaddr_in_set_port(addr, port);
216 return pj_sockaddr_in_set_str_addr(addr, str_addr);
217}
218
219
220/*
221 * Get hostname.
222 */
223PJ_DEF(const pj_str_t*) pj_gethostname(void)
224{
225 static char buf[PJ_MAX_HOSTNAME];
226 static pj_str_t hostname;
227
228 PJ_CHECK_STACK();
229
230 if (hostname.ptr == NULL) {
231 hostname.ptr = buf;
232 if (gethostname(buf, sizeof(buf)) != 0) {
233 hostname.ptr[0] = '\0';
234 hostname.slen = 0;
235 } else {
236 hostname.slen = strlen(buf);
237 }
238 }
239 return &hostname;
240}
241
242/*
243 * Get first IP address associated with the hostname.
244 */
245PJ_DEF(pj_in_addr) pj_gethostaddr(void)
246{
247 pj_sockaddr_in addr;
248 const pj_str_t *hostname = pj_gethostname();
249
250 pj_sockaddr_in_set_str_addr(&addr, hostname);
251 return addr.sin_addr;
252}
253
254
255#if defined(PJ_WIN32)
256/*
257 * Create new socket/endpoint for communication and returns a descriptor.
258 */
259PJ_DEF(pj_status_t) pj_sock_socket(int af,
260 int type,
261 int proto,
262 pj_sock_t *sock)
263{
264 PJ_CHECK_STACK();
265
266 /* Sanity checks. */
267 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
268 PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET,
269 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
270
271 *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
272
273 if (*sock == PJ_INVALID_SOCKET)
274 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
275 else
276 return PJ_SUCCESS;
277}
278
279#else
280/*
281 * Create new socket/endpoint for communication and returns a descriptor.
282 */
283PJ_DEF(pj_status_t) pj_sock_socket(int af,
284 int type,
285 int proto,
286 pj_sock_t *sock)
287{
288
289 PJ_CHECK_STACK();
290
291 /* Sanity checks. */
292 PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
293 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1,
294 (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
295
296 *sock = socket(af, type, proto);
297 if (*sock == PJ_INVALID_SOCKET)
298 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
299 else
300 return PJ_SUCCESS;
301}
302#endif
303
304
305/*
306 * Bind socket.
307 */
308PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock,
309 const pj_sockaddr_t *addr,
310 int len)
311{
312 PJ_CHECK_STACK();
313
314 PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);
315
316 if (bind(sock, (struct sockaddr*)addr, len) != 0)
317 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
318 else
319 return PJ_SUCCESS;
320}
321
322
323/*
324 * Bind socket.
325 */
326PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock,
327 pj_uint32_t addr32,
328 pj_uint16_t port)
329{
330 pj_sockaddr_in addr;
331
332 PJ_CHECK_STACK();
333
334 addr.sin_family = PJ_AF_INET;
335 addr.sin_addr.s_addr = pj_htonl(addr32);
336 addr.sin_port = pj_htons(port);
337
338 return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
339}
340
341
342/*
343 * Close socket.
344 */
345PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
346{
347 int rc;
348
349 PJ_CHECK_STACK();
350#if defined(PJ_WIN32) && PJ_WIN32==1
351 rc = closesocket(sock);
352#else
353 rc = close(sock);
354#endif
355
356 if (rc != 0)
357 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
358 else
359 return PJ_SUCCESS;
360}
361
362/*
363 * Get remote's name.
364 */
365PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
366 pj_sockaddr_t *addr,
367 int *namelen)
368{
369 PJ_CHECK_STACK();
370 if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
371 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
372 else
373 return PJ_SUCCESS;
374}
375
376/*
377 * Get socket name.
378 */
379PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
380 pj_sockaddr_t *addr,
381 int *namelen)
382{
383 PJ_CHECK_STACK();
384 if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
385 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
386 else
387 return PJ_SUCCESS;
388}
389
390/*
391 * Send data
392 */
393PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
394 const void *buf,
395 pj_ssize_t *len,
396 unsigned flags)
397{
398 PJ_CHECK_STACK();
399 PJ_ASSERT_RETURN(len, PJ_EINVAL);
400
401 *len = send(sock, (const char*)buf, *len, flags);
402
403 if (*len < 0)
404 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
405 else
406 return PJ_SUCCESS;
407}
408
409
410/*
411 * Send data.
412 */
413PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
414 const void *buf,
415 pj_ssize_t *len,
416 unsigned flags,
417 const pj_sockaddr_t *to,
418 int tolen)
419{
420 PJ_CHECK_STACK();
421 PJ_ASSERT_RETURN(len, PJ_EINVAL);
422
423 *len = sendto(sock, (const char*)buf, *len, flags,
424 (const struct sockaddr*)to, tolen);
425
426 if (*len < 0)
427 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
428 else
429 return PJ_SUCCESS;
430}
431
432/*
433 * Receive data.
434 */
435PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
436 void *buf,
437 pj_ssize_t *len,
438 unsigned flags)
439{
440 PJ_CHECK_STACK();
441 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
442
443 *len = recv(sock, (char*)buf, *len, flags);
444
445 if (*len < 0)
446 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
447 else
448 return PJ_SUCCESS;
449}
450
451/*
452 * Receive data.
453 */
454PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
455 void *buf,
456 pj_ssize_t *len,
457 unsigned flags,
458 pj_sockaddr_t *from,
459 int *fromlen)
460{
461 PJ_CHECK_STACK();
462 PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
463 PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
464
465 *len = recvfrom(sock, (char*)buf, *len, flags,
466 (struct sockaddr*)from, (socklen_t*)fromlen);
467
468 if (*len < 0)
469 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
470 else
471 return PJ_SUCCESS;
472}
473
474/*
475 * Get socket option.
476 */
477PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
Benny Prijono4d974f32005-11-06 13:32:11 +0000478 pj_uint16_t level,
479 pj_uint16_t optname,
Benny Prijonodd859a62005-11-01 16:42:51 +0000480 void *optval,
481 int *optlen)
482{
483 PJ_CHECK_STACK();
484 PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
485
486 if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
487 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
488 else
489 return PJ_SUCCESS;
490}
491
492/*
493 * Set socket option.
494 */
495PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
Benny Prijono4d974f32005-11-06 13:32:11 +0000496 pj_uint16_t level,
497 pj_uint16_t optname,
Benny Prijonodd859a62005-11-01 16:42:51 +0000498 const void *optval,
499 int optlen)
500{
501 PJ_CHECK_STACK();
502 if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
503 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
504 else
505 return PJ_SUCCESS;
506}
507
508/*
509 * Shutdown socket.
510 */
511#if PJ_HAS_TCP
512PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
513 int how)
514{
515 PJ_CHECK_STACK();
516 if (shutdown(sock, how) != 0)
517 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
518 else
519 return PJ_SUCCESS;
520}
521
522/*
523 * Start listening to incoming connections.
524 */
525PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
526 int backlog)
527{
528 PJ_CHECK_STACK();
529 if (listen(sock, backlog) != 0)
530 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
531 else
532 return PJ_SUCCESS;
533}
534
535/*
536 * Connect socket.
537 */
538PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
539 const pj_sockaddr_t *addr,
540 int namelen)
541{
542 PJ_CHECK_STACK();
543 if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
544 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
545 else
546 return PJ_SUCCESS;
547}
548
549/*
550 * Accept incoming connections
551 */
552PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
553 pj_sock_t *newsock,
554 pj_sockaddr_t *addr,
555 int *addrlen)
556{
557 PJ_CHECK_STACK();
558 PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
559
560 *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
561 if (*newsock==PJ_INVALID_SOCKET)
562 return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
563 else
564 return PJ_SUCCESS;
565}
566#endif /* PJ_HAS_TCP */
567
568