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