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