Re #2062: Remove deprecated Linux kernel implementation

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@5692 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Sauw Ming 2017-11-13 06:06:25 +00:00
parent 945170f7b2
commit 5b52b9b2e8
21 changed files with 16 additions and 2470 deletions

View File

@ -1,43 +0,0 @@
include $(KERNEL_DIR)/.config
#
# Basic kernel compilation flags.
#
export OS_CFLAGS := $(CC_DEF)PJ_LINUX_KERNEL=1 -D__KERNEL__ \
-I$(KERNEL_DIR)/include -iwithprefix include \
-nostdinc -msoft-float
#
# Additional kernel compilation flags are taken from the kernel Makefile
# itself.
#
KERNEL_CFLAGS := \
$(shell cd $(KERNEL_DIR) ; \
make script SCRIPT='@echo $$(CFLAGS) $$(CFLAGS_MODULE)' $(KERNEL_ARCH))
export OS_CFLAGS += $(KERNEL_CFLAGS)
# -DMODULE -I$(KERNEL_DIR)/include -nostdinc \
# -Wstrict-prototypes \
# -Wno-trigraphs -fno-strict-aliasing -fno-common \
# -msoft-float -m32 -fno-builtin-sprintf -fno-builtin-log2\
# -fno-builtin-puts -mpreferred-stack-boundary=2 \
# -fno-unit-at-a-time -march=i686 -mregparm=3 \
# -iwithprefix include
#export OS_CFLAGS += -U__i386__ -Ui386 -D__arch_um__ -DSUBARCH=\"i386\" \
# -D_LARGEFILE64_SOURCE -I$(KERNEL_DIR)/arch/um/include \
# -Derrno=kernel_errno \
# -I$(KERNEL_DIR)/arch/um/kernel/tt/include \
# -I$(KERNEL_DIR)/arch/um/kernel/skas/include \
export OS_CXXFLAGS :=
export OS_LDFLAGS :=
export OS_SOURCES :=

View File

@ -1,49 +0,0 @@
#
# OS specific configuration for Linux Kernel module target.
#
#
# PJLIB_OBJS specified here are object files to be included in PJLIB
# (the library) for this specific operating system. Object files common
# to all operating systems should go in Makefile instead.
#
export PJLIB_OBJS += compat/sigjmp.o compat/setjmp_i386.o \
compat/longjmp_i386.o compat/string.o \
addr_resolv_linux_kernel.o \
guid_simple.o \
log_writer_printk.o pool_policy_kmalloc.o \
os_error_linux_kernel.o os_core_linux_kernel.o \
os_time_linux_kernel.o os_timestamp_common.o \
os_timestamp_linux_kernel.o \
sock_linux_kernel.o sock_select.o
# For IOQueue, we can use either epoll or select
export PJLIB_OBJS += ioqueue_epoll.o
#export PJLIB_OBJS += ioqueue_select.o
export PJLIB_OBJS += sock_qos_bsd.o
#
# TEST_OBJS are operating system specific object files to be included in
# the test application.
#
export TEST_OBJS += main_mod.o
#
# Additional CFLAGS
#
export TEST_CFLAGS += -msoft-float
#
# Additional LD_FLAGS for this target.
#
export TEST_LDFLAGS += -lgcc
#
# TARGETS are make targets in the Makefile, to be executed for this given
# operating system.
#
export TARGETS := pjlib.ko pjlib-test.ko

View File

@ -28,13 +28,6 @@
#if defined(PJ_HAS_ASSERT_H) && PJ_HAS_ASSERT_H != 0
# include <assert.h>
#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
# define assert(expr) do { \
if (!(expr)) \
printk("!!ASSERTION FAILED: [%s:%d] \"" #expr "\"\n",\
__FILE__, __LINE__); \
} while (0)
#else
# warning "assert() is not implemented"
# define assert(expr)

View File

