blob: d7924f91842b4f4a037d81772243f089c9d76f6f [file] [log] [blame]
Benny Prijono4766ffe2005-11-01 17:56:59 +00001/* $Id$
2 *
Benny Prijonodd859a62005-11-01 16:42:51 +00003 */
4#include <pj/sock.h>
5#include <pj/assert.h>
6#include <pj/string.h> /* pj_memcpy() */
7#include <pj/os.h> /* PJ_CHECK_STACK() */
8#include <pj/addr_resolv.h> /* pj_gethostbyname() */
9#include <pj/ctype.h>
10#include <pj/compat/sprintf.h>
11#include <pj/log.h>
12#include <pj/errno.h>
13
14/* Linux kernel specific. */
15#include <linux/socket.h>
16#include <linux/net.h>
17//#include <net/sock.h>
18#include <linux/security.h>
19#include <linux/syscalls.h> /* sys_xxx() */
20#include <asm/ioctls.h> /* FIONBIO */
21#include <linux/utsname.h> /* for pj_gethostname() */
22
23/*
24 * Address families conversion.
25 * The values here are indexed based on pj_addr_family-0xFF00.
26 */
27const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
28const pj_uint16_t PJ_AF_INET = AF_INET;
29const pj_uint16_t PJ_AF_INET6 = AF_INET6;
30#ifdef AF_PACKET
31const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
32#else
33# error "AF_PACKET undeclared!"
34#endif
35#ifdef AF_IRDA
36const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
37#else
38# error "AF_IRDA undeclared!"
39#endif
40
41/*
42 * Socket types conversion.
43 * The values here are indexed based on pj_sock_type-0xFF00
44 */
45const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
46const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
47const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
48const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
49
50/*
51 * Socket level values.
52 */
53const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
54#ifdef SOL_IP
55const pj_uint16_t PJ_SOL_IP = SOL_IP;
56#else
57# error "SOL_IP undeclared!"
58#endif /* SOL_IP */
59#if defined(SOL_TCP)
60const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
61#else
62# error "SOL_TCP undeclared!"
63#endif /* SOL_TCP */
64#ifdef SOL_UDP
65const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
66#else
67# error "SOL_UDP undeclared!"
68#endif
69#ifdef SOL_IPV6
70const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
71#else
72# error "SOL_IPV6 undeclared!"
73#endif
Benny Prijono4d974f32005-11-06 13:32:11 +000074
75/* optname values. */
76const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
77const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
78const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
Benny Prijonodd859a62005-11-01 16:42:51 +000079
80/*
81 * Convert 16-bit value from network byte order to host byte order.
82 */
83PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
84{
85 return ntohs(netshort);
86}
87
88/*
89 * Convert 16-bit value from host byte order to network byte order.
90 */
91PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
92{
93 return htons(hostshort);
94}
95
96/*
97 * Convert 32-bit value from network byte order to host byte order.
98 */
99PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
100{
101 return ntohl(netlong);
102}
103
104/*
105 * Convert 32-bit value from host byte order to network byte order.
106 */
107PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
108{
109 return htonl(hostlong);
110}
111
112/*
113 * Convert an Internet host address given in network byte order
114 * to string in standard numbers and dots notation.
115 */
116PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in)
117{
118#define UC(b) (((int)b)&0xff)
119 static char b[18];
120 char *p;
121
122 p = (char *)&in;
123 pj_snprintf(b, sizeof(b), "%d.%d.%d.%d",
124 UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
125
126 return b;
127}
128
129/*
130 * This function converts the Internet host address ccp from the standard
131 * numbers-and-dots notation into binary data and stores it in the structure
132 * that inp points to.
133 */
134PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr)
135{
136 pj_uint32_t val;
137 int base, n;
138 char c;
139 unsigned parts[4];
140 unsigned *pp = parts;
141 char cp_copy[18];
142 char *cp = cp_copy;
143
144 addr->s_addr = PJ_INADDR_NONE;
145
146 if (ccp->slen > 15) return 0;
147
148 pj_memcpy(cp, ccp->ptr, ccp->slen);
149 cp[ccp->slen] = '\0';
150
151 c = *cp;
152 for (;;) {
153 /*
154 * Collect number up to ``.''.
155 * Values are specified as for C:
156 * 0x=hex, 0=octal, isdigit=decimal.
157 */
158 if (!pj_isdigit((int)c))
159 return (0);
160 val = 0; base = 10;
161 if (c == '0') {
162 c = *++cp;
163 if (c == 'x' || c == 'X')
164 base = 16, c = *++cp;
165 else
166 base = 8;
167 }
168
169 for (;;) {
170 if (pj_isascii((int)c) && pj_isdigit((int)c)) {
171 val = (val * base) + (c - '0');
172 c = *++cp;
173 } else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) {
174 val = (val << 4) |
175 (c + 10 - (pj_islower((int)c) ? 'a' : 'A'));
176 c = *++cp;
177 } else
178 break;
179 }
180
181 if (c == '.') {
182 /*
183 * Internet format:
184 * a.b.c.d
185 * a.b.c (with c treated as 16 bits)
186 * a.b (with b treated as 24 bits)
187 */
188 if (pp >= parts + 3)
189 return (0);
190 *pp++ = val;
191 c = *++cp;
192 } else
193 break;
194 }
195
196 /*
197 * Check for trailing characters.
198 */
199 if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c)))
200 return (0);
201 /*
202 * Concoct the address according to
203 * the number of parts specified.
204 */
205 n = pp - parts + 1;
206 switch (n) {
207 case 0:
208 return (0); /* initial nondigit */
209 case 1: /* a -- 32 bits */
210 break;
211 case 2: /* a.b -- 8.24 bits */
212 if (val > 0xffffff)
213 return (0);
214 val |= parts[0] << 24;
215 break;
216 case 3: /* a.b.c -- 8.8.16 bits */
217 if (val > 0xffff)
218 return (0);
219 val |= (parts[0] << 24) | (parts[1] << 16);
220 break;
221 case 4: /* a.b.c.d -- 8.8.8.8 bits */
222 if (val > 0xff)
223 return (0);
224 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
225 break;
226 }
227
228 if (addr)
229 addr->s_addr = pj_htonl(val);
230 return (1);
231}
232
233/*
234 * Convert address string with numbers and dots to binary IP address.
235 */
236PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
237{
238 pj_in_addr addr;
239 pj_inet_aton(cp, &addr);
240 return addr;
241}
242
243/*
244 * Set the IP address of an IP socket address from string address,
245 * with resolving the host if necessary. The string address may be in a
246 * standard numbers and dots notation or may be a hostname. If hostname
247 * is specified, then the function will resolve the host into the IP
248 * address.
249 */
250PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
251 const pj_str_t *str_addr)
252{
253 PJ_CHECK_STACK();
254
255 pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME);
256
257 addr->sin_family = AF_INET;
258
259 if (str_addr && str_addr->slen) {
260 addr->sin_addr = pj_inet_addr(str_addr);
261 if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
262 pj_hostent he;
263 if (pj_gethostbyname(str_addr, &he) == 0) {
264 addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
265 } else {
266 addr->sin_addr.s_addr = PJ_INADDR_NONE;
267 return -1;
268 }
269 }
270
271 } else {
272 addr->sin_addr.s_addr = 0;
273 }
274
275 return PJ_SUCCESS;
276}
277
278/*
279 * Set the IP address and port of an IP socket address.
280 * The string address may be in a standard numbers and dots notation or
281 * may be a hostname. If hostname is specified, then the function will
282 * resolve the host into the IP address.
283 */
284PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
285 const pj_str_t *str_addr,
286 pj_uint16_t port)
287{
288 pj_assert(addr && str_addr);
289
290 addr->sin_family = PJ_AF_INET;
291 pj_sockaddr_in_set_port(addr, port);
292 return pj_sockaddr_in_set_str_addr(addr, str_addr);
293}
294
295
296/*
297 * Get hostname.
298 */
299PJ_DEF(const pj_str_t*) pj_gethostname(void)
300{
301 static char buf[PJ_MAX_HOSTNAME];
302 static pj_str_t hostname;
303
304 PJ_CHECK_STACK();
305
306 if (hostname.ptr == NULL) {
307 hostname.ptr = buf;
308 down_read(&uts_sem);
309 hostname.slen = strlen(system_utsname.nodename);
310 if (hostname.slen > PJ_MAX_HOSTNAME) {
311 hostname.ptr[0] = '\0';
312 hostname.slen = 0;
313 } else {
314 pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen);
315 }
316 up_read(&uts_sem);
317 }
318 return &hostname;
319}
320
321/*
322 * Get first IP address associated with the hostname.
323 */
324PJ_DEF(pj_in_addr) pj_gethostaddr(void)
325{
326 pj_sockaddr_in addr;
327 const pj_str_t *hostname = pj_gethostname();
328
329 pj_sockaddr_in_set_str_addr(&addr, hostname);
330 return addr.sin_addr;
331}
332
333
334/*
335 * Create new socket/endpoint for communication and returns a descriptor.
336 */
337PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto,
338 pj_sock_t *sock_fd)
339{
340 long result;
341
342 PJ_CHECK_STACK();
343
344 /* Sanity checks. */
345 PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL);
346
347 /* Initialize returned socket */
348 *sock_fd = PJ_INVALID_SOCKET;
349
350 /* Create socket. */
351 result = sys_socket(af, type, proto);
352 if (result < 0) {
353 return PJ_RETURN_OS_ERROR((-result));
354 }
355
356 *sock_fd = result;
357
358 return PJ_SUCCESS;
359}
360
361/*
362 * Bind socket.
363 */
364PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd,
365 const pj_sockaddr_t *addr,
366 int len)
367{
368 long err;
369 mm_segment_t oldfs;
370
371 PJ_CHECK_STACK();
372
373 PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr),
374 PJ_EINVAL);
375
376 oldfs = get_fs();
377 set_fs(KERNEL_DS);
378
379 err = sys_bind(sockfd, (struct sockaddr*)addr, len);
380
381 set_fs(oldfs);
382
383 if (err)
384 return PJ_RETURN_OS_ERROR(-err);
385 else
386 return PJ_SUCCESS;
387}
388
389
390/*
391 * Bind socket.
392 */
393PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd,
394 pj_uint32_t addr32,
395 pj_uint16_t port)
396{
397 pj_sockaddr_in addr;
398
399 PJ_CHECK_STACK();
400
401 addr.sin_family = PJ_AF_INET;
402 addr.sin_addr.s_addr = pj_htonl(addr32);
403 addr.sin_port = pj_htons(port);
404
405 return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in));
406}
407
408/*
409 * Close socket.
410 */
411PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd)
412{
413 long err;
414
415 err = sys_close(sockfd);
416
417 if (err != 0)
418 return PJ_RETURN_OS_ERROR(-err);
419 else
420 return PJ_SUCCESS;
421}
422
423/*
424 * Get remote's name.
425 */
426PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd,
427 pj_sockaddr_t *addr,
428 int *namelen)
429{
430 mm_segment_t oldfs;
431 long err;
432
433 PJ_CHECK_STACK();
434
435 oldfs = get_fs();
436 set_fs(KERNEL_DS);
437
438 err = sys_getpeername( sockfd, addr, namelen);
439
440 set_fs(oldfs);
441
442 if (err)
443 return PJ_RETURN_OS_ERROR(-err);
444 else
445 return PJ_SUCCESS;
446}
447
448/*
449 * Get socket name.
450 */
451PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
452 pj_sockaddr_t *addr,
453 int *namelen)
454{
455 mm_segment_t oldfs;
456 int err;
457
458 PJ_CHECK_STACK();
459
460 oldfs = get_fs();
461 set_fs(KERNEL_DS);
462
463 err = sys_getsockname( sockfd, addr, namelen );
464
465 set_fs(oldfs);
466
467 if (err)
468 return PJ_RETURN_OS_ERROR(-err);
469 else
470 return PJ_SUCCESS;
471}
472
473/*
474 * Send data
475 */
476PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd,
477 const void *buf,
478 pj_ssize_t *len,
479 unsigned flags)
480{
481 return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0);
482}
483
484
485/*
486 * Send data.
487 */
488PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd,
489 const void *buff,
490 pj_ssize_t *len,
491 unsigned flags,
492 const pj_sockaddr_t *addr,
493 int addr_len)
494{
495 long err;
496 mm_segment_t oldfs;
497
498 PJ_CHECK_STACK();
499
500 oldfs = get_fs();
501 set_fs(KERNEL_DS);
502
503 err = *len = sys_sendto( sockfd, (void*)buff, *len, flags,
504 (void*)addr, addr_len );
505
506 set_fs(oldfs);
507
508 if (err >= 0) {
509 return PJ_SUCCESS;
510 }
511 else {
512 return PJ_RETURN_OS_ERROR(-err);
513 }
514}
515
516/*
517 * Receive data.
518 */
519PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd,
520 void *buf,
521 pj_ssize_t *len,
522 unsigned flags)
523{
524 return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL);
525}
526
527/*
528 * Receive data.
529 */
530PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
531 void *buff,
532 pj_ssize_t *size,
533 unsigned flags,
534 pj_sockaddr_t *from,
535 int *fromlen)
536{
537 mm_segment_t oldfs;
538 long err;
539
540 PJ_CHECK_STACK();
541
542 oldfs = get_fs();
543 set_fs(KERNEL_DS);
544
545 err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen);
546
547 set_fs(oldfs);
548
549 if (err >= 0) {
550 return PJ_SUCCESS;
551 }
552 else {
553 return PJ_RETURN_OS_ERROR(-err);
554 }
555}
556
557/*
558 * Get socket option.
559 */
560PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
Benny Prijono4d974f32005-11-06 13:32:11 +0000561 pj_uint16_t level,
562 pj_uint16_t optname,
Benny Prijonodd859a62005-11-01 16:42:51 +0000563 void *optval,
564 int *optlen)
565{
566 mm_segment_t oldfs;
567 long err;
568
569 PJ_CHECK_STACK();
570
571 oldfs = get_fs();
572 set_fs(KERNEL_DS);
573
574 err = sys_getsockopt( sockfd, level, optname, optval, optlen);
575
576 set_fs(oldfs);
577
578 if (err)
579 return PJ_RETURN_OS_ERROR(-err);
580 else
581 return PJ_SUCCESS;
582}
583
584/*
585 * Set socket option.
586 */
587PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
Benny Prijono4d974f32005-11-06 13:32:11 +0000588 pj_uint16_t level,
589 pj_uint16_t optname,
Benny Prijonodd859a62005-11-01 16:42:51 +0000590 const void *optval,
591 int optlen)
592{
593 long err;
594 mm_segment_t oldfs;
595
596 PJ_CHECK_STACK();
597
598
599 oldfs = get_fs();
600 set_fs(KERNEL_DS);
601
602 err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen);
603
604 set_fs(oldfs);
605
606 if (err)
607 return PJ_RETURN_OS_ERROR(-err);
608 else
609 return PJ_SUCCESS;
610}
611
612/*
613 * Shutdown socket.
614 */
615#if PJ_HAS_TCP
616PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
617 int how)
618{
619 long err;
620
621 PJ_CHECK_STACK();
622
623 err = sys_shutdown(sockfd, how);
624
625 if (err)
626 return PJ_RETURN_OS_ERROR(-err);
627 else
628 return PJ_SUCCESS;
629}
630
631/*
632 * Start listening to incoming connections.
633 */
634PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd,
635 int backlog)
636{
637 long err;
638
639 PJ_CHECK_STACK();
640
641 err = sys_listen( sockfd, backlog );
642
643 if (err)
644 return PJ_RETURN_OS_ERROR(-err);
645 else
646 return PJ_SUCCESS;
647}
648
649/*
650 * Connect socket.
651 */
652PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
653 const pj_sockaddr_t *addr,
654 int namelen)
655{
656 long err;
657 mm_segment_t oldfs;
658
659 PJ_CHECK_STACK();
660
661 oldfs = get_fs();
662 set_fs(KERNEL_DS);
663
664 err = sys_connect( sockfd, (void*)addr, namelen );
665
666 set_fs(oldfs);
667
668 if (err)
669 return PJ_RETURN_OS_ERROR(-err);
670 else
671 return PJ_SUCCESS;
672}
673
674/*
675 * Accept incoming connections
676 */
677PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd,
678 pj_sock_t *newsockfd,
679 pj_sockaddr_t *addr,
680 int *addrlen)
681{
682 long err;
683
684 PJ_CHECK_STACK();
685
686 PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL);
687
688 err = sys_accept( sockfd, addr, addrlen);
689
690 if (err < 0) {
691 *newsockfd = PJ_INVALID_SOCKET;
692 return PJ_RETURN_OS_ERROR(-err);
693 }
694 else {
695 *newsockfd = err;
696 return PJ_SUCCESS;
697 }
698}
699#endif /* PJ_HAS_TCP */
700
701
702
703/*
704 * Permission to steal inet_ntoa() and inet_aton() as long as this notice below
705 * is included:
706 */
707/*
708 * Copyright (c) 1983, 1993
709 * The Regents of the University of California. All rights reserved.
710 *
711 * Redistribution and use in source and binary forms, with or without
712 * modification, are permitted provided that the following conditions
713 * are met:
714 * 1. Redistributions of source code must retain the above copyright
715 * notice, this list of conditions and the following disclaimer.
716 * 2. Redistributions in binary form must reproduce the above copyright
717 * notice, this list of conditions and the following disclaimer in the
718 * documentation and/or other materials provided with the distribution.
719 * 3. All advertising materials mentioning features or use of this software
720 * must display the following acknowledgement:
721 * This product includes software developed by the University of
722 * California, Berkeley and its contributors.
723 * 4. Neither the name of the University nor the names of its contributors
724 * may be used to endorse or promote products derived from this software
725 * without specific prior written permission.
726 *
727 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
728 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
729 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
730 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
731 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
732 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
733 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
734 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
735 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
736 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
737 * SUCH DAMAGE.
738 */
739