@ -31,21 +31,6 @@
# define PJ_HIGHPREC_VALUE_IS_ZERO(a) (a==0)
# define pj_highprec_mod(a,b) (a=fmod(a,b))
#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
# include <asm/div64.h>
typedef pj_int64_t pj_highprec_t;
# define pj_highprec_div(a1,a2) do_div(a1,a2)
# define pj_highprec_mod(a1,a2) (a1=do_mod(a1, a2))
PJ_INLINE(pj_int64_t) do_mod( pj_int64_t a1, pj_int64_t a2)
{
return do_div(a1,a2);
}
#elif defined(PJ_HAS_INT64) && PJ_HAS_INT64 != 0
/*
* Next choice is to use 64-bit arithmatics.

View File

@ -1,149 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PJ_COMPAT_OS_LINUX_KERNEL_H__
#define __PJ_COMPAT_OS_LINUX_KERNEL_H__
/**
* @file os_linux.h
* @brief Describes Linux operating system specifics.
*/
#define PJ_OS_NAME "linux-module"
#define PJ_HAS_ARPA_INET_H 0
#define PJ_HAS_ASSERT_H 0
#define PJ_HAS_CTYPE_H 0
#define PJ_HAS_ERRNO_H 0
#define PJ_HAS_LINUX_SOCKET_H 1
#define PJ_HAS_MALLOC_H 0
#define PJ_HAS_NETDB_H 0
#define PJ_HAS_NETINET_IN_H 0
#define PJ_HAS_SETJMP_H 0
#define PJ_HAS_STDARG_H 1
#define PJ_HAS_STDDEF_H 0
#define PJ_HAS_STDIO_H 0
#define PJ_HAS_STDLIB_H 0
#define PJ_HAS_STRING_H 0
#define PJ_HAS_SYS_IOCTL_H 0
#define PJ_HAS_SYS_SELECT_H 0
#define PJ_HAS_SYS_SOCKET_H 0
#define PJ_HAS_SYS_TIME_H 0
#define PJ_HAS_SYS_TIMEB_H 0
#define PJ_HAS_SYS_TYPES_H 0
#define PJ_HAS_TIME_H 0
#define PJ_HAS_UNISTD_H 0
#define PJ_HAS_MSWSOCK_H 0
#define PJ_HAS_WINSOCK_H 0
#define PJ_HAS_WINSOCK2_H 0
#define PJ_SOCK_HAS_INET_ATON 0
/* Set 1 if native sockaddr_in has sin_len member.
* Default: 0
*/
#define PJ_SOCKADDR_HAS_LEN 0
/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
* the status of non-blocking connect() operation.
*/
#define PJ_HAS_SO_ERROR 1
/**
* If this macro is set, it tells select I/O Queue that select() needs to
* be given correct value of nfds (i.e. largest fd + 1). This requires
* select ioqueue to re-scan the descriptors on each registration and
* unregistration.
* If this macro is not set, then ioqueue will always give FD_SETSIZE for
* nfds argument when calling select().
*
* Default: 0
*/
#define PJ_SELECT_NEEDS_NFDS 0
/* Is errno a good way to retrieve OS errors?
* (probably no for linux kernel)
* If you answer no here, you'll need to tell pjlib how to get OS
* error (a compile error will tell you exactly where)
*/
#define PJ_HAS_ERRNO_VAR 0
/* This value specifies the value set in errno by the OS when a non-blocking
* socket recv() can not return immediate daata.
*/
#define PJ_BLOCKING_ERROR_VAL EAGAIN
/* This value specifies the value set in errno by the OS when a non-blocking
* socket connect() can not get connected immediately.
*/
#define PJ_BLOCKING_CONNECT_ERROR_VAL EINPROGRESS
#ifndef PJ_HAS_THREADS
# define PJ_HAS_THREADS (1)
#endif
/*
* Declare __FD_SETSIZE now before including <linux*>.
*/
#define __FD_SETSIZE PJ_IOQUEUE_MAX_HANDLES
#define NULL ((void*)0)
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#define __PJ_EXPORT_SYMBOL(a) EXPORT_SYMBOL(a);
/*
* Override features.
*/
#define PJ_HAS_FLOATING_POINT 0
#define PJ_HAS_MALLOC 0
#define PJ_HAS_SEMAPHORE 0
#define PJ_HAS_EVENT_OBJ 0
#define PJ_HAS_HIGH_RES_TIMER 1
#ifndef PJ_OS_HAS_CHECK_STACK
# define PJ_OS_HAS_CHECK_STACK 0
#endif
#define PJ_TERM_HAS_COLOR 0
#define PJ_NATIVE_STRING_IS_UNICODE 0
#define PJ_ATOMIC_VALUE_TYPE int
#define PJ_THREAD_DESC_SIZE 128
/* If 1, use Read/Write mutex emulation for platforms that don't support it */
#define PJ_EMULATE_RWMUTEX 0
/* If 1, pj_thread_create() should enforce the stack size when creating
* threads.
* Default: 0 (let OS decide the thread's stack size).
*/
#define PJ_THREAD_SET_STACK_SIZE 0
/* If 1, pj_thread_create() should allocate stack from the pool supplied.
* Default: 0 (let OS allocate memory for thread's stack).
*/
#define PJ_THREAD_ALLOCATE_STACK 0
#endif /* __PJ_COMPAT_OS_LINUX_KERNEL_H__ */

View File

@ -44,20 +44,6 @@
# define platform_rand rand
# endif
#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
/*
* Linux kernel mode random number generator.
*/
# include <linux/random.h>
# define platform_srand(seed)
PJ_INLINE(int) platform_rand(void)
{
int value;
get_random_bytes((void*)&value, sizeof(value));
return value;
}
#else
# warning "platform_rand() is not implemented"
# define platform_rand() 1

View File

@ -35,54 +35,6 @@
# define pj_longjmp(buf,d) longjmp(buf,d)
# endif
#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 && \
defined(PJ_M_I386) && PJ_M_I386 != 0
/*
* These are taken from uClibc.
* Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org>
*/
# if defined __USE_MISC || defined _ASM
# define JB_BX 0
# define JB_SI 1
# define JB_DI 2
# define JB_BP 3
# define JB_SP 4
# define JB_PC 5
# define JB_SIZE 24
# endif
# ifndef _ASM
typedef int __jmp_buf[6];
/* A `sigset_t' has a bit for each signal. */
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct __sigset_t_tag
{
unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;
/* Calling environment, plus possibly a saved signal mask. */
typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */
{
/* NOTE: The machine-dependent definitions of `__sigsetjmp'
assume that a `jmp_buf' begins with a `__jmp_buf' and that
`__mask_was_saved' follows it. Do not move these members
or add others before it. */
__jmp_buf __jmpbuf; /* Calling environment. */
int __mask_was_saved; /* Saved the signal mask? */
// we never saved the mask.
__sigset_t __saved_mask; /* Saved signal mask. */
} jmp_buf[1];
typedef jmp_buf sigjmp_buf;
typedef jmp_buf pj_jmp_buf;
PJ_DECL(int) pj_setjmp(pj_jmp_buf env);
PJ_DECL(void) pj_longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));
# endif /* _ASM */
#elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
/* Symbian framework don't use setjmp/longjmp */

View File

@ -184,34 +184,6 @@
#undef s6_addr
#undef sin_zero
/*
* Linux kernel specifics
*/
#if defined(PJ_LINUX_KERNEL)
# include <linux/net.h>
# include <asm/ioctls.h> /* FIONBIO */
# include <linux/syscalls.h> /* sys_select() */
# include <asm/uaccess.h> /* set/get_fs() */
typedef int socklen_t;
# define getsockopt sys_getsockopt
/*
* Wrapper for select() in Linux kernel.
*/
PJ_INLINE(int) select(int n, fd_set *inp, fd_set *outp, fd_set *exp,
struct timeval *tvp)
{
int count;
mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS);
count = sys_select(n, inp, outp, exp, tvp);
set_fs(oldfs);
return count;
}
#endif /* PJ_LINUX_KERNEL */
/*
* This will finally be obsoleted, since it should be declared in
* os_auto.h

View File

@ -115,12 +115,6 @@
# define PJ_WIN32 1
# include <pj/compat/os_win32.h>
#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
/*
* Linux kernel
*/
# include <pj/compat/os_linux_kernel.h>
#elif defined(PJ_LINUX) || defined(linux) || defined(__linux)
/*
* Linux

View File

@ -1,26 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/addr_resolv.h>
PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
{
return -1;
}

View File

@ -1,42 +0,0 @@
/* longjmp for i386.
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#define _ASM
#define _SETJMP_H
#define PJ_LINUX_KERNEL 1
#include <pj/compat/setjmp.h>
.global __longjmp
.type __longjmp,%function
.align 4
__longjmp:
movl 4(%esp), %ecx /* User's jmp_buf in %ecx. */
movl 8(%esp), %eax /* Second argument is return value. */
/* Save the return address now. */
movl (JB_PC*4)(%ecx), %edx
/* Restore registers. */
movl (JB_BX*4)(%ecx), %ebx
movl (JB_SI*4)(%ecx), %esi
movl (JB_DI*4)(%ecx), %edi
movl (JB_BP*4)(%ecx), %ebp
movl (JB_SP*4)(%ecx), %esp
/* Jump to saved PC. */
jmp *%edx
.size __longjmp,.-__longjmp

View File

@ -1,61 +0,0 @@
/* setjmp for i386, ELF version.
Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#define _ASM
#define _SETJMP_H
#define PJ_LINUX_KERNEL 1
#include <pj/compat/setjmp.h>
.global __sigsetjmp
.type __sigsetjmp,%function
.align 4
__sigsetjmp:
movl 4 (%esp), %eax
/* Save registers. */
movl %ebx, (0 *4)(%eax)
movl %esi, (1 *4)(%eax)
movl %edi, (2 *4)(%eax)
/* Save SP as it will be after we return. */
leal 4(%esp), %ecx
movl %ecx, (4 *4)(%eax)
/* Save PC we are returning to now. */
movl 0(%esp), %ecx
movl %ecx, (5 *4)(%eax)
/* Save caller's frame pointer. */
movl %ebp, (3 *4)(%eax)
/* Make a tail call to __sigjmp_save; it takes the same args. */
#ifdef __PIC__
/* We cannot use the PLT, because it requires that %ebx be set, but
we can't save and restore our caller's value. Instead, we do an
indirect jump through the GOT, using for the temporary register
%ecx, which is call-clobbered. */
call .Lhere
.Lhere:
popl %ecx
addl $_GLOBAL_OFFSET_TABLE_+[.- .Lhere ], %ecx
movl __sigjmp_save @GOT (%ecx), %ecx
jmp *%ecx
#else
jmp __sigjmp_save
#endif
.size __sigsetjmp,.-__sigsetjmp

View File

@ -546,9 +546,6 @@ pj_bool_t ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue,
# elif (defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0)
bytes_read = read(h->fd, read_op->buf, bytes_read);
rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error();
# elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
bytes_read = sys_read(h->fd, read_op->buf, bytes_read);
rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read;
# else
# error "Implement read() for this platform!"
# endif

View File

@ -37,109 +37,21 @@
#include <pj/compat/socket.h>
#include <pj/rand.h>
#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0
/*
* Linux user mode
*/
# include <sys/epoll.h>
# include <errno.h>
# include <unistd.h>
#include <sys/epoll.h>
#include <errno.h>
#include <unistd.h>
# define epoll_data data.ptr
# define epoll_data_type void*
# define ioctl_val_type unsigned long
# define getsockopt_val_ptr int*
# define os_getsockopt getsockopt
# define os_ioctl ioctl
# define os_read read
# define os_close close
# define os_epoll_create epoll_create
# define os_epoll_ctl epoll_ctl
# define os_epoll_wait epoll_wait
#else
/*
* Linux kernel mode.
*/
# include <linux/config.h>
# include <linux/version.h>
# if defined(MODVERSIONS)
# include <linux/modversions.h>
# endif
# include <linux/kernel.h>
# include <linux/poll.h>
# include <linux/eventpoll.h>
# include <linux/syscalls.h>
# include <linux/errno.h>
# include <linux/unistd.h>
# include <asm/ioctls.h>
enum EPOLL_EVENTS
{
EPOLLIN = 0x001,
EPOLLOUT = 0x004,
EPOLLERR = 0x008,
};
# define os_epoll_create sys_epoll_create
static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
long rc;
mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS);
rc = sys_epoll_ctl(epfd, op, fd, event);
set_fs(oldfs);
if (rc) {
errno = -rc;
return -1;
} else {
return 0;
}
}
static int os_epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout)
{
int count;
mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS);
count = sys_epoll_wait(epfd, events, maxevents, timeout);
set_fs(oldfs);
return count;
}
# define os_close sys_close
# define os_getsockopt pj_sock_getsockopt
static int os_read(int fd, void *buf, size_t len)
{
long rc;
mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS);
rc = sys_read(fd, buf, len);
set_fs(oldfs);
if (rc) {
errno = -rc;
return -1;
} else {
return 0;
}
}
# define socklen_t unsigned
# define ioctl_val_type unsigned long
int ioctl(int fd, int opt, ioctl_val_type value);
static int os_ioctl(int fd, int opt, ioctl_val_type value)
{
int rc;
mm_segment_t oldfs = get_fs();
set_fs(KERNEL_DS);
rc = ioctl(fd, opt, value);
set_fs(oldfs);
if (rc < 0) {
errno = -rc;
return rc;
} else
return rc;
}
# define getsockopt_val_ptr char*
# define epoll_data data
# define epoll_data_type __u32
#endif
#define epoll_data data.ptr
#define epoll_data_type void*
#define ioctl_val_type unsigned long
#define getsockopt_val_ptr int*
#define os_getsockopt getsockopt
#define os_ioctl ioctl
#define os_read read
#define os_close close
#define os_epoll_create epoll_create
#define os_epoll_ctl epoll_ctl
#define os_epoll_wait epoll_wait
#define THIS_FILE "ioq_epoll"
@ -201,11 +113,7 @@ static void scan_closing_keys(pj_ioqueue_t *ioqueue);
*/
PJ_DEF(const char*) pj_ioqueue_name(void)
{
#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
return "epoll-kernel";
#else
return "epoll";
#endif
return "epoll";
}
/*

View File

@ -1,162 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/ioqueue.h>
#include <pj/os.h>
#include <pj/log.h>
#include <pj/list.h>
#include <pj/pool.h>
#include <pj/string.h>
#include <pj/assert.h>
#include <pj/sock.h>
#define THIS_FILE "ioqueue"
#define PJ_IOQUEUE_IS_READ_OP(op) \
((op & PJ_IOQUEUE_OP_READ) || (op & PJ_IOQUEUE_OP_RECV_FROM))
#define PJ_IOQUEUE_IS_WRITE_OP(op) \
((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
#if PJ_HAS_TCP
# define PJ_IOQUEUE_IS_ACCEPT_OP(op) (op & PJ_IOQUEUE_OP_ACCEPT)
# define PJ_IOQUEUE_IS_CONNECT_OP(op) (op & PJ_IOQUEUE_OP_CONNECT)
#else
# define PJ_IOQUEUE_IS_ACCEPT_OP(op) 0
# define PJ_IOQUEUE_IS_CONNECT_OP(op) 0
#endif
#if defined(PJ_DEBUG) && PJ_DEBUG != 0
# define VALIDATE_FD_SET 1
#else
# define VALIDATE_FD_SET 0
#endif
struct pj_ioqueue_key_t
{
PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
pj_sock_t fd;
pj_ioqueue_operation_e op;
void *user_data;
pj_ioqueue_callback cb;
};
struct pj_ioqueue_t
{
};
PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd)
{
return NULL;
}
PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
{
return 0;
}
PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool,
pj_ioqueue_t *ioque,
pj_oshandle_t sock,
void *user_data,
const pj_ioqueue_callback *cb)
{
return NULL;
}
PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
pj_ioqueue_key_t *key)
{
return -1;
}
PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
{
return NULL;
}
PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
{
return -1;
}
PJ_DEF(int) pj_ioqueue_read( pj_ioqueue_t *ioque,
pj_ioqueue_key_t *key,
void *buffer,
pj_size_t buflen)
{
return -1;
}
PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
pj_ioqueue_key_t *key,
void *buffer,
pj_size_t buflen,
pj_sockaddr_t *addr,
int *addrlen)
{
return -1;
}
PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque,
pj_ioqueue_key_t *key,
const void *data,
pj_size_t datalen)
{
return -1;
}
PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
pj_ioqueue_key_t *key,
const void *data,
pj_size_t datalen,
const pj_sockaddr_t *addr,
int addrlen)
{
return -1;
}
#if PJ_HAS_TCP
/*
* Initiate overlapped accept() operation.
*/
PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
pj_ioqueue_key_t *key,
pj_sock_t *new_sock,
pj_sockaddr_t *local,
pj_sockaddr_t *remote,
int *addrlen)
{
return -1;
}
/*
* Initiate overlapped connect() operation (well, it's non-blocking actually,
* since there's no overlapped version of connect()).
*/
PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
pj_ioqueue_key_t *key,
const pj_sockaddr_t *addr,
int addrlen )
{
return -1;
}
#endif /* PJ_HAS_TCP */

View File

@ -1,698 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/os.h>
#include <pj/assert.h>
#include <pj/pool.h>
#include <pj/log.h>
#include <pj/except.h>
#include <pj/errno.h>
#include <pj/string.h>
#include <pj/compat/high_precision.h>
#include <pj/compat/sprintf.h>
#include <linux/config.h>
#include <linux/version.h>
#if defined(MODVERSIONS)
#include <linux/modversions.h>
#endif
#include <linux/kernel.h>
#include <linux/sched.h>
//#include <linux/tqueue.h>
#include <linux/wait.h>
#include <linux/signal.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <asm/semaphore.h>
#define THIS_FILE "oslinuxkern"
struct pj_thread_t
{
/** Thread's name. */
char obj_name[PJ_MAX_OBJ_NAME];
/** Linux task structure for thread. */
struct task_struct *thread;
/** Flags (specified in pj_thread_create) */
unsigned flags;
/** Task queue needed to launch thread. */
//struct tq_struct tq;
/** Semaphore needed to control thread startup. */
struct semaphore startstop_sem;
/** Semaphore to suspend thread during startup. */
struct semaphore suspend_sem;
/** Queue thread is waiting on. Gets initialized by
thread_initialize, can be used by thread itself.
*/
wait_queue_head_t queue;
/** Flag to tell thread whether to die or not.
When the thread receives a signal, it must check
the value of terminate and call thread_deinitialize and terminate
if set.
*/
int terminate;
/** Thread's entry. */
pj_thread_proc *func;
/** Argument. */
void *arg;
};
struct pj_atomic_t
{
atomic_t atom;
};
struct pj_mutex_t
{
struct semaphore sem;
pj_bool_t recursive;
pj_thread_t *owner;
int own_count;
};
struct pj_sem_t
{
struct semaphore sem;
};
/*
* Static global variables.
*/
#define MAX_TLS_ID 32
static void *tls_values[MAX_TLS_ID];
static int tls_id;
static long thread_tls_id;
static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
static unsigned long spinlock_flags;
static pj_thread_t main_thread;
/* private functions */
//#define TRACE_(expr) PJ_LOG(3,expr)
#define TRACE_(x)
/* This must be called in the context of the new thread. */
static void thread_initialize( pj_thread_t *thread )
{
TRACE_((THIS_FILE, "---new thread initializing..."));
/* Set TLS */
pj_thread_local_set(thread_tls_id, thread);
/* fill in thread structure */
thread->thread = current;
pj_assert(thread->thread != NULL);
/* set signal mask to what we want to respond */
siginitsetinv(&current->blocked,
sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
/* initialise wait queue */
init_waitqueue_head(&thread->queue);
/* initialise termination flag */
thread->terminate = 0;
/* set name of this process (making sure obj_name is null
* terminated first)
*/
thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
sprintf(current->comm, thread->obj_name);
/* tell the creator that we are ready and let him continue */
up(&thread->startstop_sem);
}
/* cleanup of thread. Called by the exiting thread. */
static void thread_deinitialize(pj_thread_t *thread)
{
/* we are terminating */
/* lock the kernel, the exit will unlock it */
thread->thread = NULL;
mb();
/* notify the stop_kthread() routine that we are terminating. */
up(&thread->startstop_sem);
/* the kernel_thread that called clone() does a do_exit here. */
/* there is no race here between execution of the "killer" and
real termination of the thread (race window between up and do_exit),
since both the thread and the "killer" function are running with
the kernel lock held.
The kernel lock will be freed after the thread exited, so the code
is really not executed anymore as soon as the unload functions gets
the kernel lock back.
The init process may not have made the cleanup of the process here,
but the cleanup can be done safely with the module unloaded.
*/
}
static int thread_proc(void *arg)
{
pj_thread_t *thread = arg;
TRACE_((THIS_FILE, "---new thread starting!"));
/* Initialize thread. */
thread_initialize( thread );
/* Wait if created suspended. */
if (thread->flags & PJ_THREAD_SUSPENDED) {
TRACE_((THIS_FILE, "---new thread suspended..."));
down(&thread->suspend_sem);
}
TRACE_((THIS_FILE, "---new thread running..."));
pj_assert(thread->func != NULL);
/* Call thread's entry. */
(*thread->func)(thread->arg);
TRACE_((THIS_FILE, "---thread exiting..."));
/* Cleanup thread. */
thread_deinitialize(thread);
return 0;
}
/* The very task entry. */
static void kthread_launcher(void *arg)
{
TRACE_((THIS_FILE, "...launching thread!..."));
kernel_thread(&thread_proc, arg, 0);
}
PJ_DEF(pj_status_t) pj_init(void)
{
pj_status_t rc;
PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
rc = pj_thread_init();
if (rc != PJ_SUCCESS)
return rc;
/* Initialize exception ID for the pool.
* Must do so after critical section is configured.
*/
rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
if (rc != PJ_SUCCESS)
return rc;
return PJ_SUCCESS;
}
PJ_DEF(pj_uint32_t) pj_getpid(void)
{
return 1;
}
PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
pj_thread_desc desc,
pj_thread_t **ptr_thread)
{
char stack_ptr;
pj_thread_t *thread = (pj_thread_t *)desc;
pj_str_t thread_name = pj_str((char*)cstr_thread_name);
/* Size sanity check. */
if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
pj_assert(!"Not enough pj_thread_desc size!");
return PJ_EBUG;
}
/* If a thread descriptor has been registered before, just return it. */
if (pj_thread_local_get (thread_tls_id) != 0) {
// 2006-02-26 bennylp:
// This wouldn't work in all cases!.
// If thread is created by external module (e.g. sound thread),
// thread may be reused while the pool used for the thread descriptor
// has been deleted by application.
//*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
//return PJ_SUCCESS;
}
/* Initialize and set the thread entry. */
pj_bzero(desc, sizeof(struct pj_thread_t));
if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
else
pj_snprintf(thread->obj_name, sizeof(thread->obj_name),
"thr%p", (void*)thread->thread);
/* Initialize. */
thread_initialize(thread);
/* Eat semaphore. */
down(&thread->startstop_sem);
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
thread->stk_start = &stack_ptr;
thread->stk_size = 0xFFFFFFFFUL;
thread->stk_max_usage = 0;
#else
stack_ptr = '\0';
#endif
*ptr_thread = thread;
return PJ_SUCCESS;
}
pj_status_t pj_thread_init(void)
{
pj_status_t rc;
pj_thread_t *dummy;
rc = pj_thread_local_alloc(&thread_tls_id);
if (rc != PJ_SUCCESS)
return rc;
return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
}
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
pj_thread_proc *proc, void *arg,
pj_size_t stack_size, unsigned flags,
pj_thread_t **ptr_thread)
{
pj_thread_t *thread;
TRACE_((THIS_FILE, "pj_thread_create()"));
PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
if (!thread)
return PJ_ENOMEM;
PJ_UNUSED_ARG(stack_size);
/* Thread name. */
if (!thread_name)
thread_name = "thr%p";
if (strchr(thread_name, '%')) {
pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
} else {
strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
}
/* Init thread's semaphore. */
TRACE_((THIS_FILE, "...init semaphores..."));
init_MUTEX_LOCKED(&thread->startstop_sem);
init_MUTEX_LOCKED(&thread->suspend_sem);
thread->flags = flags;
if ((flags & PJ_THREAD_SUSPENDED) == 0) {
up(&thread->suspend_sem);
}
/* Store the functions and argument. */
thread->func = proc;
thread->arg = arg;
/* Save return value. */
*ptr_thread = thread;
/* Create the new thread by running a task through keventd. */
#if 0
/* Initialize the task queue struct. */
thread->tq.sync = 0;
INIT_LIST_HEAD(&thread->tq.list);
thread->tq.routine = kthread_launcher;
thread->tq.data = thread;
/* and schedule it for execution. */
schedule_task(&thread->tq);
#endif
kthread_launcher(thread);
/* Wait until thread has reached the setup_thread routine. */
TRACE_((THIS_FILE, "...wait for the new thread..."));
down(&thread->startstop_sem);
TRACE_((THIS_FILE, "...main thread resumed..."));
return PJ_SUCCESS;
}
PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
{
return thread->obj_name;
}
PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
{
up(&thread->suspend_sem);
return PJ_SUCCESS;
}
PJ_DEF(pj_thread_t*) pj_thread_this(void)
{
return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
}
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
{
TRACE_((THIS_FILE, "pj_thread_join()"));
down(&p->startstop_sem);
TRACE_((THIS_FILE, " joined!"));
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
{
PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
{
pj_highprec_t ticks;
pj_thread_t *thread = pj_thread_this();
PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
/* Use high precision calculation to make sure we don't
* crop values:
*
* ticks = HZ * msec / 1000
*/
ticks = HZ;
pj_highprec_mul(ticks, msec);
pj_highprec_div(ticks, 1000);
TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
interruptible_sleep_on_timeout( &thread->queue, ticks);
return PJ_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
pj_atomic_value_t value,
pj_atomic_t **ptr_var)
{
pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
if (!t) return PJ_ENOMEM;
atomic_set(&t->atom, value);
*ptr_var = t;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
{
return PJ_SUCCESS;
}
PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
{
atomic_set(&var->atom, value);
}
PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
{
return atomic_read(&var->atom);
}
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
{
atomic_inc(&var->atom);
}
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
{
atomic_dec(&var->atom);
}
PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
{
atomic_add(value, &var->atom);
}
///////////////////////////////////////////////////////////////////////////////
PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
{
if (tls_id >= MAX_TLS_ID)
return PJ_ETOOMANY;
*index = tls_id++;
return PJ_SUCCESS;
}
PJ_DEF(void) pj_thread_local_free(long index)
{
pj_assert(index >= 0 && index < MAX_TLS_ID);
}
PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
{
pj_assert(index >= 0 && index < MAX_TLS_ID);
tls_values[index] = value;
return PJ_SUCCESS;
}
PJ_DEF(void*) pj_thread_local_get(long index)
{
pj_assert(index >= 0 && index < MAX_TLS_ID);
return tls_values[index];
}
///////////////////////////////////////////////////////////////////////////////
PJ_DEF(void) pj_enter_critical_section(void)
{
spin_lock_irqsave(&critical_section, spinlock_flags);
}
PJ_DEF(void) pj_leave_critical_section(void)
{
spin_unlock_irqrestore(&critical_section, spinlock_flags);
}
///////////////////////////////////////////////////////////////////////////////
PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
const char *name,
int type,
pj_mutex_t **ptr_mutex)
{
pj_mutex_t *mutex;
PJ_UNUSED_ARG(name);
mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
if (!mutex)
return PJ_ENOMEM;
init_MUTEX(&mutex->sem);
mutex->recursive = (type == PJ_MUTEX_RECURSE);
mutex->owner = NULL;
mutex->own_count = 0;
/* Done. */
*ptr_mutex = mutex;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
pj_mutex_t **mutex )
{
return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
}
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
const char *name,
pj_mutex_t **mutex )
{
return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
}
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
{
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
if (mutex->recursive) {
pj_thread_t *this_thread = pj_thread_this();
if (mutex->owner == this_thread) {
++mutex->own_count;
} else {
down(&mutex->sem);
pj_assert(mutex->own_count == 0);
mutex->owner = this_thread;
mutex->own_count = 1;
}
} else {
down(&mutex->sem);
}
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
{
long rc;
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
if (mutex->recursive) {
pj_thread_t *this_thread = pj_thread_this();
if (mutex->owner == this_thread) {
++mutex->own_count;
} else {
rc = down_interruptible(&mutex->sem);
if (rc != 0)
return PJ_RETURN_OS_ERROR(-rc);
pj_assert(mutex->own_count == 0);
mutex->owner = this_thread;
mutex->own_count = 1;
}
} else {
int rc = down_trylock(&mutex->sem);
if (rc != 0)
return PJ_RETURN_OS_ERROR(-rc);
}
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
{
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
if (mutex->recursive) {
pj_thread_t *this_thread = pj_thread_this();
if (mutex->owner == this_thread) {
pj_assert(mutex->own_count > 0);
--mutex->own_count;
if (mutex->own_count == 0) {
mutex->owner = NULL;
up(&mutex->sem);
}
} else {
pj_assert(!"Not owner!");
return PJ_EINVALIDOP;
}
} else {
up(&mutex->sem);
}
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
{
PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
return PJ_SUCCESS;
}
#if defined(PJ_DEBUG) && PJ_DEBUG != 0
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
{
if (mutex->recursive)
return mutex->owner == pj_thread_this();
else
return 1;
}
#endif /* PJ_DEBUG */
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
const char *name,
unsigned initial,
unsigned max,
pj_sem_t **sem)
{
pj_sem_t *sem;
PJ_UNUSED_ARG(max);
PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
sema_init(&sem->sem, initial);
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
{
PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
down(&sem->sem);
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
{
int rc;
PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
rc = down_trylock(&sem->sem);
if (rc != 0) {
return PJ_RETURN_OS_ERROR(-rc);
} else {
return PJ_SUCCESS;
}
}
PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
{
PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
up(&sem->sem);
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
{
PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
return PJ_SUCCESS;
}
#endif /* PJ_HAS_SEMAPHORE */

View File

@ -1,81 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/string.h>
#include <pj/compat/errno.h>
#include <linux/config.h>
#include <linux/version.h>
#if defined(MODVERSIONS)
#include <linux/modversions.h>
#endif
#include <linux/kernel.h>
#include <linux/errno.h>
int kernel_errno;
PJ_DEF(pj_status_t) pj_get_os_error(void)
{
return errno;
}
PJ_DEF(void) pj_set_os_error(pj_status_t code)
{
errno = code;
}
PJ_DEF(pj_status_t) pj_get_netos_error(void)
{
return errno;
}
PJ_DEF(void) pj_set_netos_error(pj_status_t code)
{
errno = code;
}
/*
* platform_strerror()
*
* Platform specific error message. This file is called by pj_strerror()
* in errno.c
*/
int platform_strerror( pj_os_err_type os_errcode,
char *buf, pj_size_t bufsize)
{
char errmsg[PJ_ERR_MSG_SIZE];
int len;
/* Handle EINVAL as special case so that it'll pass errno test. */
if (os_errcode==EINVAL)
strcpy(errmsg, "Invalid value");
else
snprintf(errmsg, sizeof(errmsg), "errno=%d", os_errcode);
len = strlen(errmsg);
if (len >= bufsize)
len = bufsize-1;
pj_memcpy(buf, errmsg, len);
buf[len] = '\0';
return len;
}

View File

@ -1,66 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/os.h>
#include <linux/time.h>
///////////////////////////////////////////////////////////////////////////////
PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
{
struct timeval tval;
do_gettimeofday(&tval);
tv->sec = tval.tv_sec;
tv->msec = tval.tv_usec / 1000;
return 0;
}
PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
{
pt->year = 2005;
pt->mon = 8;
pt->day = 20;
pt->hour = 16;
pt->min = 30;
pt->sec = 30;
pt->wday = 3;
pt->yday = 200;
pt->msec = 777;
return -1;
}
/**
* Encode parsed time to time value.
*/
PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
/**
* Convert local time to GMT.
*/
PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
/**
* Convert GMT to local time.
*/
PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);

View File

@ -1,79 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/os.h>
#include <linux/time.h>
#if 0
PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
{
ts->u32.hi = 0;
ts->u32.lo = jiffies;
return 0;
}
PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
{
freq->u32.hi = 0;
freq->u32.lo = HZ;
return 0;
}
#elif 0
PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
{
struct timespec tv;
tv = CURRENT_TIME;
ts->u64 = tv.tv_sec;
ts->u64 *= NSEC_PER_SEC;
ts->u64 += tv.tv_nsec;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
{
freq->u32.hi = 0;
freq->u32.lo = NSEC_PER_SEC;
return 0;
}
#else
PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
{
struct timeval tv;
do_gettimeofday(&tv);
ts->u64 = tv.tv_sec;
ts->u64 *= USEC_PER_SEC;
ts->u64 += tv.tv_usec;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
{
freq->u32.hi = 0;
freq->u32.lo = USEC_PER_SEC;
return 0;
}
#endif

View File

@ -229,7 +229,7 @@ PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
*/
PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
{
#if 0 //!defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
#if 0
return inet_ntoa(*(struct in_addr*)&inaddr);
#else
struct in_addr addr;

View File

@ -1,785 +0,0 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/sock.h>
#include <pj/assert.h>
#include <pj/string.h> /* pj_memcpy() */
#include <pj/os.h> /* PJ_CHECK_STACK() */
#include <pj/addr_resolv.h> /* pj_gethostbyname() */
#include <pj/ctype.h>
#include <pj/compat/sprintf.h>
#include <pj/log.h>
#include <pj/errno.h>
/* Linux kernel specific. */
#include <linux/socket.h>
#include <linux/net.h>
//#include <net/sock.h>
#include <linux/security.h>
#include <linux/syscalls.h> /* sys_xxx() */
#include <asm/ioctls.h> /* FIONBIO */
#include <linux/utsname.h> /* for pj_gethostname() */
#define THIS_FILE "sock_linux_kernel.c"
/*
* Address families conversion.
* The values here are indexed based on pj_addr_family-0xFF00.
*/
const pj_uint16_t PJ_AF_UNIX = AF_UNIX;
const pj_uint16_t PJ_AF_INET = AF_INET;
const pj_uint16_t PJ_AF_INET6 = AF_INET6;
#ifdef AF_PACKET
const pj_uint16_t PJ_AF_PACKET = AF_PACKET;
#else
# error "AF_PACKET undeclared!"
#endif
#ifdef AF_IRDA
const pj_uint16_t PJ_AF_IRDA = AF_IRDA;
#else
# error "AF_IRDA undeclared!"
#endif
/*
* Socket types conversion.
* The values here are indexed based on pj_sock_type-0xFF00
*/
const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
const pj_uint16_t PJ_SOCK_DGRAM = SOCK_DGRAM;
const pj_uint16_t PJ_SOCK_RAW = SOCK_RAW;
const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
/*
* Socket level values.
*/
const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
#ifdef SOL_IP
const pj_uint16_t PJ_SOL_IP = SOL_IP;
#else
# error "SOL_IP undeclared!"
#endif /* SOL_IP */
#if defined(SOL_TCP)
const pj_uint16_t PJ_SOL_TCP = SOL_TCP;
#else
# error "SOL_TCP undeclared!"
#endif /* SOL_TCP */
#ifdef SOL_UDP
const pj_uint16_t PJ_SOL_UDP = SOL_UDP;
#else
# error "SOL_UDP undeclared!"
#endif
#ifdef SOL_IPV6
const pj_uint16_t PJ_SOL_IPV6 = SOL_IPV6;
#else
# error "SOL_IPV6 undeclared!"
#endif
/* optname values. */
const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF;
/*
* Convert 16-bit value from network byte order to host byte order.
*/
PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
{
return ntohs(netshort);
}
/*
* Convert 16-bit value from host byte order to network byte order.
*/
PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
{
return htons(hostshort);
}
/*
* Convert 32-bit value from network byte order to host byte order.
*/
PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
{
return ntohl(netlong);
}
/*
* Convert 32-bit value from host byte order to network byte order.
*/
PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
{
return htonl(hostlong);
}
/*
* Convert an Internet host address given in network byte order
* to string in standard numbers and dots notation.
*/
PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in)
{
#define UC(b) (((int)b)&0xff)
static char b[18];
char *p;
p = (char *)&in;
pj_snprintf(b, sizeof(b), "%d.%d.%d.%d",
UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
return b;
}
/*
* This function converts the Internet host address ccp from the standard
* numbers-and-dots notation into binary data and stores it in the structure
* that inp points to.
*/
PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr)
{
pj_uint32_t val;
int base, n;
char c;
unsigned parts[4];
unsigned *pp = parts;
char cp_copy[18];
char *cp = cp_copy;
addr->s_addr = PJ_INADDR_NONE;
if (ccp->slen > 15) return 0;
pj_memcpy(cp, ccp->ptr, ccp->slen);
cp[ccp->slen] = '\0';
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
if (!pj_isdigit((int)c))
return (0);
val = 0; base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X')
base = 16, c = *++cp;
else
base = 8;
}
for (;;) {
if (pj_isascii((int)c) && pj_isdigit((int)c)) {
val = (val * base) + (c - '0');
c = *++cp;
} else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) {
val = (val << 4) |
(c + 10 - (pj_islower((int)c) ? 'a' : 'A'));
c = *++cp;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3)
return (0);
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c)))
return (0);
/*
* Concoct the address according to
* the number of parts specified.
*/
n = pp - parts + 1;
switch (n) {
case 0:
return (0); /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffff)
return (0);
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
}
if (addr)
addr->s_addr = pj_htonl(val);
return (1);
}
/*
* Convert address string with numbers and dots to binary IP address.
*/
PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
{
pj_in_addr addr;
pj_inet_aton(cp, &addr);
return addr;
}
/*
* Set the IP address of an IP socket address from string address,
* with resolving the host if necessary. The string address may be in a
* standard numbers and dots notation or may be a hostname. If hostname
* is specified, then the function will resolve the host into the IP
* address.
*/
PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
const pj_str_t *str_addr)
{
PJ_CHECK_STACK();
pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME);
addr->sin_family = AF_INET;
if (str_addr && str_addr->slen) {
addr->sin_addr = pj_inet_addr(str_addr);
if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
pj_hostent he;
if (pj_gethostbyname(str_addr, &he) == 0) {
addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
} else {
addr->sin_addr.s_addr = PJ_INADDR_NONE;
return -1;
}
}
} else {
addr->sin_addr.s_addr = 0;
}
return PJ_SUCCESS;
}
/*
* Set the IP address and port of an IP socket address.
* The string address may be in a standard numbers and dots notation or
* may be a hostname. If hostname is specified, then the function will
* resolve the host into the IP address.
*/
PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
const pj_str_t *str_addr,
pj_uint16_t port)
{
pj_assert(addr && str_addr);
addr->sin_family = PJ_AF_INET;
pj_sockaddr_in_set_port(addr, port);
return pj_sockaddr_in_set_str_addr(addr, str_addr);
}
/*
* Get hostname.
*/
PJ_DEF(const pj_str_t*) pj_gethostname(void)
{
static char buf[PJ_MAX_HOSTNAME];
static pj_str_t hostname;
PJ_CHECK_STACK();
if (hostname.ptr == NULL) {
hostname.ptr = buf;
down_read(&uts_sem);
hostname.slen = strlen(system_utsname.nodename);
if (hostname.slen > PJ_MAX_HOSTNAME) {
hostname.ptr[0] = '\0';
hostname.slen = 0;
} else {
pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen);
}
up_read(&uts_sem);
}
return &hostname;
}
/*
* Get first IP address associated with the hostname.
*/
PJ_DEF(pj_in_addr) pj_gethostaddr(void)
{
pj_sockaddr_in addr;
const pj_str_t *hostname = pj_gethostname();
pj_sockaddr_in_set_str_addr(&addr, hostname);
return addr.sin_addr;
}
/*
* Create new socket/endpoint for communication and returns a descriptor.
*/
PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto,
pj_sock_t *sock_fd)
{
long result;
PJ_CHECK_STACK();
/* Sanity checks. */
PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL);
/* Initialize returned socket */
*sock_fd = PJ_INVALID_SOCKET;
/* Create socket. */
result = sys_socket(af, type, proto);
if (result < 0) {
return PJ_RETURN_OS_ERROR((-result));
}
*sock_fd = result;
return PJ_SUCCESS;
}
/*
* Bind socket.
*/
PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd,
const pj_sockaddr_t *addr,
int len)
{
long err;
mm_segment_t oldfs;
PJ_CHECK_STACK();
PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr),
PJ_EINVAL);
oldfs = get_fs();
set_fs(KERNEL_DS);
err = sys_bind(sockfd, (struct sockaddr*)addr, len);
set_fs(oldfs);
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Bind socket.
*/
PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd,
pj_uint32_t addr32,
pj_uint16_t port)
{
pj_sockaddr_in addr;
PJ_CHECK_STACK();
addr.sin_family = PJ_AF_INET;
addr.sin_addr.s_addr = pj_htonl(addr32);
addr.sin_port = pj_htons(port);
return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in));
}
/*
* Close socket.
*/
PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd)
{
long err;
err = sys_close(sockfd);
if (err != 0)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Get remote's name.
*/
PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd,
pj_sockaddr_t *addr,
int *namelen)
{
mm_segment_t oldfs;
long err;
PJ_CHECK_STACK();
oldfs = get_fs();
set_fs(KERNEL_DS);
err = sys_getpeername( sockfd, addr, namelen);
set_fs(oldfs);
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Get socket name.
*/
PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
pj_sockaddr_t *addr,
int *namelen)
{
mm_segment_t oldfs;
int err;
PJ_CHECK_STACK();
oldfs = get_fs();
set_fs(KERNEL_DS);
err = sys_getsockname( sockfd, addr, namelen );
set_fs(oldfs);
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Send data
*/
PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd,
const void *buf,
pj_ssize_t *len,
unsigned flags)
{
return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0);
}
/*
* Send data.
*/
PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd,
const void *buff,
pj_ssize_t *len,
unsigned flags,
const pj_sockaddr_t *addr,
int addr_len)
{
long err;
mm_segment_t oldfs;
PJ_CHECK_STACK();
oldfs = get_fs();
set_fs(KERNEL_DS);
err = *len = sys_sendto( sockfd, (void*)buff, *len, flags,
(void*)addr, addr_len );
set_fs(oldfs);
if (err >= 0) {
return PJ_SUCCESS;
}
else {
return PJ_RETURN_OS_ERROR(-err);
}
}
/*
* Receive data.
*/
PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd,
void *buf,
pj_ssize_t *len,
unsigned flags)
{
return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL);
}
/*
* Receive data.
*/
PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
void *buff,
pj_ssize_t *size,
unsigned flags,
pj_sockaddr_t *from,
int *fromlen)
{
mm_segment_t oldfs;
long err;
PJ_CHECK_STACK();
oldfs = get_fs();
set_fs(KERNEL_DS);
err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen);
set_fs(oldfs);
if (err >= 0) {
return PJ_SUCCESS;
}
else {
return PJ_RETURN_OS_ERROR(-err);
}
}
/*
* Get socket option.
*/
PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
pj_uint16_t level,
pj_uint16_t optname,
void *optval,
int *optlen)
{
mm_segment_t oldfs;
long err;
PJ_CHECK_STACK();
oldfs = get_fs();
set_fs(KERNEL_DS);
err = sys_getsockopt( sockfd, level, optname, optval, optlen);
set_fs(oldfs);
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Set socket option.
*/
PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
pj_uint16_t level,
pj_uint16_t optname,
const void *optval,
int optlen)
{
long err;
mm_segment_t oldfs;
PJ_CHECK_STACK();
oldfs = get_fs();
set_fs(KERNEL_DS);
err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen);
set_fs(oldfs);
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Set socket option.
*/
PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd,
const pj_sockopt_params *params)
{
unsigned int i = 0;
pj_status_t retval = PJ_SUCCESS;
PJ_CHECK_STACK();
PJ_ASSERT_RETURN(params, PJ_EINVAL);
for (;i<params->cnt && i<PJ_MAX_SOCKOPT_PARAMS;++i) {
pj_status_t status = pj_sock_setsockopt(sockfd,
params->options[i].level,
params->options[i].optname,
params->options[i].optval,
params->options[i].optlen);
if (status != PJ_SUCCESS) {
retval = status;
PJ_PERROR(4,(THIS_FILE, status,
"Warning: error applying sock opt %d",
params->options[i].optname));
}
}
return retval;
}
/*
* Shutdown socket.
*/
#if PJ_HAS_TCP
PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
int how)
{
long err;
PJ_CHECK_STACK();
err = sys_shutdown(sockfd, how);
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Start listening to incoming connections.
*/
PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd,
int backlog)
{
long err;
PJ_CHECK_STACK();
err = sys_listen( sockfd, backlog );
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Connect socket.
*/
PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
const pj_sockaddr_t *addr,
int namelen)
{
long err;
mm_segment_t oldfs;
PJ_CHECK_STACK();
oldfs = get_fs();
set_fs(KERNEL_DS);
err = sys_connect( sockfd, (void*)addr, namelen );
set_fs(oldfs);
if (err)
return PJ_RETURN_OS_ERROR(-err);
else
return PJ_SUCCESS;
}
/*
* Accept incoming connections
*/
PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd,
pj_sock_t *newsockfd,
pj_sockaddr_t *addr,
int *addrlen)
{
long err;
PJ_CHECK_STACK();
PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL);
err = sys_accept( sockfd, addr, addrlen);
if (err < 0) {
*newsockfd = PJ_INVALID_SOCKET;
return PJ_RETURN_OS_ERROR(-err);
}
else {
*newsockfd = err;
return PJ_SUCCESS;
}
}
#endif /* PJ_HAS_TCP */
/*
* Permission to steal inet_ntoa() and inet_aton() as long as this notice below
* is included:
*/
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/