Set svn:eol-style for all files

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@66 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
index deb602b..2a8d5c0 100644
--- a/pjlib/include/pj/config.h
+++ b/pjlib/include/pj/config.h
@@ -1,465 +1,465 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_CONFIG_H__

-#define __PJ_CONFIG_H__

-

-/**

- * @file config.h

- * @brief PJLIB Main configuration settings.

- */

-

-/********************************************************************

- * Include compiler specific configuration.

- */

-#if defined(_MSC_VER)

-#  include <pj/compat/cc_msvc.h>

-#elif defined(__GNUC__)

-#  include <pj/compat/cc_gcc.h>

-#else

-#  error "Unknown compiler."

-#endif

-

-

-/********************************************************************

- * Include target OS specific configuration.

- */

-#if defined(PJ_WIN32) && PJ_WIN32!=0

-#  include <pj/compat/os_win32.h>

-#elif defined(PJ_LINUX) && PJ_LINUX!=0

-#  include <pj/compat/os_linux.h>

-#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0

-#  include <pj/compat/os_linux_kernel.h>

-#elif defined(PJ_PALMOS) && PJ_PALMOS!=0

-#  include <pj/compat/os_palmos.h>

-#elif defined(PJ_SUNOS) && PJ_SUNOS!=0

-#  include <pj/compat/os_sunos.h>

-#else

-#  error "Please specify target os."

-#endif

-

-

-/********************************************************************

- * Target machine specific configuration.

- */

-#if defined (PJ_M_I386) && PJ_M_I386 != 0

-#   include <pj/compat/m_i386.h>

-#elif defined (PJ_M_M68K) && PJ_M_M68K != 0

-#   include <pj/compat/m_m68k.h>

-#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0

-#   include <pj/compat/m_alpha.h>

-#elif defined (PJ_M_SPARC) && PJ_M_SPARC != 0

-#   include <pj/compat/m_sparc.h>

-#else

-#  error "Please specify target machine."

-#endif

-

-/* Include size_t definition. */

-#include <pj/compat/size_t.h>

-

-/* Include site/user specific configuration to control PJLIB features.

- * YOU MUST CREATE THIS FILE YOURSELF!!

- */

-#include <pj/config_site.h>

-

-/********************************************************************

- * PJLIB Features.

- */

-

-/* Overrides for DOXYGEN */

-#ifdef DOXYGEN

-#   undef PJ_FUNCTIONS_ARE_INLINED

-#   undef PJ_HAS_FLOATING_POINT

-#   undef PJ_LOG_MAX_LEVEL

-#   undef PJ_LOG_MAX_SIZE

-#   undef PJ_LOG_USE_STACK_BUFFER

-#   undef PJ_TERM_HAS_COLOR

-#   undef PJ_POOL_DEBUG

-#   undef PJ_HAS_TCP

-#   undef PJ_MAX_HOSTNAME

-#   undef PJ_IOQUEUE_MAX_HANDLES

-#   undef FD_SETSIZE

-#   undef PJ_HAS_SEMAPHORE

-#   undef PJ_HAS_EVENT_OBJ

-#   undef PJ_ENABLE_EXTRA_CHECK

-#endif

-

-/**

- * @defgroup pj_config Build Configuration

- * @ingroup PJ

- * @{

- *

- * This section contains macros that can set during PJLIB build process

- * to controll various aspects of the library.

- *

- * <b>Note</b>: the values in this page does NOT necessarily reflect to the

- * macro values during the build process.

- */

-

-/**

- * If this macro is set to 1, it will enable some debugging checking

- * in the library.

- *

- * Default: equal to (NOT NDEBUG).

- */

-#ifndef PJ_DEBUG

-#  ifndef NDEBUG

-#    define PJ_DEBUG		    1

-#  else

-#    define PJ_DEBUG		    0

-#  endif

-#endif

-

-/**

- * Expand functions in *_i.h header files as inline.

- *

- * Default: 0.

- */

-#ifndef PJ_FUNCTIONS_ARE_INLINED

-#  define PJ_FUNCTIONS_ARE_INLINED  0

-#endif

-

-/**

- * Use floating point computations in the library.

- *

- * Default: 1.

- */

-#ifndef PJ_HAS_FLOATING_POINT

-#  define PJ_HAS_FLOATING_POINT	    1

-#endif

-

-/**

- * Declare maximum logging level/verbosity. Lower number indicates higher

- * importance, with the highest importance has level zero. The least

- * important level is five in this implementation, but this can be extended

- * by supplying the appropriate implementation.

- *

- * The level conventions:

- *  - 0: fatal error

- *  - 1: error

- *  - 2: warning

- *  - 3: info

- *  - 4: debug

- *  - 5: trace

- *  - 6: more detailed trace

- *

- * Default: 4

- */

-#ifndef PJ_LOG_MAX_LEVEL

-#  define PJ_LOG_MAX_LEVEL   5

-#endif

-

-/**

- * Maximum message size that can be sent to output device for each call

- * to PJ_LOG(). If the message size is longer than this value, it will be cut.

- * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER

- * flag is set.

- *

- * Default: 800

- */

-#ifndef PJ_LOG_MAX_SIZE

-#  define PJ_LOG_MAX_SIZE	    800

-#endif

-

-/**

- * Log buffer.

- * Does the log get the buffer from the stack? (default is yes).

- * If the value is set to NO, then the buffer will be taken from static

- * buffer, which in this case will make the log function non-reentrant.

- *

- * Default: 1

- */

-#ifndef PJ_LOG_USE_STACK_BUFFER

-#  define PJ_LOG_USE_STACK_BUFFER   1

-#endif

-

-

-/**

- * Colorfull terminal (for logging etc).

- *

- * Default: 1

- */

-#ifndef PJ_TERM_HAS_COLOR

-#  define PJ_TERM_HAS_COLOR	    1

-#endif

-

-/**

- * Pool debugging.

- *

- * Default: 0

- */

-#ifndef PJ_POOL_DEBUG

-#  define PJ_POOL_DEBUG		    0

-#endif

-

-/**

- * \def PJ_HAS_TCP

- * Support TCP in the library.

- * Disabling TCP will reduce the footprint slightly (about 6KB).

- *

- * Default: 1

- */

-#ifndef PJ_HAS_TCP

-#  define PJ_HAS_TCP		    1

-#endif

-

-/**

- * Maximum hostname length.

- * Libraries sometimes needs to make copy of an address to stack buffer;

- * the value here affects the stack usage.

- *

- * Default: 128

- */

-#ifndef PJ_MAX_HOSTNAME

-#  define PJ_MAX_HOSTNAME	    (128)

-#endif

-

-/**

- * Constants for declaring the maximum handles that can be supported by

- * a single IOQ framework. This constant might not be relevant to the 

- * underlying I/O queue impelementation, but still, developers should be 

- * aware of this constant, to make sure that the program will not break when

- * the underlying implementation changes.

- *

- * For implementation based on select(), the value here will be used as the

- * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will 

- * be set to this value).

- *

- * Default: 256

- */

-#ifndef PJ_IOQUEUE_MAX_HANDLES

-#  define PJ_IOQUEUE_MAX_HANDLES    (256)

-#endif

-

-/**

- * Overrides FD_SETSIZE so it is consistent throughout the library.

- * OS specific configuration header (compat/os_*) might have declared

- * FD_SETSIZE, thus we only set if it hasn't been declared.

- *

- * Default: #PJ_IOQUEUE_MAX_HANDLES

- */

-#ifndef FD_SETSIZE

-#  define FD_SETSIZE		    PJ_IOQUEUE_MAX_HANDLES

-#endif

-

-/**

- * Has semaphore functionality?

- *

- * Default: 1

- */

-#ifndef PJ_HAS_SEMAPHORE

-#  define PJ_HAS_SEMAPHORE	    1

-#endif

-

-

-/**

- * Event object (for synchronization, e.g. in Win32)

- *

- * Default: 1

- */

-#ifndef PJ_HAS_EVENT_OBJ

-#  define PJ_HAS_EVENT_OBJ	    1

-#endif

-

-

-/**

- * Enable library's extra check.

- * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to

- * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN

- * will simply evaluate to #pj_assert().

- *

- * You can disable this macro to reduce size, at the risk of crashes

- * if invalid value (e.g. NULL) is passed to the library.

- *

- * Default: 1

- */

-#ifndef PJ_ENABLE_EXTRA_CHECK

-#   define PJ_ENABLE_EXTRA_CHECK    1

-#endif

-

-

-/**

- * Enable name registration for exceptions with #pj_exception_id_alloc().

- * If this feature is enabled, then the library will keep track of

- * names associated with each exception ID requested by application via

- * #pj_exception_id_alloc().

- *

- * Disabling this macro will reduce the code and .bss size by a tad bit.

- * See also #PJ_MAX_EXCEPTION_ID.

- *

- * Default: 1

- */

-#ifndef PJ_HAS_EXCEPTION_NAMES

-#   define PJ_HAS_EXCEPTION_NAMES   1

-#endif

-

-/**

- * Maximum number of unique exception IDs that can be requested

- * with #pj_exception_id_alloc(). For each entry, a small record will

- * be allocated in the .bss segment.

- *

- * Default: 16

- */

-#ifndef PJ_MAX_EXCEPTION_ID

-#   define PJ_MAX_EXCEPTION_ID      16

-#endif

-

-/** @} */

-

-/********************************************************************

- * General macros.

- */

-

-/**

- * @def PJ_INLINE(type)

- * @param type The return type of the function.

- * Expand the function as inline.

- */

-#define PJ_INLINE(type)	  PJ_INLINE_SPECIFIER type

-

-/**

- * @def PJ_DECL(type)

- * @param type The return type of the function.

- * Declare a function.

- */

-/**

- * @def PJ_DECL_NO_RETURN(type)

- * @param type The return type of the function.

- * Declare a function that will not return.

- */

-/**

- * @def PJ_BEGIN_DECL

- * Mark beginning of declaration section in a header file.

- */

-/**

- * @def PJ_END_DECL

- * Mark end of declaration section in a header file.

- */

-#ifdef __cplusplus

-#  define PJ_DECL(type)		    type

-#  define PJ_DECL_NO_RETURN(type)   type PJ_NORETURN

-#  define PJ_BEGIN_DECL		    extern "C" {

-#  define PJ_END_DECL		    }

-#else

-#  define PJ_DECL(type)		    extern type

-#  define PJ_DECL_NO_RETURN(type)   PJ_NORETURN type

-#  define PJ_BEGIN_DECL

-#  define PJ_END_DECL

-#endif

-

-/**

- * @def PJ_DEF(type)

- * @param type The return type of the function.

- * Define a function.

- */

-#define PJ_DEF(type)	  type

-

-/**

- * @def PJ_EXPORT_SYMBOL(sym)

- * @param sym The symbol to export.

- * Export the specified symbol in compilation type that requires export

- * (e.g. Linux kernel).

- */

-#ifdef __PJ_EXPORT_SYMBOL

-#  define PJ_EXPORT_SYMBOL(sym)	    __PJ_EXPORT_SYMBOL(sym)

-#else

-#  define PJ_EXPORT_SYMBOL(sym)

-#endif

-

-/**

- * @def PJ_IDECL(type)

- * @param type  The function's return type.

- * Declare a function that may be expanded as inline.

- */

-/**

- * @def PJ_IDEF(type)

- * @param type  The function's return type.

- * Define a function that may be expanded as inline.

- */

-

-#if PJ_FUNCTIONS_ARE_INLINED

-#  define PJ_IDECL(type)  PJ_INLINE(type)

-#  define PJ_IDEF(type)   PJ_INLINE(type)

-#else

-#  define PJ_IDECL(type)  PJ_DECL(type)

-#  define PJ_IDEF(type)   PJ_DEF(type)

-#endif

-

-/**

- * @def PJ_UNUSED_ARG(arg)

- * @param arg   The argument name.

- * PJ_UNUSED_ARG prevents warning about unused argument in a function.

- */

-#define PJ_UNUSED_ARG(arg)  (void)arg

-

-/**

- * @def PJ_TODO(id)

- * @param id    Any identifier that will be printed as TODO message.

- * PJ_TODO macro will display TODO message as warning during compilation.

- * Example: PJ_TODO(CLEAN_UP_ERROR);

- */

-#ifndef PJ_TODO

-#  define PJ_TODO(id)	    TODO___##id:

-#endif

-

-/**

- * Function attributes to inform that the function may throw exception.

- *

- * @param x     The exception list, enclosed in parenthesis.

- */

-#define __pj_throw__(x)

-

-

-/********************************************************************

- * Sanity Checks

- */

-#ifndef PJ_HAS_HIGH_RES_TIMER

-#  error "PJ_HAS_HIGH_RES_TIMER is not defined!"

-#endif

-

-#if !defined(PJ_HAS_PENTIUM)

-#  error "PJ_HAS_PENTIUM is not defined!"

-#endif

-

-#if !defined(PJ_IS_LITTLE_ENDIAN)

-#  error "PJ_IS_LITTLE_ENDIAN is not defined!"

-#endif

-

-#if !defined(PJ_IS_BIG_ENDIAN)

-#  error "PJ_IS_BIG_ENDIAN is not defined!"

-#endif

-

-

-

-PJ_BEGIN_DECL

-

-/**

- * PJLIB version string.

- */

-extern const char *PJ_VERSION;

-

-/**

- * Dump configuration to log with verbosity equal to info(3).

- */

-PJ_DECL(void) pj_dump_config(void);

-

-PJ_END_DECL

-

-

-#endif	/* __PJ_CONFIG_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_CONFIG_H__
+#define __PJ_CONFIG_H__
+
+/**
+ * @file config.h
+ * @brief PJLIB Main configuration settings.
+ */
+
+/********************************************************************
+ * Include compiler specific configuration.
+ */
+#if defined(_MSC_VER)
+#  include <pj/compat/cc_msvc.h>
+#elif defined(__GNUC__)
+#  include <pj/compat/cc_gcc.h>
+#else
+#  error "Unknown compiler."
+#endif
+
+
+/********************************************************************
+ * Include target OS specific configuration.
+ */
+#if defined(PJ_WIN32) && PJ_WIN32!=0
+#  include <pj/compat/os_win32.h>
+#elif defined(PJ_LINUX) && PJ_LINUX!=0
+#  include <pj/compat/os_linux.h>
+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
+#  include <pj/compat/os_linux_kernel.h>
+#elif defined(PJ_PALMOS) && PJ_PALMOS!=0
+#  include <pj/compat/os_palmos.h>
+#elif defined(PJ_SUNOS) && PJ_SUNOS!=0
+#  include <pj/compat/os_sunos.h>
+#else
+#  error "Please specify target os."
+#endif
+
+
+/********************************************************************
+ * Target machine specific configuration.
+ */
+#if defined (PJ_M_I386) && PJ_M_I386 != 0
+#   include <pj/compat/m_i386.h>
+#elif defined (PJ_M_M68K) && PJ_M_M68K != 0
+#   include <pj/compat/m_m68k.h>
+#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
+#   include <pj/compat/m_alpha.h>
+#elif defined (PJ_M_SPARC) && PJ_M_SPARC != 0
+#   include <pj/compat/m_sparc.h>
+#else
+#  error "Please specify target machine."
+#endif
+
+/* Include size_t definition. */
+#include <pj/compat/size_t.h>
+
+/* Include site/user specific configuration to control PJLIB features.
+ * YOU MUST CREATE THIS FILE YOURSELF!!
+ */
+#include <pj/config_site.h>
+
+/********************************************************************
+ * PJLIB Features.
+ */
+
+/* Overrides for DOXYGEN */
+#ifdef DOXYGEN
+#   undef PJ_FUNCTIONS_ARE_INLINED
+#   undef PJ_HAS_FLOATING_POINT
+#   undef PJ_LOG_MAX_LEVEL
+#   undef PJ_LOG_MAX_SIZE
+#   undef PJ_LOG_USE_STACK_BUFFER
+#   undef PJ_TERM_HAS_COLOR
+#   undef PJ_POOL_DEBUG
+#   undef PJ_HAS_TCP
+#   undef PJ_MAX_HOSTNAME
+#   undef PJ_IOQUEUE_MAX_HANDLES
+#   undef FD_SETSIZE
+#   undef PJ_HAS_SEMAPHORE
+#   undef PJ_HAS_EVENT_OBJ
+#   undef PJ_ENABLE_EXTRA_CHECK
+#endif
+
+/**
+ * @defgroup pj_config Build Configuration
+ * @ingroup PJ
+ * @{
+ *
+ * This section contains macros that can set during PJLIB build process
+ * to controll various aspects of the library.
+ *
+ * <b>Note</b>: the values in this page does NOT necessarily reflect to the
+ * macro values during the build process.
+ */
+
+/**
+ * If this macro is set to 1, it will enable some debugging checking
+ * in the library.
+ *
+ * Default: equal to (NOT NDEBUG).
+ */
+#ifndef PJ_DEBUG
+#  ifndef NDEBUG
+#    define PJ_DEBUG		    1
+#  else
+#    define PJ_DEBUG		    0
+#  endif
+#endif
+
+/**
+ * Expand functions in *_i.h header files as inline.
+ *
+ * Default: 0.
+ */
+#ifndef PJ_FUNCTIONS_ARE_INLINED
+#  define PJ_FUNCTIONS_ARE_INLINED  0
+#endif
+
+/**
+ * Use floating point computations in the library.
+ *
+ * Default: 1.
+ */
+#ifndef PJ_HAS_FLOATING_POINT
+#  define PJ_HAS_FLOATING_POINT	    1
+#endif
+
+/**
+ * Declare maximum logging level/verbosity. Lower number indicates higher
+ * importance, with the highest importance has level zero. The least
+ * important level is five in this implementation, but this can be extended
+ * by supplying the appropriate implementation.
+ *
+ * The level conventions:
+ *  - 0: fatal error
+ *  - 1: error
+ *  - 2: warning
+ *  - 3: info
+ *  - 4: debug
+ *  - 5: trace
+ *  - 6: more detailed trace
+ *
+ * Default: 4
+ */
+#ifndef PJ_LOG_MAX_LEVEL
+#  define PJ_LOG_MAX_LEVEL   5
+#endif
+
+/**
+ * Maximum message size that can be sent to output device for each call
+ * to PJ_LOG(). If the message size is longer than this value, it will be cut.
+ * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER
+ * flag is set.
+ *
+ * Default: 800
+ */
+#ifndef PJ_LOG_MAX_SIZE
+#  define PJ_LOG_MAX_SIZE	    800
+#endif
+
+/**
+ * Log buffer.
+ * Does the log get the buffer from the stack? (default is yes).
+ * If the value is set to NO, then the buffer will be taken from static
+ * buffer, which in this case will make the log function non-reentrant.
+ *
+ * Default: 1
+ */
+#ifndef PJ_LOG_USE_STACK_BUFFER
+#  define PJ_LOG_USE_STACK_BUFFER   1
+#endif
+
+
+/**
+ * Colorfull terminal (for logging etc).
+ *
+ * Default: 1
+ */
+#ifndef PJ_TERM_HAS_COLOR
+#  define PJ_TERM_HAS_COLOR	    1
+#endif
+
+/**
+ * Pool debugging.
+ *
+ * Default: 0
+ */
+#ifndef PJ_POOL_DEBUG
+#  define PJ_POOL_DEBUG		    0
+#endif
+
+/**
+ * \def PJ_HAS_TCP
+ * Support TCP in the library.
+ * Disabling TCP will reduce the footprint slightly (about 6KB).
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_TCP
+#  define PJ_HAS_TCP		    1
+#endif
+
+/**
+ * Maximum hostname length.
+ * Libraries sometimes needs to make copy of an address to stack buffer;
+ * the value here affects the stack usage.
+ *
+ * Default: 128
+ */
+#ifndef PJ_MAX_HOSTNAME
+#  define PJ_MAX_HOSTNAME	    (128)
+#endif
+
+/**
+ * Constants for declaring the maximum handles that can be supported by
+ * a single IOQ framework. This constant might not be relevant to the 
+ * underlying I/O queue impelementation, but still, developers should be 
+ * aware of this constant, to make sure that the program will not break when
+ * the underlying implementation changes.
+ *
+ * For implementation based on select(), the value here will be used as the
+ * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will 
+ * be set to this value).
+ *
+ * Default: 256
+ */
+#ifndef PJ_IOQUEUE_MAX_HANDLES
+#  define PJ_IOQUEUE_MAX_HANDLES    (256)
+#endif
+
+/**
+ * Overrides FD_SETSIZE so it is consistent throughout the library.
+ * OS specific configuration header (compat/os_*) might have declared
+ * FD_SETSIZE, thus we only set if it hasn't been declared.
+ *
+ * Default: #PJ_IOQUEUE_MAX_HANDLES
+ */
+#ifndef FD_SETSIZE
+#  define FD_SETSIZE		    PJ_IOQUEUE_MAX_HANDLES
+#endif
+
+/**
+ * Has semaphore functionality?
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_SEMAPHORE
+#  define PJ_HAS_SEMAPHORE	    1
+#endif
+
+
+/**
+ * Event object (for synchronization, e.g. in Win32)
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_EVENT_OBJ
+#  define PJ_HAS_EVENT_OBJ	    1
+#endif
+
+
+/**
+ * Enable library's extra check.
+ * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to
+ * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN
+ * will simply evaluate to #pj_assert().
+ *
+ * You can disable this macro to reduce size, at the risk of crashes
+ * if invalid value (e.g. NULL) is passed to the library.
+ *
+ * Default: 1
+ */
+#ifndef PJ_ENABLE_EXTRA_CHECK
+#   define PJ_ENABLE_EXTRA_CHECK    1
+#endif
+
+
+/**
+ * Enable name registration for exceptions with #pj_exception_id_alloc().
+ * If this feature is enabled, then the library will keep track of
+ * names associated with each exception ID requested by application via
+ * #pj_exception_id_alloc().
+ *
+ * Disabling this macro will reduce the code and .bss size by a tad bit.
+ * See also #PJ_MAX_EXCEPTION_ID.
+ *
+ * Default: 1
+ */
+#ifndef PJ_HAS_EXCEPTION_NAMES
+#   define PJ_HAS_EXCEPTION_NAMES   1
+#endif
+
+/**
+ * Maximum number of unique exception IDs that can be requested
+ * with #pj_exception_id_alloc(). For each entry, a small record will
+ * be allocated in the .bss segment.
+ *
+ * Default: 16
+ */
+#ifndef PJ_MAX_EXCEPTION_ID
+#   define PJ_MAX_EXCEPTION_ID      16
+#endif
+
+/** @} */
+
+/********************************************************************
+ * General macros.
+ */
+
+/**
+ * @def PJ_INLINE(type)
+ * @param type The return type of the function.
+ * Expand the function as inline.
+ */
+#define PJ_INLINE(type)	  PJ_INLINE_SPECIFIER type
+
+/**
+ * @def PJ_DECL(type)
+ * @param type The return type of the function.
+ * Declare a function.
+ */
+/**
+ * @def PJ_DECL_NO_RETURN(type)
+ * @param type The return type of the function.
+ * Declare a function that will not return.
+ */
+/**
+ * @def PJ_BEGIN_DECL
+ * Mark beginning of declaration section in a header file.
+ */
+/**
+ * @def PJ_END_DECL
+ * Mark end of declaration section in a header file.
+ */
+#ifdef __cplusplus
+#  define PJ_DECL(type)		    type
+#  define PJ_DECL_NO_RETURN(type)   type PJ_NORETURN
+#  define PJ_BEGIN_DECL		    extern "C" {
+#  define PJ_END_DECL		    }
+#else
+#  define PJ_DECL(type)		    extern type
+#  define PJ_DECL_NO_RETURN(type)   PJ_NORETURN type
+#  define PJ_BEGIN_DECL
+#  define PJ_END_DECL
+#endif
+
+/**
+ * @def PJ_DEF(type)
+ * @param type The return type of the function.
+ * Define a function.
+ */
+#define PJ_DEF(type)	  type
+
+/**
+ * @def PJ_EXPORT_SYMBOL(sym)
+ * @param sym The symbol to export.
+ * Export the specified symbol in compilation type that requires export
+ * (e.g. Linux kernel).
+ */
+#ifdef __PJ_EXPORT_SYMBOL
+#  define PJ_EXPORT_SYMBOL(sym)	    __PJ_EXPORT_SYMBOL(sym)
+#else
+#  define PJ_EXPORT_SYMBOL(sym)
+#endif
+
+/**
+ * @def PJ_IDECL(type)
+ * @param type  The function's return type.
+ * Declare a function that may be expanded as inline.
+ */
+/**
+ * @def PJ_IDEF(type)
+ * @param type  The function's return type.
+ * Define a function that may be expanded as inline.
+ */
+
+#if PJ_FUNCTIONS_ARE_INLINED
+#  define PJ_IDECL(type)  PJ_INLINE(type)
+#  define PJ_IDEF(type)   PJ_INLINE(type)
+#else
+#  define PJ_IDECL(type)  PJ_DECL(type)
+#  define PJ_IDEF(type)   PJ_DEF(type)
+#endif
+
+/**
+ * @def PJ_UNUSED_ARG(arg)
+ * @param arg   The argument name.
+ * PJ_UNUSED_ARG prevents warning about unused argument in a function.
+ */
+#define PJ_UNUSED_ARG(arg)  (void)arg
+
+/**
+ * @def PJ_TODO(id)
+ * @param id    Any identifier that will be printed as TODO message.
+ * PJ_TODO macro will display TODO message as warning during compilation.
+ * Example: PJ_TODO(CLEAN_UP_ERROR);
+ */
+#ifndef PJ_TODO
+#  define PJ_TODO(id)	    TODO___##id:
+#endif
+
+/**
+ * Function attributes to inform that the function may throw exception.
+ *
+ * @param x     The exception list, enclosed in parenthesis.
+ */
+#define __pj_throw__(x)
+
+
+/********************************************************************
+ * Sanity Checks
+ */
+#ifndef PJ_HAS_HIGH_RES_TIMER
+#  error "PJ_HAS_HIGH_RES_TIMER is not defined!"
+#endif
+
+#if !defined(PJ_HAS_PENTIUM)
+#  error "PJ_HAS_PENTIUM is not defined!"
+#endif
+
+#if !defined(PJ_IS_LITTLE_ENDIAN)
+#  error "PJ_IS_LITTLE_ENDIAN is not defined!"
+#endif
+
+#if !defined(PJ_IS_BIG_ENDIAN)
+#  error "PJ_IS_BIG_ENDIAN is not defined!"
+#endif
+
+
+
+PJ_BEGIN_DECL
+
+/**
+ * PJLIB version string.
+ */
+extern const char *PJ_VERSION;
+
+/**
+ * Dump configuration to log with verbosity equal to info(3).
+ */
+PJ_DECL(void) pj_dump_config(void);
+
+PJ_END_DECL
+
+
+#endif	/* __PJ_CONFIG_H__ */
+
diff --git a/pjlib/include/pj/ctype.h b/pjlib/include/pj/ctype.h
index e2ab103..0319cfd 100644
--- a/pjlib/include/pj/ctype.h
+++ b/pjlib/include/pj/ctype.h
@@ -1,173 +1,173 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_CTYPE_H__

-#define __PJ_CTYPE_H__

-

-/**

- * @file ctype.h

- * @brief C type helper macros.

- */

-

-#include <pj/types.h>

-#include <pj/compat/ctype.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup pj_ctype ctype - Character Type

- * @ingroup PJ_MISC

- * @{

- *

- * This module contains several inline functions/macros for testing or

- * manipulating character types. It is provided in PJLIB because PJLIB

- * must not depend to LIBC.

- */

-

-/** 

- * Returns a non-zero value if either isalpha or isdigit is true for c.

- * @param c     The integer character to test.

- * @return      Non-zero value if either isalpha or isdigit is true for c.

- */

-PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); }

-

-/** 

- * Returns a non-zero value if c is a particular representation of an 

- * alphabetic character.

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a particular representation of an 

- *              alphabetic character.

- */

-PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); }

-

-/** 

- * Returns a non-zero value if c is a particular representation of an 

- * ASCII character.

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a particular representation of 

- *              an ASCII character.

- */

-PJ_INLINE(int) pj_isascii(int c) { return isascii(c); }

-

-/** 

- * Returns a non-zero value if c is a particular representation of 

- * a decimal-digit character.

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a particular representation of 

- *              a decimal-digit character.

- */

-PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); }

-

-/** 

- * Returns a non-zero value if c is a particular representation of 

- * a space character (0x09 - 0x0D or 0x20).

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a particular representation of 

- *              a space character (0x09 - 0x0D or 0x20).

- */

-PJ_INLINE(int) pj_isspace(int c) { return isspace(c); }

-

-/** 

- * Returns a non-zero value if c is a particular representation of 

- * a lowercase character.

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a particular representation of 

- *              a lowercase character.

- */

-PJ_INLINE(int) pj_islower(int c) { return islower(c); }

-

-

-/** 

- * Returns a non-zero value if c is a particular representation of 

- * a uppercase character.

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a particular representation of 

- *              a uppercase character.

- */

-PJ_INLINE(int) pj_isupper(int c) { return isupper(c); }

-

-/**

- * Returns a non-zero value if c is a either a space (' ') or horizontal

- * tab ('\\t') character.

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a either a space (' ') or horizontal

- *              tab ('\\t') character.

- */

-PJ_INLINE(int) pj_isblank(int c) { return isblank(c); }

-

-/**

- * Converts character to lowercase.

- * @param c     The integer character to convert.

- * @return      Lowercase character of c.

- */

-PJ_INLINE(int) pj_tolower(int c) { return tolower(c); }

-

-/**

- * Converts character to uppercase.

- * @param c     The integer character to convert.

- * @return      Uppercase character of c.

- */

-PJ_INLINE(int) pj_toupper(int c) { return toupper(c); }

-

-/**

- * Returns a non-zero value if c is a particular representation of 

- * an hexadecimal digit character.

- * @param c     The integer character to test.

- * @return      Non-zero value if c is a particular representation of 

- *              an hexadecimal digit character.

- */

-PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); }

-

-/**

- * Array of hex digits, in lowerspace.

- */

-extern char pj_hex_digits[];

-

-/**

- * Convert a value to hex representation.

- * @param value	    Integral value to convert.

- * @param p	    Buffer to hold the hex representation, which must be

- *		    at least two bytes length.

- */

-PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p)

-{

-    *p++ = pj_hex_digits[ (value & 0xF0) >> 4 ];

-    *p   = pj_hex_digits[ (value & 0x0F) ];

-}

-

-/**

- * Convert hex digit c to integral value.

- * @param c	The hex digit character.

- * @return	The integral value between 0 and 15.

- */

-PJ_INLINE(unsigned) pj_hex_digit_to_val(unsigned c)

-{

-    if (c <= '9')

-	return (c-'0') & 0x0F;

-    else if (c <= 'F')

-	return  (c-'A'+10) & 0x0F;

-    else

-	return (c-'a'+10) & 0x0F;

-}

-

-/** @} */

-

-PJ_END_DECL

-

-#endif	/* __PJ_CTYPE_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_CTYPE_H__
+#define __PJ_CTYPE_H__
+
+/**
+ * @file ctype.h
+ * @brief C type helper macros.
+ */
+
+#include <pj/types.h>
+#include <pj/compat/ctype.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup pj_ctype ctype - Character Type
+ * @ingroup PJ_MISC
+ * @{
+ *
+ * This module contains several inline functions/macros for testing or
+ * manipulating character types. It is provided in PJLIB because PJLIB
+ * must not depend to LIBC.
+ */
+
+/** 
+ * Returns a non-zero value if either isalpha or isdigit is true for c.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if either isalpha or isdigit is true for c.
+ */
+PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); }
+
+/** 
+ * Returns a non-zero value if c is a particular representation of an 
+ * alphabetic character.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a particular representation of an 
+ *              alphabetic character.
+ */
+PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); }
+
+/** 
+ * Returns a non-zero value if c is a particular representation of an 
+ * ASCII character.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a particular representation of 
+ *              an ASCII character.
+ */
+PJ_INLINE(int) pj_isascii(int c) { return isascii(c); }
+
+/** 
+ * Returns a non-zero value if c is a particular representation of 
+ * a decimal-digit character.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a particular representation of 
+ *              a decimal-digit character.
+ */
+PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); }
+
+/** 
+ * Returns a non-zero value if c is a particular representation of 
+ * a space character (0x09 - 0x0D or 0x20).
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a particular representation of 
+ *              a space character (0x09 - 0x0D or 0x20).
+ */
+PJ_INLINE(int) pj_isspace(int c) { return isspace(c); }
+
+/** 
+ * Returns a non-zero value if c is a particular representation of 
+ * a lowercase character.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a particular representation of 
+ *              a lowercase character.
+ */
+PJ_INLINE(int) pj_islower(int c) { return islower(c); }
+
+
+/** 
+ * Returns a non-zero value if c is a particular representation of 
+ * a uppercase character.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a particular representation of 
+ *              a uppercase character.
+ */
+PJ_INLINE(int) pj_isupper(int c) { return isupper(c); }
+
+/**
+ * Returns a non-zero value if c is a either a space (' ') or horizontal
+ * tab ('\\t') character.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a either a space (' ') or horizontal
+ *              tab ('\\t') character.
+ */
+PJ_INLINE(int) pj_isblank(int c) { return isblank(c); }
+
+/**
+ * Converts character to lowercase.
+ * @param c     The integer character to convert.
+ * @return      Lowercase character of c.
+ */
+PJ_INLINE(int) pj_tolower(int c) { return tolower(c); }
+
+/**
+ * Converts character to uppercase.
+ * @param c     The integer character to convert.
+ * @return      Uppercase character of c.
+ */
+PJ_INLINE(int) pj_toupper(int c) { return toupper(c); }
+
+/**
+ * Returns a non-zero value if c is a particular representation of 
+ * an hexadecimal digit character.
+ * @param c     The integer character to test.
+ * @return      Non-zero value if c is a particular representation of 
+ *              an hexadecimal digit character.
+ */
+PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); }
+
+/**
+ * Array of hex digits, in lowerspace.
+ */
+extern char pj_hex_digits[];
+
+/**
+ * Convert a value to hex representation.
+ * @param value	    Integral value to convert.
+ * @param p	    Buffer to hold the hex representation, which must be
+ *		    at least two bytes length.
+ */
+PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p)
+{
+    *p++ = pj_hex_digits[ (value & 0xF0) >> 4 ];
+    *p   = pj_hex_digits[ (value & 0x0F) ];
+}
+
+/**
+ * Convert hex digit c to integral value.
+ * @param c	The hex digit character.
+ * @return	The integral value between 0 and 15.
+ */
+PJ_INLINE(unsigned) pj_hex_digit_to_val(unsigned c)
+{
+    if (c <= '9')
+	return (c-'0') & 0x0F;
+    else if (c <= 'F')
+	return  (c-'A'+10) & 0x0F;
+    else
+	return (c-'a'+10) & 0x0F;
+}
+
+/** @} */
+
+PJ_END_DECL
+
+#endif	/* __PJ_CTYPE_H__ */
+
diff --git a/pjlib/include/pj/doxygen.h b/pjlib/include/pj/doxygen.h
index 1b5f479..f4bf8db 100644
--- a/pjlib/include/pj/doxygen.h
+++ b/pjlib/include/pj/doxygen.h
@@ -1,1019 +1,1019 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_DOXYGEN_H__

-#define __PJ_DOXYGEN_H__

-

-/**

- * @file doxygen.h

- * @brief Doxygen's mainpage.

- */

-

-/*////////////////////////////////////////////////////////////////////////// */

-/*

-	INTRODUCTION PAGE

- */

-

-/**

- * @mainpage Welcome to PJLIB!

- *

- * @section intro_sec What is PJLIB

- *

- * PJLIB is a small foundation library written in C for making scalable 

- * applications. Because of its small footprint, it can be used in embedded 

- * applications (we hope so!), but yet the library is also aimed for 

- * facilitating high performance protocol stacks.

- *

- * PJLIB is released under LGPL terms.

- *

- * @section download_sec Download

- *

- * PJLIB and all documentation can be downloaded from 

- * http://www.pjproject.net.

- *

- *

- * @section how_to_use_sec About This Documentation

- *

- * This document is generated directly from PJLIB source file using

- * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!) 

- * tools for generating such documentation.

- *

- * @subsection doc_ver_subsec Version

- *

- * This document corresponds to PJLIB version 0.3-pre2.

- *

- *

- * @subsection find_samples_subsec How to Read This Document

- *

- * This documentation is laid out more to be a reference guide instead

- * of tutorial, therefore first time users may find it difficult to

- * grasp PJLIB by reading this document alone.

- *

- * However, we've tried our best to make this document easy to follow.

- * For first time users, we would suggest that you follow these steps

- * when reading this documentation:

- *

- *  - continue reading this introduction chapter. At the end of this

- *    chapter, you'll find section called \ref pjlib_fundamentals_sec

- *    which should guide you to understand basic things about PJLIB.

- *

- *  - find information about specific features that you want to use

- *    in PJLIB. Use the <b>Module Index</b> to find out about all 

- *    features in PJLIB (if you're browsing the HTML documentation,

- *    click on the \a Module link on top of the page, or if you're

- *    reading the PDF documentation, click on \a Module \a Documentation

- *    on the navigation pane on the left).

- *

- * @subsection doc_organize_sec How To's

- *

- * Please find below links to specific tasks that you probably

- * want to do:

- *

- *  - <b>How to Build PJLIB</b>

- *\n

- * Please refer to \ref pjlib_build_sys_pg page for more information.

- *

- *  - <b>How to Use PJLIB in My Application</b>

- *\n

- * Please refer to \ref configure_app_sec for more information.

- *

- *  - <b>How to Port PJLIB</b>

- *\n

- * Please refer to \ref porting_pjlib_pg page.

- *

- *  - <b>Where to Read Samples Documentation</b>

- *\n

- * Most of the modules provide link to the corresponding sample file.

- * Alternatively, to get the list of all examples, you can click on 

- * <b>Related Pages</b> on the top of HTML document or on 

- * <b>PJLIB Page Documentation</b> on navigation pane of your PDF reader.

- *

- *  - <b>How to Submit Code to PJLIB Project</b>

- *\n

- * Please read \ref pjlib_coding_convention_page before submitting

- * your code. Send your code as patch against current Subversion tree

- * to the appropriate mailing list.

- *

- *

- * @section features_sec Features

- *

- * @subsection open_source_feat It's Open Source!

- *

- * PJLIB is currently released on LGPL license. We may release PJLIB under

- * additional schemes in the future (such as GPL or MPL) to incorporate

- * linking with specific application, however, one thing for sure is

- * we will NEVER be able to make PJLIB a proprietary software.

- *

- * @subsection extreme_portable_feat Extreme Portability

- *

- * PJLIB is designed to be extremely portable. It can run on any kind

- * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single

- * or multi-processors) and operating systems. Floating point or no

- * floating point. Multi-threading or not.

- * It can even run in environment where no ANSI LIBC is available. 

- *

- * Currently PJLIB is being ported to:

- *  - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw).

- *  - x86, Linux (user mode and as <b>kernel module</b>(!)).

- *  - alpha, Linux

- * And coming up:

- *  - x86, eCos

- *  - ultra-II, Solaris.

- *  - powerpc, MacOS

- *  - m68k, PalmOS.

- *  - arm, PocketPC

- *

- * No other library is known to have this extreme portability!

- *

- * @subsection small_size_feat Small in Size

- *

- * One of the primary objectives is to have library that is small in size for

- * typical embedded applications. As a rough guidance, we aim to keep the 

- * library size below 100KB for it to be considered as small.

- * As the result, most of the functionalities in the library can be tailored

- * to meet the requirements; user can enable/disable specific functionalities

- * to get the desired size/performance/functionality balance.

- *

- * For more info, please see @ref pj_config.

- *

- * @subsection no_dyn_mem No Dynamic Memory Allocations

- *

- * The central idea of PJLIB is that for applications to run as fast as it can,

- * it should not use \a malloc() at all, but instead should get the memory 

- * from a preallocated storage pool. There are few things that can be 

- * optimized with this approach:

- *

- *  - \a alloc() is a O(1) operation.

- *  - no mutex is used inside alloc(). It is assumed that synchronization 

- *    will be used in higher abstraction by application anyway.

- *  - no \a free() is required. All chunks will be deleted when the pool is 

- *    destroyed.

- *

- * The performance gained on some systems can be as high as 10x speed up

- * against \a malloc() and \a free().

- *

- * For more information, see \ref PJ_POOL_GROUP

- *

- * 

- * @subsection os_abstract_feat Operating System Abstraction

- *

- * PJLIB has abstractions for features that are normally not portable 

- * across operating systems: 

- *  - @ref PJ_THREAD

- *\n

- *    Portable thread manipulation.

- *  - @ref PJ_TLS

- *\n

- *    Storing data in thread's private data.

- *  - @ref PJ_MUTEX

- *\n

- *    Mutual exclusion protection.

- *  - @ref PJ_SEM

- *\n

- *    Semaphores.

- *  - @ref PJ_ATOMIC

- *\n

- *    Atomic variables and their operations.

- *  - @ref PJ_CRIT_SEC

- *\n

- *    Fast locking of critical sections.

- *  - @ref PJ_LOCK

- *\n

- *    High level abstraction for lock objects.

- *  - @ref PJ_EVENT

- *\n

- *    Event object.

- *  - @ref PJ_TIME

- *\n

- *    Portable time manipulation.

- *  - @ref PJ_TIMESTAMP

- *\n

- *    High resolution time value.

- *  - etc.

- *

- *

- * @subsection ll_network_io_sec Low-Level Network I/O

- *

- * PJLIB has very portable abstraction and fairly complete set of API for

- * doing network I/O communications. At the lowest level, PJLIB provides:

- *

- *  - @ref PJ_SOCK

- *\n

- *    A highly portable socket abstraction, runs on all kind of

- *    network APIs such as standard BSD socket, Windows socket, Linux

- *    \b kernel socket, PalmOS networking API, etc.

- *

- *  - @ref pj_addr_resolve

- *\n

- *    Portable address resolution, which implements #pj_gethostbyname().

- *

- *  - @ref PJ_SOCK_SELECT

- *\n

- *    A portable \a select() like API (#pj_sock_select()) which can be

- *    implemented with various back-end.

- *

- *

- * @subsection hl_network_io_sec High-Level Network I/O

- *

- * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE, 

- * which promotes creating high performance network

- * applications by managing asynchronous I/O. This is a passive framework

- * that utilizes the most effective way to manage asynchronous I/O

- * on a given platform, such as:

- *  - IoCompletionPort on WinNT,

- *  - on Linux it can use either /dev/epoll or aio.

- *  - or to fall back to use @a select()

- *

- * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which

- * combines asynchronous I/O with timer management and thread management 

- * to fasilitate creating trully high performance, event driven

- * application.

- * 

- *

- * @subsection timer_mgmt_sec Timer Management

- *

- * A passive framework for managing timer, see @ref PJ_TIMER for more info.

- * There is also function to retrieve high resolution timestamp

- * from the system (see @ref PJ_TIMESTAMP).

- *

- *

- * @subsection data_struct_sec Various Data Structures

- *

- * Various data structures are provided in the library:

- *

- *  - @ref PJ_PSTR

- *  - @ref PJ_ARRAY

- *  - @ref PJ_HASH

- *  - @ref PJ_LIST

- *  - @ref PJ_RBTREE

- *

- *

- * @subsection exception_sec Exception Construct

- *

- * A convenient TRY/CATCH like construct to propagate errors, which by

- * default are used by the @ref PJ_POOL_GROUP "memory pool" and 

- * the lexical scanner in pjlib-util. The exception

- * construct can be used to write programs like below:

- *

- * <pre>

- *    #define SYNTAX_ERROR  1

- *

- *    PJ_TRY {

- *       msg = NULL;

- *       msg = parse_msg(buf, len);

- *    }

- *    PJ_CATCH ( SYNTAX_ERROR ) {

- *       .. handle error ..

- *    }

- *    PJ_END;

- * </pre>

- *

- * Please see @ref PJ_EXCEPT for more information.

- *

- *

- * @subsection logging_sec Logging Facility

- *

- * PJLIB @ref PJ_LOG consists of macros to write logging information to

- * some output device. Some of the features of the logging facility:

- *

- *  - the verbosity can be fine-tuned both at compile time (to control

- *    the library size) or run-time (to control the verbosity of the

- *    information).

- *  - output device is configurable (e.g. stdout, printk, file, etc.)

- *  - log decoration is configurable.

- *

- * See @ref PJ_LOG for more information.

- *

- *

- * @subsection guid_gen_sec Random and GUID Generation

- *

- * PJLIB provides facility to create random string 

- * (#pj_create_random_string()) or globally unique identifier

- * (see @ref PJ_GUID).

- *

- *

- *

- * @section configure_app_sec Configuring Application to use PJLIB

- *

- * @subsection pjlib_compil_sec Building PJLIB

- *

- * Follow the instructions in \ref pjlib_build_sys_pg to build

- * PJLIB.

- *

- * @subsection pjlib_compil_app_sec Building Applications with PJLIB

- *

- * Use the following settings when building applications with PJLIB.

- *

- * @subsubsection compil_inc_dir_sec Include Search Path

- *

- * Add this to your include search path ($PJLIB is PJLIB root directory):

- * <pre>

- *   $PJLIB/include

- * </pre>

- *

- * @subsubsection compil_inc_file_sec Include PJLIB Header

- *

- * To include all PJLIB headers:

- * \verbatim

-    #include <pjlib.h>

-   \endverbatim

- *

- * Alternatively, you can include individual PJLIB headers like this:

- * \verbatim

-     #include <pj/log.h>

-     #include <pj/os.h>

-  \endverbatim

- *

- *

- * @subsubsection compil_lib_dir_sec Library Path

- *

- * Add this to your library search path:

- * <pre>

- *   $PJLIB/lib

- * </pre>

- *

- * Then add the appropriate PJLIB library to your link specification. For

- * example, you would add \c libpj-i386-linux-gcc.a when you're building

- * applications in Linux.

- *

- *

- * @subsection pjlib_fundamentals_sec Principles in Using PJLIB

- *

- * Few things that you \b MUST do when using PJLIB, to make sure that

- * you create trully portable applications.

- *

- * @subsubsection call_pjlib_init_sec Call pj_init()

- *

- * Before you do anything else, call \c pj_init(). This would make sure that

- * PJLIB system is properly set up.

- *

- * @subsubsection no_ansi_subsec Do NOT Use ANSI C

- *

- * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable

- * library in the world, nor it's the most ubiquitous. For example, LIBC

- * is not available in Linux kernel. Also normally LIBC will be excluded

- * from compilation of RTOSes to reduce size.

- *

- * So for maximum portability, do NOT use ANSI C. Do not even try to include

- * any other header files outside <include/pj>. Stick with the functionalities

- * provided by PJLIB. 

- *

- *

- * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings

- *

- * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this

- * convention too. Remember, ANSI string-h is not always available. And

- * PJLIB string is faster!

- *

- * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations

- *

- * You MUST NOT use \a malloc() or any other memory allocation functions.

- * Use PJLIB pool instead! It's faster and most portable.

- *

- * @subsection logging_subsubsec Use Logging for Text Display

- *

- * DO NOT use <stdio.h> for text output. Use PJLIB logging instead.

- *

- *

- * @section porting_pjlib_sec0 Porting PJLIB

- *

- * Please see \ref porting_pjlib_pg page on more information to port

- * PJLIB to new target.

- *

- * @section enjoy_sec Enjoy Using PJLIB!

- *

- * We hope that you find PJLIB usefull for your application. If you

- * have any questions, suggestions, critics, bug fixes, or anything

- * else, we would be happy to hear it.

- *

- * Enjoy using PJLIB!

- *

- * Benny Prijono < bennylp at pjproject dot net >

- */

-

-

-

-/*////////////////////////////////////////////////////////////////////////// */

-/*

-         CODING CONVENTION

- */

-

-/**

- * @page pjlib_coding_convention_page Coding Convention

- *

- * Before you submit your code/patches to be included with PJLIB, you must

- * make sure that your code is compliant with PJLIB coding convention.

- * <b>This is very important!</b> Otherwise we would not accept your code.

- *

- * @section coding_conv_editor_sec Editor Settings

- *

- * The single most important thing in the whole coding convention is editor 

- * settings. It's more important than the correctness of your code (bugs will

- * only crash the system, but incorrect tab size is mental!).

- *

- * Kindly set your editor as follows:

- *  - tab size to \b 8.

- *  - indentation to \b 4.

- *

- * With \c vi, you can do it with:

- * <pre>

- *  :se ts=8

- *  :se sts=4

- * </pre>

- *

- * You should replace tab with eight spaces.

- *

- * @section coding_conv_detail_sec Coding Style

- *

- * Coding style MUST strictly follow K&R style. The rest of coding style

- * must follow current style. You SHOULD be able to observe the style

- * currently used by PJLIB from PJLIB sources, and apply the style to your 

- * code. If you're not able to do simple thing like to observe PJLIB

- * coding style from the sources, then logic dictates that your ability to

- * observe more difficult area in PJLIB such as memory allocation strategy, 

- * concurrency, etc is questionable.

- *

- * @section coding_conv_comment_sec Commenting Your Code

- *

- * Public API (e.g. in header files) MUST have doxygen compliant comments.

- *

- */

-

-

-/*////////////////////////////////////////////////////////////////////////// */

-/*

-	BUILDING AND INSTALLING PJLIB

- */

-

-

-

-/**

- * @page pjlib_build_sys_pg Building, and Installing PJLIB

- *

- * @section build_sys_install_sec Build and Installation

- *

- * @subsection build_sys_install_win32_sec Visual Studio

- *

- * The PJLIB Visual Studio workspace supports the building of PJLIB

- * for Win32 target. Although currently only the Visual Studio 6 Workspace is

- * actively maintained, developers with later version of Visual Studio

- * can easily imports VS6 workspace into their IDE.

- *

- * To start building PJLIB projects with Visual Studio 6 or later, open

- * the \a workspace file in the corresponding \b \c build directory. You have

- * several choices on which \a dsw file to open:

- \verbatim

- $PJPROJECT/build/pjproject.dsw

- $PJPROJECT/pjlib/build/pjlib.dsw

- $PJPROJECT/pjsip/build/pjsip.dsw

- ..etc

- \endverbatim

- *

- * The easiest way is to open <tt>pjproject.dsw</tt> file in \b \c $PJPROJECT/build

- * directory. However this will only build the required projects, not

- * the complete projects. For example, the PJLIB test and samples projects 

- * are not included in this workspace. To build the complete projects, you must

- * open and build each \a dsw file in \c build directory in each

- * subprojects. For example, to open the complete PJLIB workspace, open

- * <tt>pjlib.dsw</tt> in <tt>$PJPROJECT/pjlib/build</tt> directory.

- *

- *

- * @subsubsection config_site_create_vc_sec Create config_site.h

- *

- * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>

- * is supposed to contain configuration that is specific to your site/target.

- * This file is not part of PJLIB, so you must create it yourself. Normally

- * you just need to create a blank file.

- *

- * The reason why it's not included in PJLIB is so that you would not accidently

- * overwrite your site configuration.

- *

- * If you fail to do this, Visual C will complain with error like: 

- *

- * <b>"fatal error C1083: Cannot open include file: 'pj/config_site.h': No such file 

- * or directory"</b>.

- *

- * @subsubsection build_vc_subsubsec Build the Projects

- *

- * Just hit the build button!

- *

- *

- * @subsection build_sys_install_unix_sec Make System

- *

- * For other targets, PJLIB provides a rather comprehensive build system

- * that uses GNU \a make (and only GNU \a make will work). 

- * Currently, the build system supports building * PJLIB for these targets:

- *  - i386/Win32/mingw

- *  - i386/Linux

- *  - i386/Linux (kernel)

- *  - alpha/linux

- *  - sparc/SunOS

- *  - etc..

- *

- *

- * @subsubsection build_req_sec Requirements

- *

- * In order to use the \c make based build system, you MUST have:

- *

- *  - <b>GNU make</b>

- *\n

- *    The Makefiles heavily utilize GNU make commands which most likely

- *    are not available in other \c make system.

- *  - <b>bash</b> shell is recommended.

- *\n

- *    Specificly, there is a command <tt>"echo -n"</tt> which may not work

- *    in other shells. This command is used when generating dependencies

- *    (<tt>make dep</tt>) and it's located in 

- *    <tt>$PJPROJECT/build/rules.mak</tt>.

- *  - <b>ar</b>, <b>ranlib</b> from GNU binutils

- *\n

- *    In your system has different <tt>ar</tt> or <tt>ranlib</tt> (e.g. they

- *    may have been installed as <tt>gar</tt> and <tt>granlib</tt>), then

- *    either you create the relevant symbolic links, <b>or</b> modify

- *    <tt>$PJPROJECT/build/cc-gcc.mak</tt> and rename <tt>ar</tt> and

- *    <tt>ranlib</tt> to the appropriate names.

- *  - <b>gcc</b> to generate dependency.

- *\n

- *    Currently the build system uses <tt>"gcc -MM"</tt> to generate build

- *    dependencies. If <tt>gcc</tt> is not desired to generate dependency,

- *    then either you don't run <tt>make dep</tt>, <b>or</b> edit

- *    <tt>$PJPROJECT/build/rules.mak</tt> to calculate dependency using

- *    your prefered method. (And let me know when you do so so that I can

- *    update the file. :) )

- *

- * @subsubsection build_overview_sec Building the Project

- *

- * Generally, steps required to build the PJLIB are:

- *

- \verbatim

-   $ cd /home/user/pjproject         # <-- go to $PJPROJECT

-   $ vi build.mak                    # <-- set build target etc

-   $ touch pjlib/include/pj/config_site.h

-   $ cd pjlib/build                  # <-- go to projet's build dir

-   $ make                            # <-- build the project

- \endverbatim

- *

- * For other project, \a cd to <tt>build</tt> directory in the project

- * and execute \a make from there.

- *

- * \note For Linux kernel target, there are additional steps required, which

- * will be explained in section \ref linux_kern_target_subsec.

- *

- * @subsubsection build_mak_sec Editing build.mak

- * 

- * The \c build.mak file in \c $PJPROJECT root directory is used to

- * specify the build configuration. This file is expected to export

- * the following \a make variables:

- *

- *  - <tt><b>MACHINE_NAME</b></tt>

- *\n

- *    Target machine/processor, one of: <b>{ i386 | alpha | sparc }</b>.

- *

- *  - <tt><b>OS_NAME</b></tt>

- *\n

- *    Target operating system, one of: <b>{ win32 | linux | 

- *      linux-kernel | sunos }</b>.

- *

- *  - <tt><b>CC_NAME</b></tt>

- *\n

- *    Compiler name: <b>{ gcc | vc }</b>\n

- *    (Note that support for Visual C (vc) compiler with the \c make system is

- *    experimental, and it will only work when run inside a DOS shell

- *    (i.e. <tt>"HOST_NAME=win32"</tt>)).

- *

- *  - <tt><b>HOST_NAME</b></tt>

- *\n

- *    Build host: <b>{ unix | mingw | win32 }</b>\n

- *    (Note: win32 host means a DOS command prompt. Support for this type

- *    of development host is experimental).

- *

- * These variables will cause the correct configuration file in 

- * \c $PJPROJECT/build directory to be executed by \a make. For 

- * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak

- * in \c build directory to be executed. These files contain specific

- * configuration for the option that is selected.

- *

- * For Linux kernel target, you are also required to declare the following

- * variables in this file:

- *	- \c KERNEL_DIR: full path of kernel source tree.

- *	- \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank

- * 	     for default.

- *	- \c PJPROJECT_DIR: full path of PJPROJECT source tree.

- *

- * Apart from these, there are also additional steps required to build

- * Linux kernel target, which will be explained in \ref linux_kern_target_subsec.

- *

- * @subsubsection build_dir_sec Files in "build" Directory

- *

- * The <tt>*.mak</tt> files in \c $PJPROJECT/build directory are used to specify

- * the configuration for the specified compiler, target machine target 

- * operating system, and host options. These files will be executed

- * (included) by \a make during building process, depending on the values

- * specified in <b>$PJPROJECT/build.mak</b> file.

- *

- * Normally you don't need to edit these files, except when you're porting

- * PJLIB to new target.

- *

- * Below are the description of some files in this directory:

- *

- *  - <tt>rules.mak</tt>: contains generic rules always included during make.

- *  - <tt>cc-gcc.mak</tt>: rules when gcc is used for compiler.

- *  - <tt>cc-vc.mak</tt>: rules when MSVC compiler is used.

- *  - <tt>host-mingw.mak</tt>: rules for building in mingw host.

- *  - <tt>host-unix.mak</tt>: rules for building in Unix/Posix host.

- *  - <tt>host-win32.mak</tt>: rules for building in Win32 command console

- *    (only valid when VC is used).

- *  - <tt>m-i386.mak</tt>: rules when target machine is an i386 processor.

- *  - <tt>m-m68k.mak</tt>: rules when target machine is an m68k processor.

- *  - <tt>os-linux.mak</tt>: rules when target OS is Linux.

- *  - <tt>os-linux-kernel.mak</tt>: rules when PJLIB is to be build as

- *    part of Linux kernel.

- *  - <tt>os-win32.mak</tt>: rules when target OS is Win32.

- *

- *

- * @subsubsection config_site_create_sec Create config_site.h

- *

- * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>

- * is supposed to contain configuration that is specific to your site/target.

- * This file is not part of PJLIB, so you must create it yourself.

- *

- * The reason why it's not included in PJLIB is so that you would not accidently

- * overwrite your site configuration.

- *

- *

- * @subsubsection invoking_make_sec Invoking make

- *

- * Normally, \a make is invoked in \c build directory under each project.

- * For example, to build PJLIB, you would invoke \a make in

- * \c $PJPROJECT/pjlib/build directory like below:

- *

- \verbatim

-   $ cd pjlib/build

-   $ make

- \endverbatim

- *

- * Alternatively you may invoke <tt>make</tt> in <tt>$PJPROJECT</tt> 

- * directory, to build all projects under that directory (e.g. 

- * PJLIB, PJSIP, etc.).

- *

- *

- * @subsubsection linux_kern_target_subsec Linux Kernel Target

- *

- * \note

- * <b>BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS.

- * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB

- * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION

- * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE.

- * YOU HAVE BEEN WARNED.</b>

- *

- * \note

- * <b>User Mode Linux (UML)</b> provides excellent way to experiment with Linux

- * kernel without risking the stability of the host system. See

- * http://user-mode-linux.sourceforge.net for details.

- *

- * \note

- * I only use <b>UML</b> to experiment with PJLIB kernel modules.

- * <b>I wouldn't be so foolish to use my host Linux machine to experiment

- * with this.</b> 

- *

- * \note

- * You have been warned.

- *

- * For building PJLIB for Linux kernel target, there are additional steps required.

- * In general, the additional tasks are:

- *	- Declare some more variables in <b><tt>build.mak</tt></b> file (this

- *        has been explained in \ref build_mak_sec above).

- *      - Perform these two small modifications in kernel source tree.

- *

- * There are two small modification need to be applied to the kernel tree.

- *

- * <b>1. Edit <tt>Makefile</tt> in kernel root source tree.</b>

- *

- * Add the following lines at the end of the <tt>Makefile</tt> in your 

- * <tt>$KERNEL_SRC</tt> dir:

- \verbatim

-script:

-       $(SCRIPT)

- \endverbatim

- *

- * \note Remember to replace spaces with <b>tab</b> in the Makefile.

- *

- * The modification above is needed to capture kernel's \c $CFLAGS and 

- * \c $CFLAGS_MODULE which will be used for PJLIB's compilation.

- *

- * <b>2. Add Additional Exports.</b>

- *

- * We need the kernel to export some more symbols for our use. So we declare

- * the additional symbols to be exported in <tt>extra-exports.c</tt> file, and add

- * a this file to be compiled into the kernel:

- *

- *	- Copy the file <tt>extra-exports.c</tt> from <tt>pjlib/src/pj</tt> 

- *	  directory to <tt>$KERNEL_SRC/kernel/</tt> directory.

- *	- Edit <tt>Makefile</tt> in that directory, and add this line

- *        somewhere after the declaration of that variable:

- \verbatim

-obj-y   += extra-exports.o

- \endverbatim

- *

- * To illustrate what have been done in your kernel source tree, below

- * is screenshot of my kernel source tree _after_ the modification.

- *

- \verbatim

-[root@vpc-linux linux-2.6.7]# pwd

-/usr/src/linux-2.6.7

-[root@vpc-linux linux-2.6.7]# 

-[root@vpc-linux linux-2.6.7]# 

-[root@vpc-linux linux-2.6.7]# tail Makefile 

-

-endif   # skip-makefile

-

-FORCE:

-

-.PHONY: script

-

-script:

-        $(SCRIPT)

-

-[root@vpc-linux linux-2.6.7]# 

-[root@vpc-linux linux-2.6.7]# 

-[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c 

-#include <linux/module.h>

-#include <linux/syscalls.h>

-

-EXPORT_SYMBOL(sys_select);

-

-EXPORT_SYMBOL(sys_epoll_create);

-EXPORT_SYMBOL(sys_epoll_ctl);

-EXPORT_SYMBOL(sys_epoll_wait);

-

-EXPORT_SYMBOL(sys_socket);

-[root@vpc-linux linux-2.6.7]# 

-[root@vpc-linux linux-2.6.7]# 

-[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile 

-#

-# Makefile for the linux kernel.

-#

-

-obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \

-            exit.o itimer.o time.o softirq.o resource.o \

-            sysctl.o capability.o ptrace.o timer.o user.o \

-            signal.o sys.o kmod.o workqueue.o pid.o \

-            rcupdate.o intermodule.o extable.o params.o posix-timers.o \

-            kthread.o

-

-obj-y   +=  extra-exports.o

-

-obj-$(CONFIG_FUTEX) += futex.o

-obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o

-[root@vpc-linux linux-2.6.7]# 

-

- \endverbatim

- *

- * Then you must rebuild the kernel.

- * If you fail to do this, you won't be able to <b>insmod</b> pjlib.

- *

- * \note You will see a lots of warning messages during pjlib-test compilation.

- * The warning messages complain about unresolved symbols which are defined

- * in pjlib module. You can safely ignore these warnings. However, you can not

- * ignore warnings about non-pjlib unresolved symbols.

- *

- * 

- * @subsection makefile_explained_sec Makefile Explained

- *

- * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be

- * very similar in the contents. The Makefile is located under \c build

- * directory in each project subdir.

- *

- * @subsubsection pjlib_makefile_subsec PJLIB Makefile.

- *

- * Below is PJLIB's Makefile:

- *

- * \include build/Makefile

- *

- * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak.

- *

- * Below is file <tt><b>os-linux.mak</b></tt> file in 

- * <tt>$PJPROJECT/pjlib/build</tt> directory,

- * which is OS specific configuration file for Linux target that is specific 

- * for PJLIB project. For \b global OS specific configuration, please see

- * <tt>$PJPROJECT/build/os-*.mak</tt>.

- *

- * \include build/os-linux.mak

- *

- */

-

-

-/*////////////////////////////////////////////////////////////////////////// */

-/*

-         PORTING PJLIB

- */

-

-

-

-/**

- * @page porting_pjlib_pg Porting PJLIB

- *

- *

- * @section new_arch_sec Porting to New CPU Architecture

- *

- * Below is step-by-step guide to add support for new CPU architecture.

- * This sample is based on porting to Alpha architecture; however steps for 

- * porting to other CPU architectures should be pretty similar. 

- *

- * Also note that in this example, the operating system used is <b>Linux</b>.

- * Should you wish to add support for new operating system, then follow

- * the next section \ref porting_os_sec.

- *

- * Step-by-step guide to port to new CPU architecture:

- *  - decide the name for the new architecture. In this case, we choose

- *    <tt><b>alpha</b></tt>.

- *  - edit file <tt>$PJPROJECT/build.mak</tt>, and add new section for

- *    the new target:

- *    <pre>

- *      #

- *      # Linux alpha, gcc

- *      #

- *      export MACHINE_NAME := <b>alpha</b>

- *      export OS_NAME := linux

- *      export CC_NAME := gcc

- *      export HOST_NAME := unix

- *    </pre>

- *

- *  - create a new file <tt>$PJPROJECT/build/<b>m-alpha</b>.mak</tt>.

- *    Alternatively create a copy from other file in this directory.

- *    The contents of this file will look something like:

- *    <pre>

- *      export M_CFLAGS := $(CC_DEF)<b>PJ_M_ALPHA=1</b>

- *      export M_CXXFLAGS :=

- *      export M_LDFLAGS :=

- *      export M_SOURCES :=

- *    </pre>

- *  - create a new file <tt>$PJPROJECT/pjlib/include/pj/compat/<b>m_alpha.h</b></tt>.

- *    Alternatively create a copy from other header file in this directory.

- *    The contents of this file will look something like:

- *    <pre>

- *      #define PJ_HAS_PENTIUM          0

- *      #define PJ_IS_LITTLE_ENDIAN     1

- *      #define PJ_IS_BIG_ENDIAN        0

- *    </pre>

- *  - edit <tt>pjlib/include/pj/<b>config.h</b></tt>. Add new processor

- *    configuration in this header file, like follows:

- *    <pre>

- *      ...

- *      #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0

- *      #   include <pj/compat/m_alpha.h>

- *      ...

- *    </pre>

- *  - done. Build PJLIB with:

- *    <pre>

- *      $ cd $PJPROJECT/pjlib/build

- *      $ make dep

- *      $ make clean

- *      $ make

- *    </pre>

- *

- * @section porting_os_sec Porting to New Operating System Target

- *

- * This section will try to give you rough guideline on how to

- * port PJLIB to a new target. As a sample, we give the target a name tag, 

- * for example <tt><b>xos</b></tt> (for X OS). 

- *

- * @subsection new_compat_os_h_file_sec Create New Compat Header File

- *

- * You'll need to create a new header file 

- * <b><tt>include/pj/compat/os_xos.h</tt></b>. You can copy as a 

- * template other header file and edit it accordingly.

- *

- * @subsection modify_config_h_file_sec Modify config.h

- *

- * Then modify file <b><tt>include/pj/config.h</tt></b> to include

- * this file accordingly (e.g. when macro <tt><b>PJ_XOS</b></tt> is

- * defined):

- *

- \verbatim

- ...

- #elif defined(PJ_XOS)

- #  include <pj/compat/os_xos.h>

- #else

- #...

- \endverbatim

- * 

- * @subsection new_target_mak_file_sec Create New Global Make Config File

- *

- * Then you'll need to create global configuration file that

- * is specific for this OS, i.e. <tt><b>os-xos.mak</b></tt> in 

- * <tt><b>$PJPROJECT/build</b></tt> directory.

- *

- * At very minimum, the file will normally need to define

- * <tt><b>PJ_XOS=1</b></tt> in the \c CFLAGS section:

- *

- \verbatim

-#

-# $PJPROJECT/build/os-xos.mak:

-#

-export OS_CFLAGS   := $(CC_DEF)PJ_XOS=1

-export OS_CXXFLAGS := 

-export OS_LDFLAGS  :=

-export OS_SOURCES  := 

- \endverbatim

- *

- *

- * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File

- *

- * Then you'll need to create xos-specific configuration file

- * for PJLIB. This file is also named <tt><b>os-xos.mak</b></tt>,

- * but its located in <tt><b>pjlib/build</b></tt> directory.

- * This file will specify source files that are specific to

- * this OS to be included in the build process.

- *

- * Below is a sample:

- \verbatim

-#

-# pjlib/build/os-xos.mak:

-#  XOS specific configuration for PJLIB.

-#

-export PJLIB_OBJS += 	os_core_xos.o \

-                        os_error_unix.o \

-                        os_time_ansi.o

-export TEST_OBJS +=	main.o

-export TARGETS	    =	pjlib pjlib-test

- \endverbatim

- *

- * @subsection new_target_src_sec Create and Edit Source Files

- *

- * You'll normally need to create at least these files:

- *  - <tt><b>os_core_xos.c</b></tt>: core OS specific

- *    functionality.

- *  - <tt><b>os_timestamp_xos.c</b></tt>: how to get timestamp

- *    in this OS.

- *

- * Depending on how things are done in your OS, you may need

- * to create these files:

- *  - <tt><b>os_error_*.c</b></tt>: how to manipulate

- *    OS error codes. Alternatively you may use existing

- *    <tt>os_error_unix.c</tt> if the OS has \c errno and

- *    \c strerror() function.

- *  - <tt><b>ioqueue_*.c</b></tt>: if the OS has specific method

- *    to perform asynchronous I/O. Alternatively you may

- *    use existing <tt>ioqueue_select.c</tt> if the OS supports

- *    \c select() function call.

- *  - <tt><b>sock_*.c</b></tt>: if the OS has specific method

- *    to perform socket communication. Alternatively you may

- *    use existing <tt>sock_bsd.c</tt> if the OS supports

- *    BSD socket API, and edit <tt>include/pj/compat/socket.h</tt>

- *    file accordingly.

- *

- * You will also need to check various files in 

- * <tt><b>include/pj/compat/*.h</b></tt>, to see if they're 

- * compatible with your OS.

- *

- * @subsection new_target_build_file_sec Build The Project

- *

- * After basic building blocks have been created for the OS, then

- * the easiest way to see which parts need to be fixed is by building

- * the project and see the error messages.

- *

- * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File

- *

- * When you encounter compatibility errors in PJLIB during porting,

- * you have three options on how to fix the error:

- *  - edit the existing <tt>*.c</tt> file, and give it <tt>#ifdef</tt>

- *    switch for the new OS, or

- *  - edit <tt>include/pj/compat/*.h</tt> instead, or

- *  - create a totally new file.

- *

- * Basicly there is no strict rule on which approach is the best

- * to use, however the following guidelines may be used:

- *  - if the file is expected to be completely different than

- *    any existing file, then perhaps you should create a completely

- *    new file. For example, file <tt>os_core_xxx.c</tt> will 

- *    normally be different for each OS flavour.

- *  - if the difference can be localized in <tt>include/compat</tt>

- *    header file, and existing <tt>#ifdef</tt> switch is there,

- *    then preferably you should edit this <tt>include/compat</tt>

- *    header file.

- *  - if the existing <tt>*.c</tt> file has <tt>#ifdef</tt> switch,

- *    then you may add another <tt>#elif</tt> switch there. This

- *    normally is used for behaviors that are not totally

- *    different on each platform.

- *  - other than that above, use your own judgement on whether

- *    to edit the file or create new file etc.

- */

-

-#endif	/* __PJ_DOXYGEN_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_DOXYGEN_H__
+#define __PJ_DOXYGEN_H__
+
+/**
+ * @file doxygen.h
+ * @brief Doxygen's mainpage.
+ */
+
+/*////////////////////////////////////////////////////////////////////////// */
+/*
+	INTRODUCTION PAGE
+ */
+
+/**
+ * @mainpage Welcome to PJLIB!
+ *
+ * @section intro_sec What is PJLIB
+ *
+ * PJLIB is a small foundation library written in C for making scalable 
+ * applications. Because of its small footprint, it can be used in embedded 
+ * applications (we hope so!), but yet the library is also aimed for 
+ * facilitating high performance protocol stacks.
+ *
+ * PJLIB is released under LGPL terms.
+ *
+ * @section download_sec Download
+ *
+ * PJLIB and all documentation can be downloaded from 
+ * http://www.pjproject.net.
+ *
+ *
+ * @section how_to_use_sec About This Documentation
+ *
+ * This document is generated directly from PJLIB source file using
+ * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!) 
+ * tools for generating such documentation.
+ *
+ * @subsection doc_ver_subsec Version
+ *
+ * This document corresponds to PJLIB version 0.3-pre2.
+ *
+ *
+ * @subsection find_samples_subsec How to Read This Document
+ *
+ * This documentation is laid out more to be a reference guide instead
+ * of tutorial, therefore first time users may find it difficult to
+ * grasp PJLIB by reading this document alone.
+ *
+ * However, we've tried our best to make this document easy to follow.
+ * For first time users, we would suggest that you follow these steps
+ * when reading this documentation:
+ *
+ *  - continue reading this introduction chapter. At the end of this
+ *    chapter, you'll find section called \ref pjlib_fundamentals_sec
+ *    which should guide you to understand basic things about PJLIB.
+ *
+ *  - find information about specific features that you want to use
+ *    in PJLIB. Use the <b>Module Index</b> to find out about all 
+ *    features in PJLIB (if you're browsing the HTML documentation,
+ *    click on the \a Module link on top of the page, or if you're
+ *    reading the PDF documentation, click on \a Module \a Documentation
+ *    on the navigation pane on the left).
+ *
+ * @subsection doc_organize_sec How To's
+ *
+ * Please find below links to specific tasks that you probably
+ * want to do:
+ *
+ *  - <b>How to Build PJLIB</b>
+ *\n
+ * Please refer to \ref pjlib_build_sys_pg page for more information.
+ *
+ *  - <b>How to Use PJLIB in My Application</b>
+ *\n
+ * Please refer to \ref configure_app_sec for more information.
+ *
+ *  - <b>How to Port PJLIB</b>
+ *\n
+ * Please refer to \ref porting_pjlib_pg page.
+ *
+ *  - <b>Where to Read Samples Documentation</b>
+ *\n
+ * Most of the modules provide link to the corresponding sample file.
+ * Alternatively, to get the list of all examples, you can click on 
+ * <b>Related Pages</b> on the top of HTML document or on 
+ * <b>PJLIB Page Documentation</b> on navigation pane of your PDF reader.
+ *
+ *  - <b>How to Submit Code to PJLIB Project</b>
+ *\n
+ * Please read \ref pjlib_coding_convention_page before submitting
+ * your code. Send your code as patch against current Subversion tree
+ * to the appropriate mailing list.
+ *
+ *
+ * @section features_sec Features
+ *
+ * @subsection open_source_feat It's Open Source!
+ *
+ * PJLIB is currently released on LGPL license. We may release PJLIB under
+ * additional schemes in the future (such as GPL or MPL) to incorporate
+ * linking with specific application, however, one thing for sure is
+ * we will NEVER be able to make PJLIB a proprietary software.
+ *
+ * @subsection extreme_portable_feat Extreme Portability
+ *
+ * PJLIB is designed to be extremely portable. It can run on any kind
+ * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single
+ * or multi-processors) and operating systems. Floating point or no
+ * floating point. Multi-threading or not.
+ * It can even run in environment where no ANSI LIBC is available. 
+ *
+ * Currently PJLIB is being ported to:
+ *  - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw).
+ *  - x86, Linux (user mode and as <b>kernel module</b>(!)).
+ *  - alpha, Linux
+ * And coming up:
+ *  - x86, eCos
+ *  - ultra-II, Solaris.
+ *  - powerpc, MacOS
+ *  - m68k, PalmOS.
+ *  - arm, PocketPC
+ *
+ * No other library is known to have this extreme portability!
+ *
+ * @subsection small_size_feat Small in Size
+ *
+ * One of the primary objectives is to have library that is small in size for
+ * typical embedded applications. As a rough guidance, we aim to keep the 
+ * library size below 100KB for it to be considered as small.
+ * As the result, most of the functionalities in the library can be tailored
+ * to meet the requirements; user can enable/disable specific functionalities
+ * to get the desired size/performance/functionality balance.
+ *
+ * For more info, please see @ref pj_config.
+ *
+ * @subsection no_dyn_mem No Dynamic Memory Allocations
+ *
+ * The central idea of PJLIB is that for applications to run as fast as it can,
+ * it should not use \a malloc() at all, but instead should get the memory 
+ * from a preallocated storage pool. There are few things that can be 
+ * optimized with this approach:
+ *
+ *  - \a alloc() is a O(1) operation.
+ *  - no mutex is used inside alloc(). It is assumed that synchronization 
+ *    will be used in higher abstraction by application anyway.
+ *  - no \a free() is required. All chunks will be deleted when the pool is 
+ *    destroyed.
+ *
+ * The performance gained on some systems can be as high as 10x speed up
+ * against \a malloc() and \a free().
+ *
+ * For more information, see \ref PJ_POOL_GROUP
+ *
+ * 
+ * @subsection os_abstract_feat Operating System Abstraction
+ *
+ * PJLIB has abstractions for features that are normally not portable 
+ * across operating systems: 
+ *  - @ref PJ_THREAD
+ *\n
+ *    Portable thread manipulation.
+ *  - @ref PJ_TLS
+ *\n
+ *    Storing data in thread's private data.
+ *  - @ref PJ_MUTEX
+ *\n
+ *    Mutual exclusion protection.
+ *  - @ref PJ_SEM
+ *\n
+ *    Semaphores.
+ *  - @ref PJ_ATOMIC
+ *\n
+ *    Atomic variables and their operations.
+ *  - @ref PJ_CRIT_SEC
+ *\n
+ *    Fast locking of critical sections.
+ *  - @ref PJ_LOCK
+ *\n
+ *    High level abstraction for lock objects.
+ *  - @ref PJ_EVENT
+ *\n
+ *    Event object.
+ *  - @ref PJ_TIME
+ *\n
+ *    Portable time manipulation.
+ *  - @ref PJ_TIMESTAMP
+ *\n
+ *    High resolution time value.
+ *  - etc.
+ *
+ *
+ * @subsection ll_network_io_sec Low-Level Network I/O
+ *
+ * PJLIB has very portable abstraction and fairly complete set of API for
+ * doing network I/O communications. At the lowest level, PJLIB provides:
+ *
+ *  - @ref PJ_SOCK
+ *\n
+ *    A highly portable socket abstraction, runs on all kind of
+ *    network APIs such as standard BSD socket, Windows socket, Linux
+ *    \b kernel socket, PalmOS networking API, etc.
+ *
+ *  - @ref pj_addr_resolve
+ *\n
+ *    Portable address resolution, which implements #pj_gethostbyname().
+ *
+ *  - @ref PJ_SOCK_SELECT
+ *\n
+ *    A portable \a select() like API (#pj_sock_select()) which can be
+ *    implemented with various back-end.
+ *
+ *
+ * @subsection hl_network_io_sec High-Level Network I/O
+ *
+ * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE, 
+ * which promotes creating high performance network
+ * applications by managing asynchronous I/O. This is a passive framework
+ * that utilizes the most effective way to manage asynchronous I/O
+ * on a given platform, such as:
+ *  - IoCompletionPort on WinNT,
+ *  - on Linux it can use either /dev/epoll or aio.
+ *  - or to fall back to use @a select()
+ *
+ * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which
+ * combines asynchronous I/O with timer management and thread management 
+ * to fasilitate creating trully high performance, event driven
+ * application.
+ * 
+ *
+ * @subsection timer_mgmt_sec Timer Management
+ *
+ * A passive framework for managing timer, see @ref PJ_TIMER for more info.
+ * There is also function to retrieve high resolution timestamp
+ * from the system (see @ref PJ_TIMESTAMP).
+ *
+ *
+ * @subsection data_struct_sec Various Data Structures
+ *
+ * Various data structures are provided in the library:
+ *
+ *  - @ref PJ_PSTR
+ *  - @ref PJ_ARRAY
+ *  - @ref PJ_HASH
+ *  - @ref PJ_LIST
+ *  - @ref PJ_RBTREE
+ *
+ *
+ * @subsection exception_sec Exception Construct
+ *
+ * A convenient TRY/CATCH like construct to propagate errors, which by
+ * default are used by the @ref PJ_POOL_GROUP "memory pool" and 
+ * the lexical scanner in pjlib-util. The exception
+ * construct can be used to write programs like below:
+ *
+ * <pre>
+ *    #define SYNTAX_ERROR  1
+ *
+ *    PJ_TRY {
+ *       msg = NULL;
+ *       msg = parse_msg(buf, len);
+ *    }
+ *    PJ_CATCH ( SYNTAX_ERROR ) {
+ *       .. handle error ..
+ *    }
+ *    PJ_END;
+ * </pre>
+ *
+ * Please see @ref PJ_EXCEPT for more information.
+ *
+ *
+ * @subsection logging_sec Logging Facility
+ *
+ * PJLIB @ref PJ_LOG consists of macros to write logging information to
+ * some output device. Some of the features of the logging facility:
+ *
+ *  - the verbosity can be fine-tuned both at compile time (to control
+ *    the library size) or run-time (to control the verbosity of the
+ *    information).
+ *  - output device is configurable (e.g. stdout, printk, file, etc.)
+ *  - log decoration is configurable.
+ *
+ * See @ref PJ_LOG for more information.
+ *
+ *
+ * @subsection guid_gen_sec Random and GUID Generation
+ *
+ * PJLIB provides facility to create random string 
+ * (#pj_create_random_string()) or globally unique identifier
+ * (see @ref PJ_GUID).
+ *
+ *
+ *
+ * @section configure_app_sec Configuring Application to use PJLIB
+ *
+ * @subsection pjlib_compil_sec Building PJLIB
+ *
+ * Follow the instructions in \ref pjlib_build_sys_pg to build
+ * PJLIB.
+ *
+ * @subsection pjlib_compil_app_sec Building Applications with PJLIB
+ *
+ * Use the following settings when building applications with PJLIB.
+ *
+ * @subsubsection compil_inc_dir_sec Include Search Path
+ *
+ * Add this to your include search path ($PJLIB is PJLIB root directory):
+ * <pre>
+ *   $PJLIB/include
+ * </pre>
+ *
+ * @subsubsection compil_inc_file_sec Include PJLIB Header
+ *
+ * To include all PJLIB headers:
+ * \verbatim
+    #include <pjlib.h>
+   \endverbatim
+ *
+ * Alternatively, you can include individual PJLIB headers like this:
+ * \verbatim
+     #include <pj/log.h>
+     #include <pj/os.h>
+  \endverbatim
+ *
+ *
+ * @subsubsection compil_lib_dir_sec Library Path
+ *
+ * Add this to your library search path:
+ * <pre>
+ *   $PJLIB/lib
+ * </pre>
+ *
+ * Then add the appropriate PJLIB library to your link specification. For
+ * example, you would add \c libpj-i386-linux-gcc.a when you're building
+ * applications in Linux.
+ *
+ *
+ * @subsection pjlib_fundamentals_sec Principles in Using PJLIB
+ *
+ * Few things that you \b MUST do when using PJLIB, to make sure that
+ * you create trully portable applications.
+ *
+ * @subsubsection call_pjlib_init_sec Call pj_init()
+ *
+ * Before you do anything else, call \c pj_init(). This would make sure that
+ * PJLIB system is properly set up.
+ *
+ * @subsubsection no_ansi_subsec Do NOT Use ANSI C
+ *
+ * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable
+ * library in the world, nor it's the most ubiquitous. For example, LIBC
+ * is not available in Linux kernel. Also normally LIBC will be excluded
+ * from compilation of RTOSes to reduce size.
+ *
+ * So for maximum portability, do NOT use ANSI C. Do not even try to include
+ * any other header files outside <include/pj>. Stick with the functionalities
+ * provided by PJLIB. 
+ *
+ *
+ * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings
+ *
+ * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this
+ * convention too. Remember, ANSI string-h is not always available. And
+ * PJLIB string is faster!
+ *
+ * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations
+ *
+ * You MUST NOT use \a malloc() or any other memory allocation functions.
+ * Use PJLIB pool instead! It's faster and most portable.
+ *
+ * @subsection logging_subsubsec Use Logging for Text Display
+ *
+ * DO NOT use <stdio.h> for text output. Use PJLIB logging instead.
+ *
+ *
+ * @section porting_pjlib_sec0 Porting PJLIB
+ *
+ * Please see \ref porting_pjlib_pg page on more information to port
+ * PJLIB to new target.
+ *
+ * @section enjoy_sec Enjoy Using PJLIB!
+ *
+ * We hope that you find PJLIB usefull for your application. If you
+ * have any questions, suggestions, critics, bug fixes, or anything
+ * else, we would be happy to hear it.
+ *
+ * Enjoy using PJLIB!
+ *
+ * Benny Prijono < bennylp at pjproject dot net >
+ */
+
+
+
+/*////////////////////////////////////////////////////////////////////////// */
+/*
+         CODING CONVENTION
+ */
+
+/**
+ * @page pjlib_coding_convention_page Coding Convention
+ *
+ * Before you submit your code/patches to be included with PJLIB, you must
+ * make sure that your code is compliant with PJLIB coding convention.
+ * <b>This is very important!</b> Otherwise we would not accept your code.
+ *
+ * @section coding_conv_editor_sec Editor Settings
+ *
+ * The single most important thing in the whole coding convention is editor 
+ * settings. It's more important than the correctness of your code (bugs will
+ * only crash the system, but incorrect tab size is mental!).
+ *
+ * Kindly set your editor as follows:
+ *  - tab size to \b 8.
+ *  - indentation to \b 4.
+ *
+ * With \c vi, you can do it with:
+ * <pre>
+ *  :se ts=8
+ *  :se sts=4
+ * </pre>
+ *
+ * You should replace tab with eight spaces.
+ *
+ * @section coding_conv_detail_sec Coding Style
+ *
+ * Coding style MUST strictly follow K&R style. The rest of coding style
+ * must follow current style. You SHOULD be able to observe the style
+ * currently used by PJLIB from PJLIB sources, and apply the style to your 
+ * code. If you're not able to do simple thing like to observe PJLIB
+ * coding style from the sources, then logic dictates that your ability to
+ * observe more difficult area in PJLIB such as memory allocation strategy, 
+ * concurrency, etc is questionable.
+ *
+ * @section coding_conv_comment_sec Commenting Your Code
+ *
+ * Public API (e.g. in header files) MUST have doxygen compliant comments.
+ *
+ */
+
+
+/*////////////////////////////////////////////////////////////////////////// */
+/*
+	BUILDING AND INSTALLING PJLIB
+ */
+
+
+
+/**
+ * @page pjlib_build_sys_pg Building, and Installing PJLIB
+ *
+ * @section build_sys_install_sec Build and Installation
+ *
+ * @subsection build_sys_install_win32_sec Visual Studio
+ *
+ * The PJLIB Visual Studio workspace supports the building of PJLIB
+ * for Win32 target. Although currently only the Visual Studio 6 Workspace is
+ * actively maintained, developers with later version of Visual Studio
+ * can easily imports VS6 workspace into their IDE.
+ *
+ * To start building PJLIB projects with Visual Studio 6 or later, open
+ * the \a workspace file in the corresponding \b \c build directory. You have
+ * several choices on which \a dsw file to open:
+ \verbatim
+ $PJPROJECT/build/pjproject.dsw
+ $PJPROJECT/pjlib/build/pjlib.dsw
+ $PJPROJECT/pjsip/build/pjsip.dsw
+ ..etc
+ \endverbatim
+ *
+ * The easiest way is to open <tt>pjproject.dsw</tt> file in \b \c $PJPROJECT/build
+ * directory. However this will only build the required projects, not
+ * the complete projects. For example, the PJLIB test and samples projects 
+ * are not included in this workspace. To build the complete projects, you must
+ * open and build each \a dsw file in \c build directory in each
+ * subprojects. For example, to open the complete PJLIB workspace, open
+ * <tt>pjlib.dsw</tt> in <tt>$PJPROJECT/pjlib/build</tt> directory.
+ *
+ *
+ * @subsubsection config_site_create_vc_sec Create config_site.h
+ *
+ * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>
+ * is supposed to contain configuration that is specific to your site/target.
+ * This file is not part of PJLIB, so you must create it yourself. Normally
+ * you just need to create a blank file.
+ *
+ * The reason why it's not included in PJLIB is so that you would not accidently
+ * overwrite your site configuration.
+ *
+ * If you fail to do this, Visual C will complain with error like: 
+ *
+ * <b>"fatal error C1083: Cannot open include file: 'pj/config_site.h': No such file 
+ * or directory"</b>.
+ *
+ * @subsubsection build_vc_subsubsec Build the Projects
+ *
+ * Just hit the build button!
+ *
+ *
+ * @subsection build_sys_install_unix_sec Make System
+ *
+ * For other targets, PJLIB provides a rather comprehensive build system
+ * that uses GNU \a make (and only GNU \a make will work). 
+ * Currently, the build system supports building * PJLIB for these targets:
+ *  - i386/Win32/mingw
+ *  - i386/Linux
+ *  - i386/Linux (kernel)
+ *  - alpha/linux
+ *  - sparc/SunOS
+ *  - etc..
+ *
+ *
+ * @subsubsection build_req_sec Requirements
+ *
+ * In order to use the \c make based build system, you MUST have:
+ *
+ *  - <b>GNU make</b>
+ *\n
+ *    The Makefiles heavily utilize GNU make commands which most likely
+ *    are not available in other \c make system.
+ *  - <b>bash</b> shell is recommended.
+ *\n
+ *    Specificly, there is a command <tt>"echo -n"</tt> which may not work
+ *    in other shells. This command is used when generating dependencies
+ *    (<tt>make dep</tt>) and it's located in 
+ *    <tt>$PJPROJECT/build/rules.mak</tt>.
+ *  - <b>ar</b>, <b>ranlib</b> from GNU binutils
+ *\n
+ *    In your system has different <tt>ar</tt> or <tt>ranlib</tt> (e.g. they
+ *    may have been installed as <tt>gar</tt> and <tt>granlib</tt>), then
+ *    either you create the relevant symbolic links, <b>or</b> modify
+ *    <tt>$PJPROJECT/build/cc-gcc.mak</tt> and rename <tt>ar</tt> and
+ *    <tt>ranlib</tt> to the appropriate names.
+ *  - <b>gcc</b> to generate dependency.
+ *\n
+ *    Currently the build system uses <tt>"gcc -MM"</tt> to generate build
+ *    dependencies. If <tt>gcc</tt> is not desired to generate dependency,
+ *    then either you don't run <tt>make dep</tt>, <b>or</b> edit
+ *    <tt>$PJPROJECT/build/rules.mak</tt> to calculate dependency using
+ *    your prefered method. (And let me know when you do so so that I can
+ *    update the file. :) )
+ *
+ * @subsubsection build_overview_sec Building the Project
+ *
+ * Generally, steps required to build the PJLIB are:
+ *
+ \verbatim
+   $ cd /home/user/pjproject         # <-- go to $PJPROJECT
+   $ vi build.mak                    # <-- set build target etc
+   $ touch pjlib/include/pj/config_site.h
+   $ cd pjlib/build                  # <-- go to projet's build dir
+   $ make                            # <-- build the project
+ \endverbatim
+ *
+ * For other project, \a cd to <tt>build</tt> directory in the project
+ * and execute \a make from there.
+ *
+ * \note For Linux kernel target, there are additional steps required, which
+ * will be explained in section \ref linux_kern_target_subsec.
+ *
+ * @subsubsection build_mak_sec Editing build.mak
+ * 
+ * The \c build.mak file in \c $PJPROJECT root directory is used to
+ * specify the build configuration. This file is expected to export
+ * the following \a make variables:
+ *
+ *  - <tt><b>MACHINE_NAME</b></tt>
+ *\n
+ *    Target machine/processor, one of: <b>{ i386 | alpha | sparc }</b>.
+ *
+ *  - <tt><b>OS_NAME</b></tt>
+ *\n
+ *    Target operating system, one of: <b>{ win32 | linux | 
+ *      linux-kernel | sunos }</b>.
+ *
+ *  - <tt><b>CC_NAME</b></tt>
+ *\n
+ *    Compiler name: <b>{ gcc | vc }</b>\n
+ *    (Note that support for Visual C (vc) compiler with the \c make system is
+ *    experimental, and it will only work when run inside a DOS shell
+ *    (i.e. <tt>"HOST_NAME=win32"</tt>)).
+ *
+ *  - <tt><b>HOST_NAME</b></tt>
+ *\n
+ *    Build host: <b>{ unix | mingw | win32 }</b>\n
+ *    (Note: win32 host means a DOS command prompt. Support for this type
+ *    of development host is experimental).
+ *
+ * These variables will cause the correct configuration file in 
+ * \c $PJPROJECT/build directory to be executed by \a make. For 
+ * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak
+ * in \c build directory to be executed. These files contain specific
+ * configuration for the option that is selected.
+ *
+ * For Linux kernel target, you are also required to declare the following
+ * variables in this file:
+ *	- \c KERNEL_DIR: full path of kernel source tree.
+ *	- \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank
+ * 	     for default.
+ *	- \c PJPROJECT_DIR: full path of PJPROJECT source tree.
+ *
+ * Apart from these, there are also additional steps required to build
+ * Linux kernel target, which will be explained in \ref linux_kern_target_subsec.
+ *
+ * @subsubsection build_dir_sec Files in "build" Directory
+ *
+ * The <tt>*.mak</tt> files in \c $PJPROJECT/build directory are used to specify
+ * the configuration for the specified compiler, target machine target 
+ * operating system, and host options. These files will be executed
+ * (included) by \a make during building process, depending on the values
+ * specified in <b>$PJPROJECT/build.mak</b> file.
+ *
+ * Normally you don't need to edit these files, except when you're porting
+ * PJLIB to new target.
+ *
+ * Below are the description of some files in this directory:
+ *
+ *  - <tt>rules.mak</tt>: contains generic rules always included during make.
+ *  - <tt>cc-gcc.mak</tt>: rules when gcc is used for compiler.
+ *  - <tt>cc-vc.mak</tt>: rules when MSVC compiler is used.
+ *  - <tt>host-mingw.mak</tt>: rules for building in mingw host.
+ *  - <tt>host-unix.mak</tt>: rules for building in Unix/Posix host.
+ *  - <tt>host-win32.mak</tt>: rules for building in Win32 command console
+ *    (only valid when VC is used).
+ *  - <tt>m-i386.mak</tt>: rules when target machine is an i386 processor.
+ *  - <tt>m-m68k.mak</tt>: rules when target machine is an m68k processor.
+ *  - <tt>os-linux.mak</tt>: rules when target OS is Linux.
+ *  - <tt>os-linux-kernel.mak</tt>: rules when PJLIB is to be build as
+ *    part of Linux kernel.
+ *  - <tt>os-win32.mak</tt>: rules when target OS is Win32.
+ *
+ *
+ * @subsubsection config_site_create_sec Create config_site.h
+ *
+ * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>
+ * is supposed to contain configuration that is specific to your site/target.
+ * This file is not part of PJLIB, so you must create it yourself.
+ *
+ * The reason why it's not included in PJLIB is so that you would not accidently
+ * overwrite your site configuration.
+ *
+ *
+ * @subsubsection invoking_make_sec Invoking make
+ *
+ * Normally, \a make is invoked in \c build directory under each project.
+ * For example, to build PJLIB, you would invoke \a make in
+ * \c $PJPROJECT/pjlib/build directory like below:
+ *
+ \verbatim
+   $ cd pjlib/build
+   $ make
+ \endverbatim
+ *
+ * Alternatively you may invoke <tt>make</tt> in <tt>$PJPROJECT</tt> 
+ * directory, to build all projects under that directory (e.g. 
+ * PJLIB, PJSIP, etc.).
+ *
+ *
+ * @subsubsection linux_kern_target_subsec Linux Kernel Target
+ *
+ * \note
+ * <b>BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS.
+ * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB
+ * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION
+ * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE.
+ * YOU HAVE BEEN WARNED.</b>
+ *
+ * \note
+ * <b>User Mode Linux (UML)</b> provides excellent way to experiment with Linux
+ * kernel without risking the stability of the host system. See
+ * http://user-mode-linux.sourceforge.net for details.
+ *
+ * \note
+ * I only use <b>UML</b> to experiment with PJLIB kernel modules.
+ * <b>I wouldn't be so foolish to use my host Linux machine to experiment
+ * with this.</b> 
+ *
+ * \note
+ * You have been warned.
+ *
+ * For building PJLIB for Linux kernel target, there are additional steps required.
+ * In general, the additional tasks are:
+ *	- Declare some more variables in <b><tt>build.mak</tt></b> file (this
+ *        has been explained in \ref build_mak_sec above).
+ *      - Perform these two small modifications in kernel source tree.
+ *
+ * There are two small modification need to be applied to the kernel tree.
+ *
+ * <b>1. Edit <tt>Makefile</tt> in kernel root source tree.</b>
+ *
+ * Add the following lines at the end of the <tt>Makefile</tt> in your 
+ * <tt>$KERNEL_SRC</tt> dir:
+ \verbatim
+script:
+       $(SCRIPT)
+ \endverbatim
+ *
+ * \note Remember to replace spaces with <b>tab</b> in the Makefile.
+ *
+ * The modification above is needed to capture kernel's \c $CFLAGS and 
+ * \c $CFLAGS_MODULE which will be used for PJLIB's compilation.
+ *
+ * <b>2. Add Additional Exports.</b>
+ *
+ * We need the kernel to export some more symbols for our use. So we declare
+ * the additional symbols to be exported in <tt>extra-exports.c</tt> file, and add
+ * a this file to be compiled into the kernel:
+ *
+ *	- Copy the file <tt>extra-exports.c</tt> from <tt>pjlib/src/pj</tt> 
+ *	  directory to <tt>$KERNEL_SRC/kernel/</tt> directory.
+ *	- Edit <tt>Makefile</tt> in that directory, and add this line
+ *        somewhere after the declaration of that variable:
+ \verbatim
+obj-y   += extra-exports.o
+ \endverbatim
+ *
+ * To illustrate what have been done in your kernel source tree, below
+ * is screenshot of my kernel source tree _after_ the modification.
+ *
+ \verbatim
+[root@vpc-linux linux-2.6.7]# pwd
+/usr/src/linux-2.6.7
+[root@vpc-linux linux-2.6.7]# 
+[root@vpc-linux linux-2.6.7]# 
+[root@vpc-linux linux-2.6.7]# tail Makefile 
+
+endif   # skip-makefile
+
+FORCE:
+
+.PHONY: script
+
+script:
+        $(SCRIPT)
+
+[root@vpc-linux linux-2.6.7]# 
+[root@vpc-linux linux-2.6.7]# 
+[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c 
+#include <linux/module.h>
+#include <linux/syscalls.h>
+
+EXPORT_SYMBOL(sys_select);
+
+EXPORT_SYMBOL(sys_epoll_create);
+EXPORT_SYMBOL(sys_epoll_ctl);
+EXPORT_SYMBOL(sys_epoll_wait);
+
+EXPORT_SYMBOL(sys_socket);
+[root@vpc-linux linux-2.6.7]# 
+[root@vpc-linux linux-2.6.7]# 
+[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile 
+#
+# Makefile for the linux kernel.
+#
+
+obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
+            exit.o itimer.o time.o softirq.o resource.o \
+            sysctl.o capability.o ptrace.o timer.o user.o \
+            signal.o sys.o kmod.o workqueue.o pid.o \
+            rcupdate.o intermodule.o extable.o params.o posix-timers.o \
+            kthread.o
+
+obj-y   +=  extra-exports.o
+
+obj-$(CONFIG_FUTEX) += futex.o
+obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
+[root@vpc-linux linux-2.6.7]# 
+
+ \endverbatim
+ *
+ * Then you must rebuild the kernel.
+ * If you fail to do this, you won't be able to <b>insmod</b> pjlib.
+ *
+ * \note You will see a lots of warning messages during pjlib-test compilation.
+ * The warning messages complain about unresolved symbols which are defined
+ * in pjlib module. You can safely ignore these warnings. However, you can not
+ * ignore warnings about non-pjlib unresolved symbols.
+ *
+ * 
+ * @subsection makefile_explained_sec Makefile Explained
+ *
+ * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be
+ * very similar in the contents. The Makefile is located under \c build
+ * directory in each project subdir.
+ *
+ * @subsubsection pjlib_makefile_subsec PJLIB Makefile.
+ *
+ * Below is PJLIB's Makefile:
+ *
+ * \include build/Makefile
+ *
+ * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak.
+ *
+ * Below is file <tt><b>os-linux.mak</b></tt> file in 
+ * <tt>$PJPROJECT/pjlib/build</tt> directory,
+ * which is OS specific configuration file for Linux target that is specific 
+ * for PJLIB project. For \b global OS specific configuration, please see
+ * <tt>$PJPROJECT/build/os-*.mak</tt>.
+ *
+ * \include build/os-linux.mak
+ *
+ */
+
+
+/*////////////////////////////////////////////////////////////////////////// */
+/*
+         PORTING PJLIB
+ */
+
+
+
+/**
+ * @page porting_pjlib_pg Porting PJLIB
+ *
+ *
+ * @section new_arch_sec Porting to New CPU Architecture
+ *
+ * Below is step-by-step guide to add support for new CPU architecture.
+ * This sample is based on porting to Alpha architecture; however steps for 
+ * porting to other CPU architectures should be pretty similar. 
+ *
+ * Also note that in this example, the operating system used is <b>Linux</b>.
+ * Should you wish to add support for new operating system, then follow
+ * the next section \ref porting_os_sec.
+ *
+ * Step-by-step guide to port to new CPU architecture:
+ *  - decide the name for the new architecture. In this case, we choose
+ *    <tt><b>alpha</b></tt>.
+ *  - edit file <tt>$PJPROJECT/build.mak</tt>, and add new section for
+ *    the new target:
+ *    <pre>
+ *      #
+ *      # Linux alpha, gcc
+ *      #
+ *      export MACHINE_NAME := <b>alpha</b>
+ *      export OS_NAME := linux
+ *      export CC_NAME := gcc
+ *      export HOST_NAME := unix
+ *    </pre>
+ *
+ *  - create a new file <tt>$PJPROJECT/build/<b>m-alpha</b>.mak</tt>.
+ *    Alternatively create a copy from other file in this directory.
+ *    The contents of this file will look something like:
+ *    <pre>
+ *      export M_CFLAGS := $(CC_DEF)<b>PJ_M_ALPHA=1</b>
+ *      export M_CXXFLAGS :=
+ *      export M_LDFLAGS :=
+ *      export M_SOURCES :=
+ *    </pre>
+ *  - create a new file <tt>$PJPROJECT/pjlib/include/pj/compat/<b>m_alpha.h</b></tt>.
+ *    Alternatively create a copy from other header file in this directory.
+ *    The contents of this file will look something like:
+ *    <pre>
+ *      #define PJ_HAS_PENTIUM          0
+ *      #define PJ_IS_LITTLE_ENDIAN     1
+ *      #define PJ_IS_BIG_ENDIAN        0
+ *    </pre>
+ *  - edit <tt>pjlib/include/pj/<b>config.h</b></tt>. Add new processor
+ *    configuration in this header file, like follows:
+ *    <pre>
+ *      ...
+ *      #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
+ *      #   include <pj/compat/m_alpha.h>
+ *      ...
+ *    </pre>
+ *  - done. Build PJLIB with:
+ *    <pre>
+ *      $ cd $PJPROJECT/pjlib/build
+ *      $ make dep
+ *      $ make clean
+ *      $ make
+ *    </pre>
+ *
+ * @section porting_os_sec Porting to New Operating System Target
+ *
+ * This section will try to give you rough guideline on how to
+ * port PJLIB to a new target. As a sample, we give the target a name tag, 
+ * for example <tt><b>xos</b></tt> (for X OS). 
+ *
+ * @subsection new_compat_os_h_file_sec Create New Compat Header File
+ *
+ * You'll need to create a new header file 
+ * <b><tt>include/pj/compat/os_xos.h</tt></b>. You can copy as a 
+ * template other header file and edit it accordingly.
+ *
+ * @subsection modify_config_h_file_sec Modify config.h
+ *
+ * Then modify file <b><tt>include/pj/config.h</tt></b> to include
+ * this file accordingly (e.g. when macro <tt><b>PJ_XOS</b></tt> is
+ * defined):
+ *
+ \verbatim
+ ...
+ #elif defined(PJ_XOS)
+ #  include <pj/compat/os_xos.h>
+ #else
+ #...
+ \endverbatim
+ * 
+ * @subsection new_target_mak_file_sec Create New Global Make Config File
+ *
+ * Then you'll need to create global configuration file that
+ * is specific for this OS, i.e. <tt><b>os-xos.mak</b></tt> in 
+ * <tt><b>$PJPROJECT/build</b></tt> directory.
+ *
+ * At very minimum, the file will normally need to define
+ * <tt><b>PJ_XOS=1</b></tt> in the \c CFLAGS section:
+ *
+ \verbatim
+#
+# $PJPROJECT/build/os-xos.mak:
+#
+export OS_CFLAGS   := $(CC_DEF)PJ_XOS=1
+export OS_CXXFLAGS := 
+export OS_LDFLAGS  :=
+export OS_SOURCES  := 
+ \endverbatim
+ *
+ *
+ * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File
+ *
+ * Then you'll need to create xos-specific configuration file
+ * for PJLIB. This file is also named <tt><b>os-xos.mak</b></tt>,
+ * but its located in <tt><b>pjlib/build</b></tt> directory.
+ * This file will specify source files that are specific to
+ * this OS to be included in the build process.
+ *
+ * Below is a sample:
+ \verbatim
+#
+# pjlib/build/os-xos.mak:
+#  XOS specific configuration for PJLIB.
+#
+export PJLIB_OBJS += 	os_core_xos.o \
+                        os_error_unix.o \
+                        os_time_ansi.o
+export TEST_OBJS +=	main.o
+export TARGETS	    =	pjlib pjlib-test
+ \endverbatim
+ *
+ * @subsection new_target_src_sec Create and Edit Source Files
+ *
+ * You'll normally need to create at least these files:
+ *  - <tt><b>os_core_xos.c</b></tt>: core OS specific
+ *    functionality.
+ *  - <tt><b>os_timestamp_xos.c</b></tt>: how to get timestamp
+ *    in this OS.
+ *
+ * Depending on how things are done in your OS, you may need
+ * to create these files:
+ *  - <tt><b>os_error_*.c</b></tt>: how to manipulate
+ *    OS error codes. Alternatively you may use existing
+ *    <tt>os_error_unix.c</tt> if the OS has \c errno and
+ *    \c strerror() function.
+ *  - <tt><b>ioqueue_*.c</b></tt>: if the OS has specific method
+ *    to perform asynchronous I/O. Alternatively you may
+ *    use existing <tt>ioqueue_select.c</tt> if the OS supports
+ *    \c select() function call.
+ *  - <tt><b>sock_*.c</b></tt>: if the OS has specific method
+ *    to perform socket communication. Alternatively you may
+ *    use existing <tt>sock_bsd.c</tt> if the OS supports
+ *    BSD socket API, and edit <tt>include/pj/compat/socket.h</tt>
+ *    file accordingly.
+ *
+ * You will also need to check various files in 
+ * <tt><b>include/pj/compat/*.h</b></tt>, to see if they're 
+ * compatible with your OS.
+ *
+ * @subsection new_target_build_file_sec Build The Project
+ *
+ * After basic building blocks have been created for the OS, then
+ * the easiest way to see which parts need to be fixed is by building
+ * the project and see the error messages.
+ *
+ * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File
+ *
+ * When you encounter compatibility errors in PJLIB during porting,
+ * you have three options on how to fix the error:
+ *  - edit the existing <tt>*.c</tt> file, and give it <tt>#ifdef</tt>
+ *    switch for the new OS, or
+ *  - edit <tt>include/pj/compat/*.h</tt> instead, or
+ *  - create a totally new file.
+ *
+ * Basicly there is no strict rule on which approach is the best
+ * to use, however the following guidelines may be used:
+ *  - if the file is expected to be completely different than
+ *    any existing file, then perhaps you should create a completely
+ *    new file. For example, file <tt>os_core_xxx.c</tt> will 
+ *    normally be different for each OS flavour.
+ *  - if the difference can be localized in <tt>include/compat</tt>
+ *    header file, and existing <tt>#ifdef</tt> switch is there,
+ *    then preferably you should edit this <tt>include/compat</tt>
+ *    header file.
+ *  - if the existing <tt>*.c</tt> file has <tt>#ifdef</tt> switch,
+ *    then you may add another <tt>#elif</tt> switch there. This
+ *    normally is used for behaviors that are not totally
+ *    different on each platform.
+ *  - other than that above, use your own judgement on whether
+ *    to edit the file or create new file etc.
+ */
+
+#endif	/* __PJ_DOXYGEN_H__ */
+
diff --git a/pjlib/include/pj/equeue.h b/pjlib/include/pj/equeue.h
index d0bf756..77374bd 100644
--- a/pjlib/include/pj/equeue.h
+++ b/pjlib/include/pj/equeue.h
@@ -1,336 +1,336 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_EQUEUE_H__

-#define __PJ_EQUEUE_H__

-

-/**

- * @file equeue.h

- * @brief Event Queue

- */

-#include <pj/types.h>

-

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_EQUEUE Event Queue

- * @brief Event Queue

- * @ingroup PJ_OS

- * @{

- */

-

-

-/**

- * Opaque data type for Event Queue.

- */

-typedef struct pj_equeue_t pj_equeue_t;

-

-/**

- * Opaque data type for Event Queue key.

- */

-typedef struct pj_equeue_key_t pj_equeue_key_t;

-

-

-/**

- * This structure describes the callbacks to be called when I/O operation

- * completes.

- */

-typedef struct pj_io_callback

-{

-    /**

-     * This callback is called when #pj_equeue_read, #pj_equeue_recv or 

-     * #pj_equeue_recvfrom completes.

-     *

-     * @param key	    The key.

-     * @param bytes_read    The size of data that has just been read.

-     */

-    void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read);

-

-    /**

-     * This callback is called when #pj_equeue_write, #pj_equeue_send, or

-     * #pj_equeue_sendto completes.

-     *

-     * @param key	    The key.

-     * @param bytes_read    The size of data that has just been written.

-     */

-    void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent);

-

-    /**

-     * This callback is called when #pj_equeue_accept completes.

-     *

-     * @param key	    The key.

-     * @param status	    Zero if the operation completes successfully.

-     */

-    void (*on_accept_complete)(pj_equeue_key_t *key, int status);

-

-    /**

-     * This callback is called when #pj_equeue_connect completes.

-     *

-     * @param key	    The key.

-     * @param status	    Zero if the operation completes successfully.

-     */

-    void (*on_connect_complete)(pj_equeue_key_t *key, int status);

-

-} pj_io_callback;

-

-/**

- * Event Queue options.

- */

-typedef struct pj_equeue_options

-{

-    /** Maximum number of threads that are allowed to access Event Queue

-     *  simulteneously.

-     */

-    unsigned	nb_threads;

-

-    /** If non-zero, then no mutex protection will be used. */

-    pj_bool_t	no_lock;

-

-    /** Interval of the busy loop inside the event queue.

-     *  The time resolution here determines the accuracy of the

-     *  timer in the Event Queue.

-     */

-    pj_time_val	poll_interval;

-

-} pj_equeue_options;

-

-

-/**

- * Error value returned by I/O operations to indicate that the operation

- * can't complete immediately and will complete later.

- */

-#define PJ_EQUEUE_PENDING   (-2)

-

-/**

- * Types of Event Queue operation.

- */

-typedef enum pj_equeue_op

-{

-    PJ_EQUEUE_OP_NONE		= 0,	/**< No operation.	    */

-    PJ_EQUEUE_OP_READ		= 1,	/**< read() operation.	    */

-    PJ_EQUEUE_OP_RECV_FROM	= 2,	/**< recvfrom() operation.  */

-    PJ_EQUEUE_OP_WRITE		= 4,	/**< write() operation.	    */

-    PJ_EQUEUE_OP_SEND_TO	= 8,	/**< sendto() operation.    */

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-    PJ_EQUEUE_OP_ACCEPT		= 16,	/**< accept() operation.    */

-    PJ_EQUEUE_OP_CONNECT	= 32,	/**< connect() operation.   */

-#endif	/* PJ_HAS_TCP */

-} pj_equeue_op;

-

-

-

-/**

- * Initialize Event Queue options with default values.

- *

- * @param options   Event Queue options.

- */

-PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options);

-

-/**

- * Create a new Event Queue framework.

- *

- * @param pool	    The pool to allocate the event queue structure.

- * @param options   Event queue options, or if NULL is given, then

- *		    default options will be used.

- * @param equeue    Pointer to receive event queue structure.

- *

- * @return	    zero on success.

- */

-PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool, 

-				       const pj_equeue_options *options,

-				       pj_equeue_t **equeue);

-

-/**

- * Get the first instance of Event Queue, or NULL if no Event Queue

- * instance has been created in the application.

- *

- * @return	    The first instance of Event Queue created, or NULL.

- */

-PJ_DECL(pj_equeue_t*) pj_equeue_instance(void);

-

-/**

- * Destroy the Event Queue.

- *

- * @param equeue    The Event Queue instance to be destroyed.

- */

-PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue );

-

-/**

- * Customize the lock object that is used by the Event Queue.

- *

- * @param equeue    The Event Queue instance.

- * @param lock	    The lock object.

- * @param auto_del  If non-zero, the lock will be destroyed by

- *		    Event Queue.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue,

-					 pj_lock_t *lock, 

-					 pj_bool_t auto_del);

-

-/**

- * Associate an Event Queue key to particular handle. The key is also

- * associated with the callback and user data, which will be used by

- * the Event Queue framework when signalling event back to application.

- *

- * @param pool	    To allocate the resource for the specified handle, which

- *		    must be valid until the handle/key is unregistered

- *		    from Event Queue.

- * @param equeue    The Event Queue.

- * @param hnd	    The OS handle to be registered, which can be a socket

- *		    descriptor (pj_sock_t), file descriptor, etc.

- * @param cb	    Callback to be called when I/O operation completes. 

- * @param user_data User data to be associated with the key.

- * @param key	    Pointer to receive the key.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool,

-					 pj_equeue_t *equeue,

-					 pj_oshandle_t hnd,

-					 pj_io_callback *cb,

-					 void *user_data,

-					 pj_equeue_key_t **key);

-

-/**

- * Retrieve user data associated with a key.

- *

- * @param key	    The Event Queue key.

- *

- * @return	    User data associated with the key.

- */

-PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key );

-

-

-/**

- * Unregister Event Queue key from the Event Queue.

- *

- * @param equeue    The Event Queue.

- * @param key	    The key.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue,

-					   pj_equeue_key_t *key);

-

-/**

- * Instruct the Event Queue to read from the specified handle. This function

- * returns immediately (i.e. non-blocking) regardless whether some data has 

- * been transfered. If the operation can't complete immediately, caller will 

- * be notified about the completion when it calls pj_equeue_poll().

- *

- * @param key	    The key that uniquely identifies the handle.

- * @param buffer    The buffer to hold the read data. The caller MUST make sure

- *		    that this buffer remain valid until the framework completes

- *		    reading the handle.

- * @param size	    The maximum size to be read.

- *

- * @return

- *  - zero or positive number to indicate the number of bytes has been

- *		    read, and in this case the operation was not queued.

- *  - (-1) on error, which in this case operation was not queued.

- *  - PJ_EQUEUE_PENDING if the operation has been queued.

- */

-PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key,

-				    void *buffer,

-				    pj_size_t size);

-

-/**

- * Start recv() operation on the specified handle.

- *

- * @see ::pj_ioqueue_read

- */

-PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key,

-				    void *buf,

-				    pj_size_t size,

-				    unsigned flags);

-

-/**

- * Start recvfrom() operation on the specified handle.

- *

- * @see ::pj_equeue_read

- */

-PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key,

-					void *buf,

-					pj_size_t size,

-					unsigned flags,

-					pj_sockaddr_t *addr,

-					int *addrlen );

-

-/**

- * Write.

- */

-PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key,

-				     const void *buf,

-				     pj_size_t size);

-

-/**

- * Send.

- */

-PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key,

-				    const void *buf,

-				    pj_size_t size,

-				    unsigned flags);

-

-/**

- * Sendto.

- */

-PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key,

-				      const void *buf,

-				      pj_size_t size,

-				      unsigned flags,

-				      const pj_sockaddr_t *addr,

-				      int addrlen);

-

-/**

- * Schedule timer.

- */

-PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue,

-					       const pj_time_val *timeout,

-					       pj_timer_entry *entry);

-

-/**

- * Cancel timer.

- */

-PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue,

-					     pj_timer_entry *entry);

-

-/**

- * Poll for events.

- */

-PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue,

-				     const pj_time_val *timeout );

-

-/**

- * Run.

- */

-PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue );

-

-/**

- * Stop all running threads.

- */

-PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue );

-

-

-/** @} */

-

-PJ_END_DECL

-

-#endif	/* __PJ_EQUEUE_H__ */

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_EQUEUE_H__
+#define __PJ_EQUEUE_H__
+
+/**
+ * @file equeue.h
+ * @brief Event Queue
+ */
+#include <pj/types.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_EQUEUE Event Queue
+ * @brief Event Queue
+ * @ingroup PJ_OS
+ * @{
+ */
+
+
+/**
+ * Opaque data type for Event Queue.
+ */
+typedef struct pj_equeue_t pj_equeue_t;
+
+/**
+ * Opaque data type for Event Queue key.
+ */
+typedef struct pj_equeue_key_t pj_equeue_key_t;
+
+
+/**
+ * This structure describes the callbacks to be called when I/O operation
+ * completes.
+ */
+typedef struct pj_io_callback
+{
+    /**
+     * This callback is called when #pj_equeue_read, #pj_equeue_recv or 
+     * #pj_equeue_recvfrom completes.
+     *
+     * @param key	    The key.
+     * @param bytes_read    The size of data that has just been read.
+     */
+    void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read);
+
+    /**
+     * This callback is called when #pj_equeue_write, #pj_equeue_send, or
+     * #pj_equeue_sendto completes.
+     *
+     * @param key	    The key.
+     * @param bytes_read    The size of data that has just been written.
+     */
+    void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent);
+
+    /**
+     * This callback is called when #pj_equeue_accept completes.
+     *
+     * @param key	    The key.
+     * @param status	    Zero if the operation completes successfully.
+     */
+    void (*on_accept_complete)(pj_equeue_key_t *key, int status);
+
+    /**
+     * This callback is called when #pj_equeue_connect completes.
+     *
+     * @param key	    The key.
+     * @param status	    Zero if the operation completes successfully.
+     */
+    void (*on_connect_complete)(pj_equeue_key_t *key, int status);
+
+} pj_io_callback;
+
+/**
+ * Event Queue options.
+ */
+typedef struct pj_equeue_options
+{
+    /** Maximum number of threads that are allowed to access Event Queue
+     *  simulteneously.
+     */
+    unsigned	nb_threads;
+
+    /** If non-zero, then no mutex protection will be used. */
+    pj_bool_t	no_lock;
+
+    /** Interval of the busy loop inside the event queue.
+     *  The time resolution here determines the accuracy of the
+     *  timer in the Event Queue.
+     */
+    pj_time_val	poll_interval;
+
+} pj_equeue_options;
+
+
+/**
+ * Error value returned by I/O operations to indicate that the operation
+ * can't complete immediately and will complete later.
+ */
+#define PJ_EQUEUE_PENDING   (-2)
+
+/**
+ * Types of Event Queue operation.
+ */
+typedef enum pj_equeue_op
+{
+    PJ_EQUEUE_OP_NONE		= 0,	/**< No operation.	    */
+    PJ_EQUEUE_OP_READ		= 1,	/**< read() operation.	    */
+    PJ_EQUEUE_OP_RECV_FROM	= 2,	/**< recvfrom() operation.  */
+    PJ_EQUEUE_OP_WRITE		= 4,	/**< write() operation.	    */
+    PJ_EQUEUE_OP_SEND_TO	= 8,	/**< sendto() operation.    */
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+    PJ_EQUEUE_OP_ACCEPT		= 16,	/**< accept() operation.    */
+    PJ_EQUEUE_OP_CONNECT	= 32,	/**< connect() operation.   */
+#endif	/* PJ_HAS_TCP */
+} pj_equeue_op;
+
+
+
+/**
+ * Initialize Event Queue options with default values.
+ *
+ * @param options   Event Queue options.
+ */
+PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options);
+
+/**
+ * Create a new Event Queue framework.
+ *
+ * @param pool	    The pool to allocate the event queue structure.
+ * @param options   Event queue options, or if NULL is given, then
+ *		    default options will be used.
+ * @param equeue    Pointer to receive event queue structure.
+ *
+ * @return	    zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool, 
+				       const pj_equeue_options *options,
+				       pj_equeue_t **equeue);
+
+/**
+ * Get the first instance of Event Queue, or NULL if no Event Queue
+ * instance has been created in the application.
+ *
+ * @return	    The first instance of Event Queue created, or NULL.
+ */
+PJ_DECL(pj_equeue_t*) pj_equeue_instance(void);
+
+/**
+ * Destroy the Event Queue.
+ *
+ * @param equeue    The Event Queue instance to be destroyed.
+ */
+PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue );
+
+/**
+ * Customize the lock object that is used by the Event Queue.
+ *
+ * @param equeue    The Event Queue instance.
+ * @param lock	    The lock object.
+ * @param auto_del  If non-zero, the lock will be destroyed by
+ *		    Event Queue.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue,
+					 pj_lock_t *lock, 
+					 pj_bool_t auto_del);
+
+/**
+ * Associate an Event Queue key to particular handle. The key is also
+ * associated with the callback and user data, which will be used by
+ * the Event Queue framework when signalling event back to application.
+ *
+ * @param pool	    To allocate the resource for the specified handle, which
+ *		    must be valid until the handle/key is unregistered
+ *		    from Event Queue.
+ * @param equeue    The Event Queue.
+ * @param hnd	    The OS handle to be registered, which can be a socket
+ *		    descriptor (pj_sock_t), file descriptor, etc.
+ * @param cb	    Callback to be called when I/O operation completes. 
+ * @param user_data User data to be associated with the key.
+ * @param key	    Pointer to receive the key.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool,
+					 pj_equeue_t *equeue,
+					 pj_oshandle_t hnd,
+					 pj_io_callback *cb,
+					 void *user_data,
+					 pj_equeue_key_t **key);
+
+/**
+ * Retrieve user data associated with a key.
+ *
+ * @param key	    The Event Queue key.
+ *
+ * @return	    User data associated with the key.
+ */
+PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key );
+
+
+/**
+ * Unregister Event Queue key from the Event Queue.
+ *
+ * @param equeue    The Event Queue.
+ * @param key	    The key.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue,
+					   pj_equeue_key_t *key);
+
+/**
+ * Instruct the Event Queue to read from the specified handle. This function
+ * returns immediately (i.e. non-blocking) regardless whether some data has 
+ * been transfered. If the operation can't complete immediately, caller will 
+ * be notified about the completion when it calls pj_equeue_poll().
+ *
+ * @param key	    The key that uniquely identifies the handle.
+ * @param buffer    The buffer to hold the read data. The caller MUST make sure
+ *		    that this buffer remain valid until the framework completes
+ *		    reading the handle.
+ * @param size	    The maximum size to be read.
+ *
+ * @return
+ *  - zero or positive number to indicate the number of bytes has been
+ *		    read, and in this case the operation was not queued.
+ *  - (-1) on error, which in this case operation was not queued.
+ *  - PJ_EQUEUE_PENDING if the operation has been queued.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key,
+				    void *buffer,
+				    pj_size_t size);
+
+/**
+ * Start recv() operation on the specified handle.
+ *
+ * @see ::pj_ioqueue_read
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key,
+				    void *buf,
+				    pj_size_t size,
+				    unsigned flags);
+
+/**
+ * Start recvfrom() operation on the specified handle.
+ *
+ * @see ::pj_equeue_read
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key,
+					void *buf,
+					pj_size_t size,
+					unsigned flags,
+					pj_sockaddr_t *addr,
+					int *addrlen );
+
+/**
+ * Write.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key,
+				     const void *buf,
+				     pj_size_t size);
+
+/**
+ * Send.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key,
+				    const void *buf,
+				    pj_size_t size,
+				    unsigned flags);
+
+/**
+ * Sendto.
+ */
+PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key,
+				      const void *buf,
+				      pj_size_t size,
+				      unsigned flags,
+				      const pj_sockaddr_t *addr,
+				      int addrlen);
+
+/**
+ * Schedule timer.
+ */
+PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue,
+					       const pj_time_val *timeout,
+					       pj_timer_entry *entry);
+
+/**
+ * Cancel timer.
+ */
+PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue,
+					     pj_timer_entry *entry);
+
+/**
+ * Poll for events.
+ */
+PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue,
+				     const pj_time_val *timeout );
+
+/**
+ * Run.
+ */
+PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue );
+
+/**
+ * Stop all running threads.
+ */
+PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue );
+
+
+/** @} */
+
+PJ_END_DECL
+
+#endif	/* __PJ_EQUEUE_H__ */
diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h
index c45c3b8..ffb72c1 100644
--- a/pjlib/include/pj/errno.h
+++ b/pjlib/include/pj/errno.h
@@ -1,279 +1,279 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_ERRNO_H__

-#define __PJ_ERRNO_H__

-

-/**

- * @file errno.h

- * @brief PJLIB Error Codes

- */

-#include <pj/types.h>

-#include <pj/compat/errno.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup pj_errno Error Codes

- * @ingroup PJ

- * @{

- *

- * In PJLIB, error/status codes from operating system are translated

- * into PJLIB error namespace, and stored in @a pj_status_t. All functions

- * that work with @a pj_status_t expect to get PJLIB error code instead

- * of native codes.

- *

- * @section pj_errno_retval Return Values

- *

- * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the

- * operation was completed successfully, or non-zero value to indicate 

- * error. If the error came from operating system, then the native error

- * code is translated/folded into PJLIB's error namespace by using

- * #PJ_STATUS_FROM_OS() macro. The function will do this automatically

- * before returning the error to caller.

- *

- * @section pj_errno_errmsg Error Message

- *

- * To get the error message corresponding to a particular code, use function

- * #pj_strerror(). This function expects error code in PJLIB error namespace,

- * not the native error code. Application can pass the value from the 

- * following sources to this function:

- *  - #pj_get_os_error()

- *  - #pj_get_netos_error()

- *  - any return value from function returning @a pj_status_t.

- *

- * Application MUST NOT pass native error code (such as error code from

- * functions like GetLastError() or errno) to PJLIB functions expecting

- * @a pj_status_t.

- *

- */

-

-/**

- * Get the last platform error/status, folded into pj_status_t.

- * @return	OS dependent error code, folded into pj_status_t.

- * @remark	This function gets errno, or calls GetLastError() function and

- *		convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do

- *		not call this for socket functions!

- * @see	pj_get_netos_error()

- */

-PJ_DECL(pj_status_t) pj_get_os_error(void);

-

-/**

- * Set last error.

- * @param code	pj_status_t

- */

-PJ_DECL(void) pj_set_os_error(pj_status_t code);

-

-/**

- * Get the last error from socket operations.

- * @return	Last socket error, folded into pj_status_t.

- */

-PJ_DECL(pj_status_t) pj_get_netos_error(void);

-

-/**

- * Set error code.

- * @param code	pj_status_t.

- */

-PJ_DECL(void) pj_set_netos_error(pj_status_t code);

-

-

-/**

- * Get the error message for the specified error code. The message

- * string will be NULL terminated.

- *

- * @param statcode  The error code.

- * @param buf	    Buffer to hold the error message string.

- * @param bufsize   Size of the buffer.

- *

- * @return	    The error message as NULL terminated string,

- *                  wrapped with pj_str_t.

- */

-PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, 

-			       char *buf, pj_size_t bufsize);

-

-

-/**

- * @hideinitializer

- * Return platform os error code folded into pj_status_t code. This is

- * the macro that is used throughout the library for all PJLIB's functions

- * that returns error from operating system. Application may override

- * this macro to reduce size (e.g. by defining it to always return 

- * #PJ_EUNKNOWN).

- *

- * Note:

- *  This macro MUST return non-zero value regardless whether zero is

- *  passed as the argument. The reason is to protect logic error when

- *  the operating system doesn't report error codes properly.

- *

- * @param os_code   Platform OS error code. This value may be evaluated

- *		    more than once.

- * @return	    The platform os error code folded into pj_status_t.

- */

-#ifndef PJ_RETURN_OS_ERROR

-#   define PJ_RETURN_OS_ERROR(os_code)   (os_code ? \

-					    PJ_STATUS_FROM_OS(os_code) : -1)

-#endif

-

-

-/**

- * @hideinitializer

- * Fold a platform specific error into an pj_status_t code.

- *

- * @param e	The platform os error code.

- * @return	pj_status_t

- * @warning	Macro implementation; the syserr argument may be evaluated

- *		multiple times.

- */

-#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS)

-

-/**

- * @hideinitializer

- * Fold an pj_status_t code back to the native platform defined error.

- *

- * @param e	The pj_status_t folded platform os error code.

- * @return	pj_os_err_type

- * @warning	macro implementation; the statcode argument may be evaluated

- *		multiple times.  If the statcode was not created by 

- *		pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined.

- */

-#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS)

-

-

-/**

- * @defgroup pj_errnum PJLIB's Own Error Codes

- * @ingroup pj_errno

- * @{

- */

-

-/**

- * @hideinitializer

- * Unknown error has been reported.

- */

-#define PJ_EUNKNOWN	    (PJ_ERRNO_START_STATUS + 1)	/* 70001 */

-/**

- * @hideinitializer

- * The operation is pending and will be completed later.

- */

-#define PJ_EPENDING	    (PJ_ERRNO_START_STATUS + 2)	/* 70002 */

-/**

- * @hideinitializer

- * Too many connecting sockets.

- */

-#define PJ_ETOOMANYCONN	    (PJ_ERRNO_START_STATUS + 3)	/* 70003 */

-/**

- * @hideinitializer

- * Invalid argument.

- */

-#define PJ_EINVAL	    (PJ_ERRNO_START_STATUS + 4)	/* 70004 */

-/**

- * @hideinitializer

- * Name too long (eg. hostname too long).

- */

-#define PJ_ENAMETOOLONG	    (PJ_ERRNO_START_STATUS + 5)	/* 70005 */

-/**

- * @hideinitializer

- * Not found.

- */

-#define PJ_ENOTFOUND	    (PJ_ERRNO_START_STATUS + 6)	/* 70006 */

-/**

- * @hideinitializer

- * Not enough memory.

- */

-#define PJ_ENOMEM	    (PJ_ERRNO_START_STATUS + 7)	/* 70007 */

-/**

- * @hideinitializer

- * Bug detected!

- */

-#define PJ_EBUG             (PJ_ERRNO_START_STATUS + 8)	/* 70008 */

-/**

- * @hideinitializer

- * Operation timed out.

- */

-#define PJ_ETIMEDOUT        (PJ_ERRNO_START_STATUS + 9)	/* 70009 */

-/**

- * @hideinitializer

- * Too many objects.

- */

-#define PJ_ETOOMANY         (PJ_ERRNO_START_STATUS + 10)/* 70010 */

-/**

- * @hideinitializer

- * Object is busy.

- */

-#define PJ_EBUSY            (PJ_ERRNO_START_STATUS + 11)/* 70011 */

-/**

- * @hideinitializer

- * The specified option is not supported.

- */

-#define PJ_ENOTSUP	    (PJ_ERRNO_START_STATUS + 12)/* 70012 */

-/**

- * @hideinitializer

- * Invalid operation.

- */

-#define PJ_EINVALIDOP	    (PJ_ERRNO_START_STATUS + 13)/* 70013 */

-/**

- * @hideinitializer

- * Operation is cancelled.

- */

-#define PJ_ECANCELLED	    (PJ_ERRNO_START_STATUS + 14)/* 70014 */

-/**

- * @hideinitializer

- * Object already exists.

- */

-#define PJ_EEXISTS          (PJ_ERRNO_START_STATUS + 15)/* 70015 */

-

-/** @} */   /* pj_errnum */

-

-/** @} */   /* pj_errno */

-

-

-/**

- * PJ_ERRNO_START is where PJLIB specific error values start.

- */

-#define PJ_ERRNO_START		20000

-

-/**

- * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of 

- * the error/status range below.

- */

-#define PJ_ERRNO_SPACE_SIZE	50000

-

-/**

- * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start.

- * Effectively the error in this class would be 70000 - 119000.

- */

-#define PJ_ERRNO_START_STATUS	(PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE)

-

-/**

- * PJ_ERRNO_START_SYS converts platform specific error codes into

- * pj_status_t values.

- * Effectively the error in this class would be 120000 - 169000.

- */

-#define PJ_ERRNO_START_SYS	(PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE)

-

-/**

- * PJ_ERRNO_START_USER are reserved for applications that use error

- * codes along with PJLIB codes.

- * Effectively the error in this class would be 170000 - 219000.

- */

-#define PJ_ERRNO_START_USER	(PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE)

-

-

-PJ_END_DECL

-

-#endif	/* __PJ_ERRNO_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_ERRNO_H__
+#define __PJ_ERRNO_H__
+
+/**
+ * @file errno.h
+ * @brief PJLIB Error Codes
+ */
+#include <pj/types.h>
+#include <pj/compat/errno.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup pj_errno Error Codes
+ * @ingroup PJ
+ * @{
+ *
+ * In PJLIB, error/status codes from operating system are translated
+ * into PJLIB error namespace, and stored in @a pj_status_t. All functions
+ * that work with @a pj_status_t expect to get PJLIB error code instead
+ * of native codes.
+ *
+ * @section pj_errno_retval Return Values
+ *
+ * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the
+ * operation was completed successfully, or non-zero value to indicate 
+ * error. If the error came from operating system, then the native error
+ * code is translated/folded into PJLIB's error namespace by using
+ * #PJ_STATUS_FROM_OS() macro. The function will do this automatically
+ * before returning the error to caller.
+ *
+ * @section pj_errno_errmsg Error Message
+ *
+ * To get the error message corresponding to a particular code, use function
+ * #pj_strerror(). This function expects error code in PJLIB error namespace,
+ * not the native error code. Application can pass the value from the 
+ * following sources to this function:
+ *  - #pj_get_os_error()
+ *  - #pj_get_netos_error()
+ *  - any return value from function returning @a pj_status_t.
+ *
+ * Application MUST NOT pass native error code (such as error code from
+ * functions like GetLastError() or errno) to PJLIB functions expecting
+ * @a pj_status_t.
+ *
+ */
+
+/**
+ * Get the last platform error/status, folded into pj_status_t.
+ * @return	OS dependent error code, folded into pj_status_t.
+ * @remark	This function gets errno, or calls GetLastError() function and
+ *		convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do
+ *		not call this for socket functions!
+ * @see	pj_get_netos_error()
+ */
+PJ_DECL(pj_status_t) pj_get_os_error(void);
+
+/**
+ * Set last error.
+ * @param code	pj_status_t
+ */
+PJ_DECL(void) pj_set_os_error(pj_status_t code);
+
+/**
+ * Get the last error from socket operations.
+ * @return	Last socket error, folded into pj_status_t.
+ */
+PJ_DECL(pj_status_t) pj_get_netos_error(void);
+
+/**
+ * Set error code.
+ * @param code	pj_status_t.
+ */
+PJ_DECL(void) pj_set_netos_error(pj_status_t code);
+
+
+/**
+ * Get the error message for the specified error code. The message
+ * string will be NULL terminated.
+ *
+ * @param statcode  The error code.
+ * @param buf	    Buffer to hold the error message string.
+ * @param bufsize   Size of the buffer.
+ *
+ * @return	    The error message as NULL terminated string,
+ *                  wrapped with pj_str_t.
+ */
+PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, 
+			       char *buf, pj_size_t bufsize);
+
+
+/**
+ * @hideinitializer
+ * Return platform os error code folded into pj_status_t code. This is
+ * the macro that is used throughout the library for all PJLIB's functions
+ * that returns error from operating system. Application may override
+ * this macro to reduce size (e.g. by defining it to always return 
+ * #PJ_EUNKNOWN).
+ *
+ * Note:
+ *  This macro MUST return non-zero value regardless whether zero is
+ *  passed as the argument. The reason is to protect logic error when
+ *  the operating system doesn't report error codes properly.
+ *
+ * @param os_code   Platform OS error code. This value may be evaluated
+ *		    more than once.
+ * @return	    The platform os error code folded into pj_status_t.
+ */
+#ifndef PJ_RETURN_OS_ERROR
+#   define PJ_RETURN_OS_ERROR(os_code)   (os_code ? \
+					    PJ_STATUS_FROM_OS(os_code) : -1)
+#endif
+
+
+/**
+ * @hideinitializer
+ * Fold a platform specific error into an pj_status_t code.
+ *
+ * @param e	The platform os error code.
+ * @return	pj_status_t
+ * @warning	Macro implementation; the syserr argument may be evaluated
+ *		multiple times.
+ */
+#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS)
+
+/**
+ * @hideinitializer
+ * Fold an pj_status_t code back to the native platform defined error.
+ *
+ * @param e	The pj_status_t folded platform os error code.
+ * @return	pj_os_err_type
+ * @warning	macro implementation; the statcode argument may be evaluated
+ *		multiple times.  If the statcode was not created by 
+ *		pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined.
+ */
+#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS)
+
+
+/**
+ * @defgroup pj_errnum PJLIB's Own Error Codes
+ * @ingroup pj_errno
+ * @{
+ */
+
+/**
+ * @hideinitializer
+ * Unknown error has been reported.
+ */
+#define PJ_EUNKNOWN	    (PJ_ERRNO_START_STATUS + 1)	/* 70001 */
+/**
+ * @hideinitializer
+ * The operation is pending and will be completed later.
+ */
+#define PJ_EPENDING	    (PJ_ERRNO_START_STATUS + 2)	/* 70002 */
+/**
+ * @hideinitializer
+ * Too many connecting sockets.
+ */
+#define PJ_ETOOMANYCONN	    (PJ_ERRNO_START_STATUS + 3)	/* 70003 */
+/**
+ * @hideinitializer
+ * Invalid argument.
+ */
+#define PJ_EINVAL	    (PJ_ERRNO_START_STATUS + 4)	/* 70004 */
+/**
+ * @hideinitializer
+ * Name too long (eg. hostname too long).
+ */
+#define PJ_ENAMETOOLONG	    (PJ_ERRNO_START_STATUS + 5)	/* 70005 */
+/**
+ * @hideinitializer
+ * Not found.
+ */
+#define PJ_ENOTFOUND	    (PJ_ERRNO_START_STATUS + 6)	/* 70006 */
+/**
+ * @hideinitializer
+ * Not enough memory.
+ */
+#define PJ_ENOMEM	    (PJ_ERRNO_START_STATUS + 7)	/* 70007 */
+/**
+ * @hideinitializer
+ * Bug detected!
+ */
+#define PJ_EBUG             (PJ_ERRNO_START_STATUS + 8)	/* 70008 */
+/**
+ * @hideinitializer
+ * Operation timed out.
+ */
+#define PJ_ETIMEDOUT        (PJ_ERRNO_START_STATUS + 9)	/* 70009 */
+/**
+ * @hideinitializer
+ * Too many objects.
+ */
+#define PJ_ETOOMANY         (PJ_ERRNO_START_STATUS + 10)/* 70010 */
+/**
+ * @hideinitializer
+ * Object is busy.
+ */
+#define PJ_EBUSY            (PJ_ERRNO_START_STATUS + 11)/* 70011 */
+/**
+ * @hideinitializer
+ * The specified option is not supported.
+ */
+#define PJ_ENOTSUP	    (PJ_ERRNO_START_STATUS + 12)/* 70012 */
+/**
+ * @hideinitializer
+ * Invalid operation.
+ */
+#define PJ_EINVALIDOP	    (PJ_ERRNO_START_STATUS + 13)/* 70013 */
+/**
+ * @hideinitializer
+ * Operation is cancelled.
+ */
+#define PJ_ECANCELLED	    (PJ_ERRNO_START_STATUS + 14)/* 70014 */
+/**
+ * @hideinitializer
+ * Object already exists.
+ */
+#define PJ_EEXISTS          (PJ_ERRNO_START_STATUS + 15)/* 70015 */
+
+/** @} */   /* pj_errnum */
+
+/** @} */   /* pj_errno */
+
+
+/**
+ * PJ_ERRNO_START is where PJLIB specific error values start.
+ */
+#define PJ_ERRNO_START		20000
+
+/**
+ * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of 
+ * the error/status range below.
+ */
+#define PJ_ERRNO_SPACE_SIZE	50000
+
+/**
+ * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start.
+ * Effectively the error in this class would be 70000 - 119000.
+ */
+#define PJ_ERRNO_START_STATUS	(PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE)
+
+/**
+ * PJ_ERRNO_START_SYS converts platform specific error codes into
+ * pj_status_t values.
+ * Effectively the error in this class would be 120000 - 169000.
+ */
+#define PJ_ERRNO_START_SYS	(PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE)
+
+/**
+ * PJ_ERRNO_START_USER are reserved for applications that use error
+ * codes along with PJLIB codes.
+ * Effectively the error in this class would be 170000 - 219000.
+ */
+#define PJ_ERRNO_START_USER	(PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE)
+
+
+PJ_END_DECL
+
+#endif	/* __PJ_ERRNO_H__ */
+
diff --git a/pjlib/include/pj/except.h b/pjlib/include/pj/except.h
index a0143b9..301242a 100644
--- a/pjlib/include/pj/except.h
+++ b/pjlib/include/pj/except.h
@@ -1,284 +1,284 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_EXCEPTION_H__

-#define __PJ_EXCEPTION_H__

-

-/**

- * @file except.h

- * @brief Exception Handling in C.

- */

-

-#include <pj/types.h>

-#include <pj/compat/setjmp.h>

-

-

-PJ_BEGIN_DECL

-

-

-/**

- * @defgroup PJ_EXCEPT Exception Handling

- * @ingroup PJ_MISC

- * @{

- *

- * \section pj_except_sample_sec Quick Example

- *

- * For the impatient, take a look at some examples:

- *  - @ref page_pjlib_samples_except_c

- *  - @ref page_pjlib_exception_test

- *

- * \section pj_except_except Exception Handling

- *

- * This module provides exception handling syntactically similar to C++ in

- * C language. The underlying mechanism use setjmp() and longjmp(), and since

- * these constructs are ANSI standard, the mechanism here should be available

- * on most platforms/compilers which are ANSI compliant.

- *

- * If ANSI libc is not available, then setjmp()/longjmp() implementation will

- * be provided. See <pj/compat/setjmp.h> for compatibility.

- *

- * The exception handling mechanism is completely thread safe, so the exception

- * thrown by one thread will not interfere with other thread.

- *

- * CAVEATS:

- *  - unlike C++ exception, the scheme here won't call destructors of local

- *    objects if exception is thrown. Care must be taken when a function

- *    hold some resorce such as pool or mutex etc.

- *  - You CAN NOT make nested exception in one single function without using

- *    a nested PJ_USE_EXCEPTION.

- *  - Exceptions will always be caught by the first handle (unlike C++ where

- *    exception is only caught if the type matches.

- *

- * The exception handling constructs are similar to C++. The blocks will be

- * constructed similar to the following sample:

- *

- * \verbatim

-   #define NO_MEMORY     1

-   #define SYNTAX_ERROR  2

-  

-   int main()

-   {

-      PJ_USE_EXCEPTION;  // declare local exception stack.

-  

-      PJ_TRY {

-        ...// do something..

-      }

-      PJ_CATCH(NO_MEMORY) {

-        ... // handle exception 1

-      }

-      PJ_CATCH(SYNTAX_ERROR) {

-        ... // handle exception 2

-      }

-      PJ_DEFAULT {

-        ... // handle other exceptions.

-      }

-      PJ_END;

-   }

-   \endverbatim

- *

- * The above sample uses hard coded exception ID. It is @b strongly

- * recommended that applications request a unique exception ID instead

- * of hard coded value like above.

- *

- * \section pj_except_reg Exception ID Allocation

- *

- * To ensure that exception ID (number) are used consistently and to

- * prevent ID collisions in an application, it is strongly suggested that 

- * applications allocate an exception ID for each possible exception

- * type. As a bonus of this process, the application can identify

- * the name of the exception when the particular exception is thrown.

- *

- * Exception ID management are performed with the following APIs:

- *  - #pj_exception_id_alloc().

- *  - #pj_exception_id_free().

- *  - #pj_exception_id_name().

- *

- *

- * PJLIB itself automatically allocates one exception id, i.e.

- * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception

- * ID is raised by default pool policy when it fails to allocate memory.

- *

- * \section PJ_EX_KEYWORDS Keywords

- *

- * \subsection PJ_THROW PJ_THROW(expression)

- * Throw an exception. The expression thrown is an integer as the result of

- * the \a expression. This keyword can be specified anywhere within the 

- * program.

- *

- * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION

- * Specify this in the variable definition section of the function block 

- * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception 

- * block. 

- * Actually, this is just a macro to declare local variable which is used to

- * push the exception state to the exception stack.

- *

- * \subsection PJ_TRY PJ_TRY

- * The \a PJ_TRY keyword is typically followed by a block. If an exception is

- * thrown in this block, then the execution will resume to the \a PJ_CATCH 

- * handler.

- *

- * \subsection PJ_CATCH PJ_CATCH(expression)

- * The \a PJ_CATCH is normally followed by a block. This block will be executed

- * if the exception being thrown is equal to the expression specified in the

- * \a PJ_CATCH.

- *

- * \subsection PJ_DEFAULT PJ_DEFAULT

- * The \a PJ_DEFAULT keyword is normally followed by a block. This block will

- * be executed if the exception being thrown doesn't match any of the \a

- * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the

- * last block of the handlers.

- *

- * \subsection PJ_END PJ_END

- * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks.

- *

- * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void)

- * Get the last exception thrown. This macro is normally called inside the

- * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where

- * the \a PJ_USE_EXCEPTION definition is in scope.

- *

- * 

- * \section pj_except_examples_sec Examples

- *

- * For some examples on how to use the exception construct, please see:

- *  - @ref page_pjlib_samples_except_c

- *  - @ref page_pjlib_exception_test

- */

-

-/**

- * Allocate a unique exception id.

- * Applications don't have to allocate a unique exception ID before using

- * the exception construct. However, by doing so it ensures that there is

- * no collisions of exception ID.

- *

- * As a bonus, when exception number is acquired through this function,

- * the library can assign name to the exception (only if 

- * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the

- * exception name when it catches an exception.

- *

- * @param name      Name to be associated with the exception ID.

- * @param id        Pointer to receive the ID.

- *

- * @return          PJ_SUCCESS on success or PJ_ETOOMANY if the library 

- *                  is running out out ids.

- */

-PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name,

-                                           pj_exception_id_t *id);

-

-/**

- * Free an exception id.

- *

- * @param id        The exception ID.

- *

- * @return          PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id);

-

-/**

- * Retrieve name associated with the exception id.

- *

- * @param id        The exception ID.

- *

- * @return          The name associated with the specified ID.

- */

-PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id);

-

-

-/** @} */

-

-/**

- * This structure (which should be invisible to user) manages the TRY handler

- * stack.

- */

-struct pj_exception_state_t

-{

-    struct pj_exception_state_t *prev;  /**< Previous state in the list. */

-    pj_jmp_buf state;                   /**< jmp_buf.                    */

-};

-

-/**

- * Throw exception.

- * @param id    Exception Id.

- */

-PJ_DECL_NO_RETURN(void) 

-pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN;

-

-/**

- * Push exception handler.

- */

-PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec);

-

-/**

- * Pop exception handler.

- */

-PJ_DECL(void) pj_pop_exception_handler_(void);

-

-/**

- * Declare that the function will use exception.

- * @hideinitializer

- */

-#define PJ_USE_EXCEPTION    struct pj_exception_state_t pj_x_except__; int pj_x_code__

-

-/**

- * Start exception specification block.

- * @hideinitializer

- */

-#define PJ_TRY		    if (1) { \

-				pj_push_exception_handler_(&pj_x_except__); \

-				pj_x_code__ = pj_setjmp(pj_x_except__.state); \

-				if (pj_x_code__ == 0)

-/**

- * Catch the specified exception Id.

- * @param id    The exception number to catch.

- * @hideinitializer

- */

-#define PJ_CATCH(id)	    else if (pj_x_code__ == (id))

-

-/**

- * Catch any exception number.

- * @hideinitializer

- */

-#define PJ_DEFAULT	    else

-

-/**

- * End of exception specification block.

- * @hideinitializer

- */

-#define PJ_END			pj_pop_exception_handler_(); \

-			    } else {}

-

-/**

- * Throw exception.

- * @param exception_id  The exception number.

- * @hideinitializer

- */

-#define PJ_THROW(exception_id)	pj_throw_exception_(exception_id)

-

-/**

- * Get current exception.

- * @return      Current exception code.

- * @hideinitializer

- */

-#define PJ_GET_EXCEPTION()	(pj_x_code__)

-

-PJ_END_DECL

-

-

-

-#endif	/* __PJ_EXCEPTION_H__ */

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_EXCEPTION_H__
+#define __PJ_EXCEPTION_H__
+
+/**
+ * @file except.h
+ * @brief Exception Handling in C.
+ */
+
+#include <pj/types.h>
+#include <pj/compat/setjmp.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_EXCEPT Exception Handling
+ * @ingroup PJ_MISC
+ * @{
+ *
+ * \section pj_except_sample_sec Quick Example
+ *
+ * For the impatient, take a look at some examples:
+ *  - @ref page_pjlib_samples_except_c
+ *  - @ref page_pjlib_exception_test
+ *
+ * \section pj_except_except Exception Handling
+ *
+ * This module provides exception handling syntactically similar to C++ in
+ * C language. The underlying mechanism use setjmp() and longjmp(), and since
+ * these constructs are ANSI standard, the mechanism here should be available
+ * on most platforms/compilers which are ANSI compliant.
+ *
+ * If ANSI libc is not available, then setjmp()/longjmp() implementation will
+ * be provided. See <pj/compat/setjmp.h> for compatibility.
+ *
+ * The exception handling mechanism is completely thread safe, so the exception
+ * thrown by one thread will not interfere with other thread.
+ *
+ * CAVEATS:
+ *  - unlike C++ exception, the scheme here won't call destructors of local
+ *    objects if exception is thrown. Care must be taken when a function
+ *    hold some resorce such as pool or mutex etc.
+ *  - You CAN NOT make nested exception in one single function without using
+ *    a nested PJ_USE_EXCEPTION.
+ *  - Exceptions will always be caught by the first handle (unlike C++ where
+ *    exception is only caught if the type matches.
+ *
+ * The exception handling constructs are similar to C++. The blocks will be
+ * constructed similar to the following sample:
+ *
+ * \verbatim
+   #define NO_MEMORY     1
+   #define SYNTAX_ERROR  2
+  
+   int main()
+   {
+      PJ_USE_EXCEPTION;  // declare local exception stack.
+  
+      PJ_TRY {
+        ...// do something..
+      }
+      PJ_CATCH(NO_MEMORY) {
+        ... // handle exception 1
+      }
+      PJ_CATCH(SYNTAX_ERROR) {
+        ... // handle exception 2
+      }
+      PJ_DEFAULT {
+        ... // handle other exceptions.
+      }
+      PJ_END;
+   }
+   \endverbatim
+ *
+ * The above sample uses hard coded exception ID. It is @b strongly
+ * recommended that applications request a unique exception ID instead
+ * of hard coded value like above.
+ *
+ * \section pj_except_reg Exception ID Allocation
+ *
+ * To ensure that exception ID (number) are used consistently and to
+ * prevent ID collisions in an application, it is strongly suggested that 
+ * applications allocate an exception ID for each possible exception
+ * type. As a bonus of this process, the application can identify
+ * the name of the exception when the particular exception is thrown.
+ *
+ * Exception ID management are performed with the following APIs:
+ *  - #pj_exception_id_alloc().
+ *  - #pj_exception_id_free().
+ *  - #pj_exception_id_name().
+ *
+ *
+ * PJLIB itself automatically allocates one exception id, i.e.
+ * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception
+ * ID is raised by default pool policy when it fails to allocate memory.
+ *
+ * \section PJ_EX_KEYWORDS Keywords
+ *
+ * \subsection PJ_THROW PJ_THROW(expression)
+ * Throw an exception. The expression thrown is an integer as the result of
+ * the \a expression. This keyword can be specified anywhere within the 
+ * program.
+ *
+ * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION
+ * Specify this in the variable definition section of the function block 
+ * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception 
+ * block. 
+ * Actually, this is just a macro to declare local variable which is used to
+ * push the exception state to the exception stack.
+ *
+ * \subsection PJ_TRY PJ_TRY
+ * The \a PJ_TRY keyword is typically followed by a block. If an exception is
+ * thrown in this block, then the execution will resume to the \a PJ_CATCH 
+ * handler.
+ *
+ * \subsection PJ_CATCH PJ_CATCH(expression)
+ * The \a PJ_CATCH is normally followed by a block. This block will be executed
+ * if the exception being thrown is equal to the expression specified in the
+ * \a PJ_CATCH.
+ *
+ * \subsection PJ_DEFAULT PJ_DEFAULT
+ * The \a PJ_DEFAULT keyword is normally followed by a block. This block will
+ * be executed if the exception being thrown doesn't match any of the \a
+ * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the
+ * last block of the handlers.
+ *
+ * \subsection PJ_END PJ_END
+ * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks.
+ *
+ * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void)
+ * Get the last exception thrown. This macro is normally called inside the
+ * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where
+ * the \a PJ_USE_EXCEPTION definition is in scope.
+ *
+ * 
+ * \section pj_except_examples_sec Examples
+ *
+ * For some examples on how to use the exception construct, please see:
+ *  - @ref page_pjlib_samples_except_c
+ *  - @ref page_pjlib_exception_test
+ */
+
+/**
+ * Allocate a unique exception id.
+ * Applications don't have to allocate a unique exception ID before using
+ * the exception construct. However, by doing so it ensures that there is
+ * no collisions of exception ID.
+ *
+ * As a bonus, when exception number is acquired through this function,
+ * the library can assign name to the exception (only if 
+ * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the
+ * exception name when it catches an exception.
+ *
+ * @param name      Name to be associated with the exception ID.
+ * @param id        Pointer to receive the ID.
+ *
+ * @return          PJ_SUCCESS on success or PJ_ETOOMANY if the library 
+ *                  is running out out ids.
+ */
+PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name,
+                                           pj_exception_id_t *id);
+
+/**
+ * Free an exception id.
+ *
+ * @param id        The exception ID.
+ *
+ * @return          PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id);
+
+/**
+ * Retrieve name associated with the exception id.
+ *
+ * @param id        The exception ID.
+ *
+ * @return          The name associated with the specified ID.
+ */
+PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id);
+
+
+/** @} */
+
+/**
+ * This structure (which should be invisible to user) manages the TRY handler
+ * stack.
+ */
+struct pj_exception_state_t
+{
+    struct pj_exception_state_t *prev;  /**< Previous state in the list. */
+    pj_jmp_buf state;                   /**< jmp_buf.                    */
+};
+
+/**
+ * Throw exception.
+ * @param id    Exception Id.
+ */
+PJ_DECL_NO_RETURN(void) 
+pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN;
+
+/**
+ * Push exception handler.
+ */
+PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec);
+
+/**
+ * Pop exception handler.
+ */
+PJ_DECL(void) pj_pop_exception_handler_(void);
+
+/**
+ * Declare that the function will use exception.
+ * @hideinitializer
+ */
+#define PJ_USE_EXCEPTION    struct pj_exception_state_t pj_x_except__; int pj_x_code__
+
+/**
+ * Start exception specification block.
+ * @hideinitializer
+ */
+#define PJ_TRY		    if (1) { \
+				pj_push_exception_handler_(&pj_x_except__); \
+				pj_x_code__ = pj_setjmp(pj_x_except__.state); \
+				if (pj_x_code__ == 0)
+/**
+ * Catch the specified exception Id.
+ * @param id    The exception number to catch.
+ * @hideinitializer
+ */
+#define PJ_CATCH(id)	    else if (pj_x_code__ == (id))
+
+/**
+ * Catch any exception number.
+ * @hideinitializer
+ */
+#define PJ_DEFAULT	    else
+
+/**
+ * End of exception specification block.
+ * @hideinitializer
+ */
+#define PJ_END			pj_pop_exception_handler_(); \
+			    } else {}
+
+/**
+ * Throw exception.
+ * @param exception_id  The exception number.
+ * @hideinitializer
+ */
+#define PJ_THROW(exception_id)	pj_throw_exception_(exception_id)
+
+/**
+ * Get current exception.
+ * @return      Current exception code.
+ * @hideinitializer
+ */
+#define PJ_GET_EXCEPTION()	(pj_x_code__)
+
+PJ_END_DECL
+
+
+
+#endif	/* __PJ_EXCEPTION_H__ */
+
+
diff --git a/pjlib/include/pj/fifobuf.h b/pjlib/include/pj/fifobuf.h
index ee3a19a..59af013 100644
--- a/pjlib/include/pj/fifobuf.h
+++ b/pjlib/include/pj/fifobuf.h
@@ -1,43 +1,43 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_FIFOBUF_H__

-#define __PJ_FIFOBUF_H__

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-typedef struct pj_fifobuf_t pj_fifobuf_t;

-struct pj_fifobuf_t

-{

-    char *first, *last;

-    char *ubegin, *uend;

-    int full;

-};

-

-PJ_DECL(void)	     pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size);

-PJ_DECL(unsigned)    pj_fifobuf_max_size (pj_fifobuf_t *fb);

-PJ_DECL(void*)	     pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size);

-PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf);

-PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf);

-

-PJ_END_DECL

-

-#endif	/* __PJ_FIFOBUF_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_FIFOBUF_H__
+#define __PJ_FIFOBUF_H__
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+typedef struct pj_fifobuf_t pj_fifobuf_t;
+struct pj_fifobuf_t
+{
+    char *first, *last;
+    char *ubegin, *uend;
+    int full;
+};
+
+PJ_DECL(void)	     pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size);
+PJ_DECL(unsigned)    pj_fifobuf_max_size (pj_fifobuf_t *fb);
+PJ_DECL(void*)	     pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size);
+PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf);
+PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf);
+
+PJ_END_DECL
+
+#endif	/* __PJ_FIFOBUF_H__ */
+
diff --git a/pjlib/include/pj/file_access.h b/pjlib/include/pj/file_access.h
index efa7121..5eed23d 100644
--- a/pjlib/include/pj/file_access.h
+++ b/pjlib/include/pj/file_access.h
@@ -1,108 +1,108 @@
-/* $Id */

-/* 

- * Copyright (C)2003-2006 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_FILE_ACCESS_H__

-#define __PJ_FILE_ACCESS_H__

-

-/**

- * @file file_access.h

- * @brief File manipulation and access.

- */

-#include <pj/types.h>

-

-PJ_BEGIN_DECL 

-

-/**

- * @defgroup PJ_FILE_ACCESS File Access

- * @ingroup PJ_IO

- * @{

- *

- */

-

-/**

- * This structure describes file information, to be obtained by

- * calling #pj_file_getstat(). The time information in this structure

- * is in local time.

- */

-typedef struct pj_file_stat

-{

-    pj_off_t        size;   /**< Total file size.               */

-    pj_time_val     atime;  /**< Time of last access.           */

-    pj_time_val     mtime;  /**< Time of last modification.     */

-    pj_time_val     ctime;  /**< Time of last creation.         */

-} pj_file_stat;

-

-

-/**

- * Returns non-zero if the specified file exists.

- *

- * @param filename      The file name.

- *

- * @return              Non-zero if the file exists.

- */

-PJ_DECL(pj_bool_t) pj_file_exists(const char *filename);

-

-/**

- * Returns the size of the file.

- *

- * @param filename      The file name.

- *

- * @return              The file size in bytes or -1 on error.

- */

-PJ_DECL(pj_off_t) pj_file_size(const char *filename);

-

-/**

- * Delete a file.

- *

- * @param filename      The filename.

- *

- * @return              PJ_SUCCESS on success or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_file_delete(const char *filename);

-

-/**

- * Move a \c oldname to \c newname. If \c newname already exists,

- * it will be overwritten.

- *

- * @param oldname       The file to rename.

- * @param newname       New filename to assign.

- *

- * @return              PJ_SUCCESS on success or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_file_move( const char *oldname, 

-                                   const char *newname);

-

-

-/**

- * Return information about the specified file. The time information in

- * the \c stat structure will be in local time.

- *

- * @param filename      The filename.

- * @param stat          Pointer to variable to receive file information.

- *

- * @return              PJ_SUCCESS on success or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_file_getstat(const char *filename, pj_file_stat *stat);

-

-

-/** @} */

-

-PJ_END_DECL

-

-

-#endif	/* __PJ_FILE_ACCESS_H__ */

+/* $Id */
+/* 
+ * Copyright (C)2003-2006 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_FILE_ACCESS_H__
+#define __PJ_FILE_ACCESS_H__
+
+/**
+ * @file file_access.h
+ * @brief File manipulation and access.
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL 
+
+/**
+ * @defgroup PJ_FILE_ACCESS File Access
+ * @ingroup PJ_IO
+ * @{
+ *
+ */
+
+/**
+ * This structure describes file information, to be obtained by
+ * calling #pj_file_getstat(). The time information in this structure
+ * is in local time.
+ */
+typedef struct pj_file_stat
+{
+    pj_off_t        size;   /**< Total file size.               */
+    pj_time_val     atime;  /**< Time of last access.           */
+    pj_time_val     mtime;  /**< Time of last modification.     */
+    pj_time_val     ctime;  /**< Time of last creation.         */
+} pj_file_stat;
+
+
+/**
+ * Returns non-zero if the specified file exists.
+ *
+ * @param filename      The file name.
+ *
+ * @return              Non-zero if the file exists.
+ */
+PJ_DECL(pj_bool_t) pj_file_exists(const char *filename);
+
+/**
+ * Returns the size of the file.
+ *
+ * @param filename      The file name.
+ *
+ * @return              The file size in bytes or -1 on error.
+ */
+PJ_DECL(pj_off_t) pj_file_size(const char *filename);
+
+/**
+ * Delete a file.
+ *
+ * @param filename      The filename.
+ *
+ * @return              PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_file_delete(const char *filename);
+
+/**
+ * Move a \c oldname to \c newname. If \c newname already exists,
+ * it will be overwritten.
+ *
+ * @param oldname       The file to rename.
+ * @param newname       New filename to assign.
+ *
+ * @return              PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_file_move( const char *oldname, 
+                                   const char *newname);
+
+
+/**
+ * Return information about the specified file. The time information in
+ * the \c stat structure will be in local time.
+ *
+ * @param filename      The filename.
+ * @param stat          Pointer to variable to receive file information.
+ *
+ * @return              PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_file_getstat(const char *filename, pj_file_stat *stat);
+
+
+/** @} */
+
+PJ_END_DECL
+
+
+#endif	/* __PJ_FILE_ACCESS_H__ */
diff --git a/pjlib/include/pj/file_io.h b/pjlib/include/pj/file_io.h
index e66c2cc..ea0e207 100644
--- a/pjlib/include/pj/file_io.h
+++ b/pjlib/include/pj/file_io.h
@@ -1,172 +1,172 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_FILE_IO_H__

-#define __PJ_FILE_IO_H__

-

-/**

- * @file file_io.h

- * @brief Simple file I/O abstraction.

- */

-#include <pj/types.h>

-

-PJ_BEGIN_DECL 

-

-/**

- * @defgroup PJ_FILE_IO File I/O

- * @ingroup PJ_IO

- * @{

- *

- * This file contains functionalities to perform file I/O. The file

- * I/O can be implemented with various back-end, either using native

- * file API or ANSI stream. 

- *

- * @section pj_file_size_limit_sec Size Limits

- *

- * There may be limitation on the size that can be handled by the

- * #pj_file_setpos() or #pj_file_getpos() functions. The API itself

- * uses 64-bit integer for the file offset/position (where available); 

- * however some backends (such as ANSI) may only support signed 32-bit 

- * offset resolution.

- *

- * Reading and writing operation uses signed 32-bit integer to indicate

- * the size.

- *

- *

- */

-

-/**

- * These enumerations are used when opening file. Values PJ_O_RDONLY,

- * PJ_O_WRONLY, and PJ_O_RDWR are mutually exclusive. Value PJ_O_APPEND

- * can only be used when the file is opened for writing. 

- */

-enum pj_file_access

-{

-    PJ_O_RDONLY     = 0x1101,   /**< Open file for reading.             */

-    PJ_O_WRONLY     = 0x1102,   /**< Open file for writing.             */

-    PJ_O_RDWR       = 0x1103,   /**< Open file for reading and writing. 

-                                     File will be truncated.            */

-    PJ_O_APPEND     = 0x1108,   /**< Append to existing file.           */

-};

-

-/**

- * The seek directive when setting the file position with #pj_file_setpos.

- */

-enum pj_file_seek_type

-{

-    PJ_SEEK_SET     = 0x1201,   /**< Offset from beginning of the file. */

-    PJ_SEEK_CUR     = 0x1202,   /**< Offset from current position.      */

-    PJ_SEEK_END     = 0x1203,   /**< Size of the file plus offset.      */

-};

-

-/**

- * Open the file as specified in \c pathname with the specified

- * mode, and return the handle in \c fd. All files will be opened

- * as binary.

- *

- * @param pool          Pool to allocate memory for the new file descriptor.

- * @param pathname      The file name to open.

- * @param flags         Open flags, which is bitmask combination of

- *                      #pj_file_access enum. The flag must be either

- *                      PJ_O_RDONLY, PJ_O_WRONLY, or PJ_O_RDWR. When file

- *                      writing is specified, existing file will be 

- *                      truncated unless PJ_O_APPEND is specified.

- * @param fd            The returned descriptor.

- *

- * @return              PJ_SUCCESS or the appropriate error code on error.

- */

-PJ_DECL(pj_status_t) pj_file_open(pj_pool_t *pool,

-                                  const char *pathname, 

-                                  unsigned flags,

-                                  pj_oshandle_t *fd);

-

-/**

- * Close an opened file descriptor.

- *

- * @param fd            The file descriptor.

- *

- * @return              PJ_SUCCESS or the appropriate error code on error.

- */

-PJ_DECL(pj_status_t) pj_file_close(pj_oshandle_t fd);

-

-/**

- * Write data with the specified size to an opened file.

- *

- * @param fd            The file descriptor.

- * @param data          Data to be written to the file.

- * @param size          On input, specifies the size of data to be written.

- *                      On return, it contains the number of data actually

- *                      written to the file.

- *

- * @return              PJ_SUCCESS or the appropriate error code on error.

- */

-PJ_DECL(pj_status_t) pj_file_write(pj_oshandle_t fd,

-                                   const void *data,

-                                   pj_ssize_t *size);

-

-/**

- * Read data from the specified file. When end-of-file condition is set,

- * this function will return PJ_SUCCESS but the size will contain zero.

- *

- * @param fd            The file descriptor.

- * @param data          Pointer to buffer to receive the data.

- * @param size          On input, specifies the maximum number of data to

- *                      read from the file. On output, it contains the size

- *                      of data actually read from the file. It will contain

- *                      zero when EOF occurs.

- *

- * @return              PJ_SUCCESS or the appropriate error code on error.

- *                      When EOF occurs, the return is PJ_SUCCESS but size

- *                      will report zero.

- */

-PJ_DECL(pj_status_t) pj_file_read(pj_oshandle_t fd,

-                                  void *data,

-                                  pj_ssize_t *size);

-

-/**

- * Set file position to new offset according to directive \c whence.

- *

- * @param fd            The file descriptor.

- * @param offset        The new file position to set.

- * @param whence        The directive.

- *

- * @return              PJ_SUCCESS or the appropriate error code on error.

- */

-PJ_DECL(pj_status_t) pj_file_setpos(pj_oshandle_t fd,

-                                    pj_off_t offset,

-                                    enum pj_file_seek_type whence);

-

-/**

- * Get current file position.

- *

- * @param fd            The file descriptor.

- * @param pos           On return contains the file position as measured

- *                      from the beginning of the file.

- *

- * @return              PJ_SUCCESS or the appropriate error code on error.

- */

-PJ_DECL(pj_status_t) pj_file_getpos(pj_oshandle_t fd,

-                                    pj_off_t *pos);

-

-/** @} */

-

-

-PJ_END_DECL

-

-#endif  /* __PJ_FILE_IO_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_FILE_IO_H__
+#define __PJ_FILE_IO_H__
+
+/**
+ * @file file_io.h
+ * @brief Simple file I/O abstraction.
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL 
+
+/**
+ * @defgroup PJ_FILE_IO File I/O
+ * @ingroup PJ_IO
+ * @{
+ *
+ * This file contains functionalities to perform file I/O. The file
+ * I/O can be implemented with various back-end, either using native
+ * file API or ANSI stream. 
+ *
+ * @section pj_file_size_limit_sec Size Limits
+ *
+ * There may be limitation on the size that can be handled by the
+ * #pj_file_setpos() or #pj_file_getpos() functions. The API itself
+ * uses 64-bit integer for the file offset/position (where available); 
+ * however some backends (such as ANSI) may only support signed 32-bit 
+ * offset resolution.
+ *
+ * Reading and writing operation uses signed 32-bit integer to indicate
+ * the size.
+ *
+ *
+ */
+
+/**
+ * These enumerations are used when opening file. Values PJ_O_RDONLY,
+ * PJ_O_WRONLY, and PJ_O_RDWR are mutually exclusive. Value PJ_O_APPEND
+ * can only be used when the file is opened for writing. 
+ */
+enum pj_file_access
+{
+    PJ_O_RDONLY     = 0x1101,   /**< Open file for reading.             */
+    PJ_O_WRONLY     = 0x1102,   /**< Open file for writing.             */
+    PJ_O_RDWR       = 0x1103,   /**< Open file for reading and writing. 
+                                     File will be truncated.            */
+    PJ_O_APPEND     = 0x1108,   /**< Append to existing file.           */
+};
+
+/**
+ * The seek directive when setting the file position with #pj_file_setpos.
+ */
+enum pj_file_seek_type
+{
+    PJ_SEEK_SET     = 0x1201,   /**< Offset from beginning of the file. */
+    PJ_SEEK_CUR     = 0x1202,   /**< Offset from current position.      */
+    PJ_SEEK_END     = 0x1203,   /**< Size of the file plus offset.      */
+};
+
+/**
+ * Open the file as specified in \c pathname with the specified
+ * mode, and return the handle in \c fd. All files will be opened
+ * as binary.
+ *
+ * @param pool          Pool to allocate memory for the new file descriptor.
+ * @param pathname      The file name to open.
+ * @param flags         Open flags, which is bitmask combination of
+ *                      #pj_file_access enum. The flag must be either
+ *                      PJ_O_RDONLY, PJ_O_WRONLY, or PJ_O_RDWR. When file
+ *                      writing is specified, existing file will be 
+ *                      truncated unless PJ_O_APPEND is specified.
+ * @param fd            The returned descriptor.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_open(pj_pool_t *pool,
+                                  const char *pathname, 
+                                  unsigned flags,
+                                  pj_oshandle_t *fd);
+
+/**
+ * Close an opened file descriptor.
+ *
+ * @param fd            The file descriptor.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_close(pj_oshandle_t fd);
+
+/**
+ * Write data with the specified size to an opened file.
+ *
+ * @param fd            The file descriptor.
+ * @param data          Data to be written to the file.
+ * @param size          On input, specifies the size of data to be written.
+ *                      On return, it contains the number of data actually
+ *                      written to the file.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_write(pj_oshandle_t fd,
+                                   const void *data,
+                                   pj_ssize_t *size);
+
+/**
+ * Read data from the specified file. When end-of-file condition is set,
+ * this function will return PJ_SUCCESS but the size will contain zero.
+ *
+ * @param fd            The file descriptor.
+ * @param data          Pointer to buffer to receive the data.
+ * @param size          On input, specifies the maximum number of data to
+ *                      read from the file. On output, it contains the size
+ *                      of data actually read from the file. It will contain
+ *                      zero when EOF occurs.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code on error.
+ *                      When EOF occurs, the return is PJ_SUCCESS but size
+ *                      will report zero.
+ */
+PJ_DECL(pj_status_t) pj_file_read(pj_oshandle_t fd,
+                                  void *data,
+                                  pj_ssize_t *size);
+
+/**
+ * Set file position to new offset according to directive \c whence.
+ *
+ * @param fd            The file descriptor.
+ * @param offset        The new file position to set.
+ * @param whence        The directive.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_setpos(pj_oshandle_t fd,
+                                    pj_off_t offset,
+                                    enum pj_file_seek_type whence);
+
+/**
+ * Get current file position.
+ *
+ * @param fd            The file descriptor.
+ * @param pos           On return contains the file position as measured
+ *                      from the beginning of the file.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code on error.
+ */
+PJ_DECL(pj_status_t) pj_file_getpos(pj_oshandle_t fd,
+                                    pj_off_t *pos);
+
+/** @} */
+
+
+PJ_END_DECL
+
+#endif  /* __PJ_FILE_IO_H__ */
+
diff --git a/pjlib/include/pj/guid.h b/pjlib/include/pj/guid.h
index 2fc9656..9c6d30b 100644
--- a/pjlib/include/pj/guid.h
+++ b/pjlib/include/pj/guid.h
@@ -1,91 +1,91 @@
-/* $Id */

-/* 

- * Copyright (C)2003-2006 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_GUID_H__

-#define __PJ_GUID_H__

-

-

-/**

- * @file guid.h

- * @brief GUID Globally Unique Identifier.

- */

-#include <pj/types.h>

-

-

-PJ_BEGIN_DECL

-

-

-/**

- * @defgroup PJ_DS Data Structure.

- * @ingroup PJ

- */

-/**

- * @defgroup PJ_GUID Globally Unique Identifier

- * @ingroup PJ_DS

- * @{

- *

- * This module provides API to create string that is globally unique.

- * If application doesn't require that strong requirement, it can just

- * use #pj_create_random_string() instead.

- */

-

-

-/**

- * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is

- * dependent on the algorithm used internally to generate the GUID string.

- * If real GUID generator is used, then the length will be 128bit or 

- * 32 bytes. If shadow GUID generator is used, then the length

- * will be 20 bytes. Application should not assume which algorithm will

- * be used by GUID generator.

- */

-extern const unsigned PJ_GUID_STRING_LENGTH;

-

-/**

- * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string,

- * regardless of which algorithm to use.

- */

-#define PJ_GUID_MAX_LENGTH  32

-

-/**

- * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH

- * characters. Caller is responsible for preallocating the storage used

- * in the string.

- *

- * @param str       The string to store the result.

- *

- * @return          The string.

- */

-PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str);

-

-/**

- * Generate a unique string.

- *

- * @param pool	    Pool to allocate memory from.

- * @param str	    The string.

- */

-PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str);

-

-

-/**

- * @}

- */

-

-PJ_END_DECL

-

-#endif/* __PJ_GUID_H__ */

-

+/* $Id */
+/* 
+ * Copyright (C)2003-2006 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_GUID_H__
+#define __PJ_GUID_H__
+
+
+/**
+ * @file guid.h
+ * @brief GUID Globally Unique Identifier.
+ */
+#include <pj/types.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_DS Data Structure.
+ * @ingroup PJ
+ */
+/**
+ * @defgroup PJ_GUID Globally Unique Identifier
+ * @ingroup PJ_DS
+ * @{
+ *
+ * This module provides API to create string that is globally unique.
+ * If application doesn't require that strong requirement, it can just
+ * use #pj_create_random_string() instead.
+ */
+
+
+/**
+ * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is
+ * dependent on the algorithm used internally to generate the GUID string.
+ * If real GUID generator is used, then the length will be 128bit or 
+ * 32 bytes. If shadow GUID generator is used, then the length
+ * will be 20 bytes. Application should not assume which algorithm will
+ * be used by GUID generator.
+ */
+extern const unsigned PJ_GUID_STRING_LENGTH;
+
+/**
+ * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string,
+ * regardless of which algorithm to use.
+ */
+#define PJ_GUID_MAX_LENGTH  32
+
+/**
+ * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH
+ * characters. Caller is responsible for preallocating the storage used
+ * in the string.
+ *
+ * @param str       The string to store the result.
+ *
+ * @return          The string.
+ */
+PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str);
+
+/**
+ * Generate a unique string.
+ *
+ * @param pool	    Pool to allocate memory from.
+ * @param str	    The string.
+ */
+PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str);
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif/* __PJ_GUID_H__ */
+
diff --git a/pjlib/include/pj/hash.h b/pjlib/include/pj/hash.h
index cee8e71..41c89bc 100644
--- a/pjlib/include/pj/hash.h
+++ b/pjlib/include/pj/hash.h
@@ -1,171 +1,171 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_HASH_H__

-#define __PJ_HASH_H__

-

-/**

- * @file hash.h

- * @brief Hash Table.

- */

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_HASH Hash Table

- * @ingroup PJ_DS

- * @{

- * A hash table is a dictionary in which keys are mapped to array positions by

- * hash functions. Having the keys of more than one item map to the same 

- * position is called a collision. In this library, we will chain the nodes

- * that have the same key in a list.

- */

-

-/**

- * If this constant is used as keylen, then the key is interpreted as

- * NULL terminated string.

- */

-#define PJ_HASH_KEY_STRING	((unsigned)-1)

-

-/**

- * This is the function that is used by the hash table to calculate hash value

- * of the specified key.

- *

- * @param hval	    the initial hash value, or zero.

- * @param key	    the key to calculate.

- * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to treat 

- *		    the key as null terminated string.

- *

- * @return          the hash value.

- */

-PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, 

-				  const void *key, unsigned keylen);

-

-

-/**

- * Convert the key to lowercase and calculate the hash value. The resulting

- * string is stored in \c result.

- *

- * @param hval      The initial hash value, normally zero.

- * @param result    Buffer to store the result, which must be enough to hold

- *                  the string.

- * @param key       The input key to be converted and calculated.

- *

- * @return          The hash value.

- */

-PJ_DECL(pj_uint32_t) pj_hash_calc_tolower(pj_uint32_t hval,

-                                          char *result,

-                                          const pj_str_t *key);

-

-/**

- * Create a hash table with the specified 'bucket' size.

- *

- * @param pool	the pool from which the hash table will be allocated from.

- * @param size	the bucket size, which will be round-up to the nearest 2^n+1

- *

- * @return the hash table.

- */

-PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size);

-

-

-/**

- * Get the value associated with the specified key.

- *

- * @param ht	    the hash table.

- * @param key	    the key to look for.

- * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the

- *		    string length of the key.

- *

- * @return the value associated with the key, or NULL if the key is not found.

- */

-PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,

-			     const void *key, unsigned keylen );

-

-

-/**

- * Associate/disassociate a value with the specified key.

- *

- * @param pool	    the pool to allocate the new entry if a new entry has to be

- *		    created.

- * @param ht	    the hash table.

- * @param key	    the key.

- * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the 

- *		    string length of the key.

- * @param value	    value to be associated, or NULL to delete the entry with

- *		    the specified key.

- */

-PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,

-			   const void *key, unsigned keylen,

-			   void *value );

-

-/**

- * Get the total number of entries in the hash table.

- *

- * @param ht	the hash table.

- *

- * @return the number of entries in the hash table.

- */

-PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht );

-

-

-/**

- * Get the iterator to the first element in the hash table. 

- *

- * @param ht	the hash table.

- * @param it	the iterator for iterating hash elements.

- *

- * @return the iterator to the hash element, or NULL if no element presents.

- */

-PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,

-					    pj_hash_iterator_t *it );

-

-

-/**

- * Get the next element from the iterator.

- *

- * @param ht	the hash table.

- * @param it	the hash iterator.

- *

- * @return the next iterator, or NULL if there's no more element.

- */

-PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 

-					   pj_hash_iterator_t *it );

-

-/**

- * Get the value associated with a hash iterator.

- *

- * @param ht	the hash table.

- * @param it	the hash iterator.

- *

- * @return the value associated with the current element in iterator.

- */

-PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht,

-			     pj_hash_iterator_t *it );

-

-

-/**

- * @}

- */

-

-PJ_END_DECL

-

-#endif

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_HASH_H__
+#define __PJ_HASH_H__
+
+/**
+ * @file hash.h
+ * @brief Hash Table.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_HASH Hash Table
+ * @ingroup PJ_DS
+ * @{
+ * A hash table is a dictionary in which keys are mapped to array positions by
+ * hash functions. Having the keys of more than one item map to the same 
+ * position is called a collision. In this library, we will chain the nodes
+ * that have the same key in a list.
+ */
+
+/**
+ * If this constant is used as keylen, then the key is interpreted as
+ * NULL terminated string.
+ */
+#define PJ_HASH_KEY_STRING	((unsigned)-1)
+
+/**
+ * This is the function that is used by the hash table to calculate hash value
+ * of the specified key.
+ *
+ * @param hval	    the initial hash value, or zero.
+ * @param key	    the key to calculate.
+ * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to treat 
+ *		    the key as null terminated string.
+ *
+ * @return          the hash value.
+ */
+PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, 
+				  const void *key, unsigned keylen);
+
+
+/**
+ * Convert the key to lowercase and calculate the hash value. The resulting
+ * string is stored in \c result.
+ *
+ * @param hval      The initial hash value, normally zero.
+ * @param result    Buffer to store the result, which must be enough to hold
+ *                  the string.
+ * @param key       The input key to be converted and calculated.
+ *
+ * @return          The hash value.
+ */
+PJ_DECL(pj_uint32_t) pj_hash_calc_tolower(pj_uint32_t hval,
+                                          char *result,
+                                          const pj_str_t *key);
+
+/**
+ * Create a hash table with the specified 'bucket' size.
+ *
+ * @param pool	the pool from which the hash table will be allocated from.
+ * @param size	the bucket size, which will be round-up to the nearest 2^n+1
+ *
+ * @return the hash table.
+ */
+PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size);
+
+
+/**
+ * Get the value associated with the specified key.
+ *
+ * @param ht	    the hash table.
+ * @param key	    the key to look for.
+ * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the
+ *		    string length of the key.
+ *
+ * @return the value associated with the key, or NULL if the key is not found.
+ */
+PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
+			     const void *key, unsigned keylen );
+
+
+/**
+ * Associate/disassociate a value with the specified key.
+ *
+ * @param pool	    the pool to allocate the new entry if a new entry has to be
+ *		    created.
+ * @param ht	    the hash table.
+ * @param key	    the key.
+ * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the 
+ *		    string length of the key.
+ * @param value	    value to be associated, or NULL to delete the entry with
+ *		    the specified key.
+ */
+PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
+			   const void *key, unsigned keylen,
+			   void *value );
+
+/**
+ * Get the total number of entries in the hash table.
+ *
+ * @param ht	the hash table.
+ *
+ * @return the number of entries in the hash table.
+ */
+PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht );
+
+
+/**
+ * Get the iterator to the first element in the hash table. 
+ *
+ * @param ht	the hash table.
+ * @param it	the iterator for iterating hash elements.
+ *
+ * @return the iterator to the hash element, or NULL if no element presents.
+ */
+PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,
+					    pj_hash_iterator_t *it );
+
+
+/**
+ * Get the next element from the iterator.
+ *
+ * @param ht	the hash table.
+ * @param it	the hash iterator.
+ *
+ * @return the next iterator, or NULL if there's no more element.
+ */
+PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 
+					   pj_hash_iterator_t *it );
+
+/**
+ * Get the value associated with a hash iterator.
+ *
+ * @param ht	the hash table.
+ * @param it	the hash iterator.
+ *
+ * @return the value associated with the current element in iterator.
+ */
+PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht,
+			     pj_hash_iterator_t *it );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif
+
+
diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h
index 26484ca..86a5309 100644
--- a/pjlib/include/pj/ioqueue.h
+++ b/pjlib/include/pj/ioqueue.h
@@ -1,665 +1,665 @@
-/* $Id$

- */

-/* 

- * Copyright (C)2003-2006 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_IOQUEUE_H__

-#define __PJ_IOQUEUE_H__

-

-/**

- * @file ioqueue.h

- * @brief I/O Dispatching Mechanism

- */

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_IO Input/Output

- * @brief Input/Output

- * @ingroup PJ_OS

- *

- * This section contains API building blocks to perform network I/O and 

- * communications. If provides:

- *  - @ref PJ_SOCK

- *\n

- *    A highly portable socket abstraction, runs on all kind of

- *    network APIs such as standard BSD socket, Windows socket, Linux

- *    \b kernel socket, PalmOS networking API, etc.

- *

- *  - @ref pj_addr_resolve

- *\n

- *    Portable address resolution, which implements #pj_gethostbyname().

- *

- *  - @ref PJ_SOCK_SELECT

- *\n

- *    A portable \a select() like API (#pj_sock_select()) which can be

- *    implemented with various back-ends.

- *

- *  - @ref PJ_IOQUEUE

- *\n

- *    Framework for dispatching network events.

- *

- * For more information see the modules below.

- */

-

-/**

- * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue

- * @ingroup PJ_IO

- * @{

- *

- * I/O Queue provides API for performing asynchronous I/O operations. It

- * conforms to proactor pattern, which allows application to submit an

- * asynchronous operation and to be notified later when the operation has

- * completed.

- *

- * The I/O Queue can work on both socket and file descriptors. For 

- * asynchronous file operations however, one must make sure that the correct

- * file I/O back-end is used, because not all file I/O back-end can be

- * used with the ioqueue. Please see \ref PJ_FILE_IO for more details.

- *

- * The framework works natively in platforms where asynchronous operation API

- * exists, such as in Windows NT with IoCompletionPort/IOCP. In other 

- * platforms, the I/O queue abstracts the operating system's event poll API

- * to provide semantics similar to IoCompletionPort with minimal penalties

- * (i.e. per ioqueue and per handle mutex protection).

- *

- * The I/O queue provides more than just unified abstraction. It also:

- *  - makes sure that the operation uses the most effective way to utilize

- *    the underlying mechanism, to achieve the maximum theoritical

- *    throughput possible on a given platform.

- *  - choose the most efficient mechanism for event polling on a given

- *    platform.

- *

- * Currently, the I/O Queue is implemented using:

- *  - <tt><b>select()</b></tt>, as the common denominator, but the least 

- *    efficient. Also the number of descriptor is limited to 

- *    \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64).

- *  - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode), 

- *    a much faster replacement for select() on Linux (and more importantly

- *    doesn't have limitation on number of descriptors).

- *  - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most 

- *    efficient way to dispatch events in Windows NT based OSes, and most 

- *    importantly, it doesn't have the limit on how many handles to monitor.

- *    And it works with files (not only sockets) as well.

- *

- *

- * \section pj_ioqueue_concurrency_sec Concurrency Rules

- *

- * The items below describe rules that must be obeyed when using the I/O 

- * queue, with regard to concurrency:

- *  - simultaneous operations (by different threads) to different key is safe.

- *  - simultaneous operations to the same key is also safe, except

- *    <b>unregistration</b>, which is described below.

- *  - <b>care must be taken when unregistering a key</b> from the

- *    ioqueue. Application must take care that when one thread is issuing

- *    an unregistration, other thread is not simultaneously invoking an

- *    operation <b>to the same key</b>.

- *\n

- *    This happens because the ioqueue functions are working with a pointer

- *    to the key, and there is a possible race condition where the pointer

- *    has been rendered invalid by other threads before the ioqueue has a

- *    chance to acquire mutex on it.

- *

- * \section pj_ioqeuue_examples_sec Examples

- *

- * For some examples on how to use the I/O Queue, please see:

- *

- *  - \ref page_pjlib_ioqueue_tcp_test

- *  - \ref page_pjlib_ioqueue_udp_test

- *  - \ref page_pjlib_ioqueue_perf_test

- */

-

-

-/**

- * This structure describes operation specific key to be submitted to

- * I/O Queue when performing the asynchronous operation. This key will

- * be returned to the application when completion callback is called.

- *

- * Application normally wants to attach it's specific data in the

- * \c user_data field so that it can keep track of which operation has

- * completed when the callback is called. Alternatively, application can

- * also extend this struct to include its data, because the pointer that

- * is returned in the completion callback will be exactly the same as

- * the pointer supplied when the asynchronous function is called.

- */

-typedef struct pj_ioqueue_op_key_t

-{ 

-    void *internal__[32];           /**< Internal I/O Queue data.   */

-    void *user_data;                /**< Application data.          */

-} pj_ioqueue_op_key_t;

-

-/**

- * This structure describes the callbacks to be called when I/O operation

- * completes.

- */

-typedef struct pj_ioqueue_callback

-{

-    /**

-     * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom

-     * completes.

-     *

-     * @param key	    The key.

-     * @param op_key        Operation key.

-     * @param bytes_read    >= 0 to indicate the amount of data read, 

-     *                      otherwise negative value containing the error

-     *                      code. To obtain the pj_status_t error code, use

-     *                      (pj_status_t code = -bytes_read).

-     */

-    void (*on_read_complete)(pj_ioqueue_key_t *key, 

-                             pj_ioqueue_op_key_t *op_key, 

-                             pj_ssize_t bytes_read);

-

-    /**

-     * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto

-     * completes.

-     *

-     * @param key	    The key.

-     * @param op_key        Operation key.

-     * @param bytes_sent    >= 0 to indicate the amount of data written, 

-     *                      otherwise negative value containing the error

-     *                      code. To obtain the pj_status_t error code, use

-     *                      (pj_status_t code = -bytes_sent).

-     */

-    void (*on_write_complete)(pj_ioqueue_key_t *key, 

-                              pj_ioqueue_op_key_t *op_key, 

-                              pj_ssize_t bytes_sent);

-

-    /**

-     * This callback is called when #pj_ioqueue_accept completes.

-     *

-     * @param key	    The key.

-     * @param op_key        Operation key.

-     * @param sock          Newly connected socket.

-     * @param status	    Zero if the operation completes successfully.

-     */

-    void (*on_accept_complete)(pj_ioqueue_key_t *key, 

-                               pj_ioqueue_op_key_t *op_key, 

-                               pj_sock_t sock, 

-                               pj_status_t status);

-

-    /**

-     * This callback is called when #pj_ioqueue_connect completes.

-     *

-     * @param key	    The key.

-     * @param status	    PJ_SUCCESS if the operation completes successfully.

-     */

-    void (*on_connect_complete)(pj_ioqueue_key_t *key, 

-                                pj_status_t status);

-} pj_ioqueue_callback;

-

-

-/**

- * Types of pending I/O Queue operation. This enumeration is only used

- * internally within the ioqueue.

- */

-typedef enum pj_ioqueue_operation_e

-{

-    PJ_IOQUEUE_OP_NONE		= 0,	/**< No operation.          */

-    PJ_IOQUEUE_OP_READ		= 1,	/**< read() operation.      */

-    PJ_IOQUEUE_OP_RECV          = 2,    /**< recv() operation.      */

-    PJ_IOQUEUE_OP_RECV_FROM	= 4,	/**< recvfrom() operation.  */

-    PJ_IOQUEUE_OP_WRITE		= 8,	/**< write() operation.     */

-    PJ_IOQUEUE_OP_SEND          = 16,   /**< send() operation.      */

-    PJ_IOQUEUE_OP_SEND_TO	= 32,	/**< sendto() operation.    */

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-    PJ_IOQUEUE_OP_ACCEPT	= 64,	/**< accept() operation.    */

-    PJ_IOQUEUE_OP_CONNECT	= 128,	/**< connect() operation.   */

-#endif	/* PJ_HAS_TCP */

-} pj_ioqueue_operation_e;

-

-

-/**

- * This macro specifies the maximum number of events that can be

- * processed by the ioqueue on a single poll cycle, on implementation

- * that supports it. The value is only meaningfull when specified

- * during PJLIB build.

- */

-#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL

-#   define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL     (16)

-#endif

-

-/**

- * When this flag is specified in ioqueue's recv() or send() operations,

- * the ioqueue will always mark the operation as asynchronous.

- */

-#define PJ_IOQUEUE_ALWAYS_ASYNC	    ((pj_uint32_t)1 << (pj_uint32_t)31)

-

-/**

- * Return the name of the ioqueue implementation.

- *

- * @return		Implementation name.

- */

-PJ_DECL(const char*) pj_ioqueue_name(void);

-

-

-/**

- * Create a new I/O Queue framework.

- *

- * @param pool		The pool to allocate the I/O queue structure. 

- * @param max_fd	The maximum number of handles to be supported, which 

- *			should not exceed PJ_IOQUEUE_MAX_HANDLES.

- * @param ioqueue	Pointer to hold the newly created I/O Queue.

- *

- * @return		PJ_SUCCESS on success.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

-					pj_size_t max_fd,

-					pj_ioqueue_t **ioqueue);

-

-/**

- * Destroy the I/O queue.

- *

- * @param ioque	        The I/O Queue to be destroyed.

- *

- * @return              PJ_SUCCESS if success.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque );

-

-/**

- * Set the lock object to be used by the I/O Queue. This function can only

- * be called right after the I/O queue is created, before any handle is

- * registered to the I/O queue.

- *

- * Initially the I/O queue is created with non-recursive mutex protection. 

- * Applications can supply alternative lock to be used by calling this 

- * function.

- *

- * @param ioque         The ioqueue instance.

- * @param lock          The lock to be used by the ioqueue.

- * @param auto_delete   In non-zero, the lock will be deleted by the ioqueue.

- *

- * @return              PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 

-					  pj_lock_t *lock,

-					  pj_bool_t auto_delete );

-

-/**

- * Register a socket to the I/O queue framework. 

- * When a socket is registered to the IOQueue, it may be modified to use

- * non-blocking IO. If it is modified, there is no guarantee that this 

- * modification will be restored after the socket is unregistered.

- *

- * @param pool	    To allocate the resource for the specified handle, 

- *		    which must be valid until the handle/key is unregistered 

- *		    from I/O Queue.

- * @param ioque	    The I/O Queue.

- * @param sock	    The socket.

- * @param user_data User data to be associated with the key, which can be

- *		    retrieved later.

- * @param cb	    Callback to be called when I/O operation completes. 

- * @param key       Pointer to receive the key to be associated with this

- *                  socket. Subsequent I/O queue operation will need this

- *                  key.

- *

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

-					       pj_ioqueue_t *ioque,

-					       pj_sock_t sock,

-					       void *user_data,

-					       const pj_ioqueue_callback *cb,

-                                               pj_ioqueue_key_t **key );

-

-/**

- * Unregister from the I/O Queue framework. Caller must make sure that

- * the key doesn't have any pending operations before calling this function,

- * by calling #pj_ioqueue_is_pending() for all previously submitted

- * operations except asynchronous connect, and if necessary call

- * #pj_ioqueue_post_completion() to cancel the pending operations.

- *

- * Note that asynchronous connect operation will automatically be 

- * cancelled during the unregistration.

- *

- * @param key	    The key that was previously obtained from registration.

- *

- * @return          PJ_SUCCESS on success or the error code.

- *

- * @see pj_ioqueue_is_pending

- */

-PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );

-

-

-/**

- * Get user data associated with an ioqueue key.

- *

- * @param key	    The key that was previously obtained from registration.

- *

- * @return          The user data associated with the descriptor, or NULL 

- *                  on error or if no data is associated with the key during

- *                  registration.

- */

-PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key );

-

-/**

- * Set or change the user data to be associated with the file descriptor or

- * handle or socket descriptor.

- *

- * @param key	    The key that was previously obtained from registration.

- * @param user_data User data to be associated with the descriptor.

- * @param old_data  Optional parameter to retrieve the old user data.

- *

- * @return          PJ_SUCCESS on success or the error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,

-                                               void *user_data,

-                                               void **old_data);

-

-

-/**

- * Initialize operation key.

- *

- * @param op_key    The operation key to be initialied.

- * @param size	    The size of the operation key.

- */

-PJ_DECL(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,

-				      pj_size_t size );

-

-/**

- * Check if operation is pending on the specified operation key.

- * The \c op_key must have been initialized with #pj_ioqueue_op_key_init() 

- * or submitted as pending operation before, or otherwise the result 

- * is undefined.

- *

- * @param key       The key.

- * @param op_key    The operation key, previously submitted to any of

- *                  the I/O functions and has returned PJ_EPENDING.

- *

- * @return          Non-zero if operation is still pending.

- */

-PJ_DECL(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,

-                                          pj_ioqueue_op_key_t *op_key );

-

-

-/**

- * Post completion status to the specified operation key and call the

- * appropriate callback. When the callback is called, the number of bytes 

- * received in read/write callback or the status in accept/connect callback

- * will be set from the \c bytes_status parameter.

- *

- * @param key           The key.

- * @param op_key        Pending operation key.

- * @param bytes_status  Number of bytes or status to be set. A good value

- *                      to put here is -PJ_ECANCELLED.

- *

- * @return              PJ_SUCCESS if completion status has been successfully

- *                      sent.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,

-                                                 pj_ioqueue_op_key_t *op_key,

-                                                 pj_ssize_t bytes_status );

-

-

-

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-/**

- * Instruct I/O Queue to accept incoming connection on the specified 

- * listening socket. This function will return immediately (i.e. non-blocking)

- * regardless whether a connection is immediately available. If the function

- * can't complete immediately, the caller will be notified about the incoming

- * connection when it calls pj_ioqueue_poll(). If a new connection is

- * immediately available, the function returns PJ_SUCCESS with the new

- * connection; in this case, the callback WILL NOT be called.

- *

- * @param key	    The key which registered to the server socket.

- * @param op_key    An operation specific key to be associated with the

- *                  pending operation, so that application can keep track of

- *                  which operation has been completed when the callback is

- *                  called.

- * @param new_sock  Argument which contain pointer to receive the new socket

- *                  for the incoming connection.

- * @param local	    Optional argument which contain pointer to variable to 

- *                  receive local address.

- * @param remote    Optional argument which contain pointer to variable to 

- *                  receive the remote address.

- * @param addrlen   On input, contains the length of the buffer for the

- *		    address, and on output, contains the actual length of the

- *		    address. This argument is optional.

- * @return

- *  - PJ_SUCCESS    When connection is available immediately, and the 

- *                  parameters will be updated to contain information about 

- *                  the new connection. In this case, a completion callback

- *                  WILL NOT be called.

- *  - PJ_EPENDING   If no connection is available immediately. When a new

- *                  connection arrives, the callback will be called.

- *  - non-zero      which indicates the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,

-                                        pj_ioqueue_op_key_t *op_key,

-					pj_sock_t *sock,

-					pj_sockaddr_t *local,

-					pj_sockaddr_t *remote,

-					int *addrlen );

-

-/**

- * Initiate non-blocking socket connect. If the socket can NOT be connected

- * immediately, asynchronous connect() will be scheduled and caller will be

- * notified via completion callback when it calls pj_ioqueue_poll(). If

- * socket is connected immediately, the function returns PJ_SUCCESS and

- * completion callback WILL NOT be called.

- *

- * @param key	    The key associated with TCP socket

- * @param addr	    The remote address.

- * @param addrlen   The remote address length.

- *

- * @return

- *  - PJ_SUCCESS    If socket is connected immediately. In this case, the

- *                  completion callback WILL NOT be called.

- *  - PJ_EPENDING   If operation is queued, or 

- *  - non-zero      Indicates the error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,

-					 const pj_sockaddr_t *addr,

-					 int addrlen );

-

-#endif	/* PJ_HAS_TCP */

-

-/**

- * Poll the I/O Queue for completed events.

- *

- * @param ioque		the I/O Queue.

- * @param timeout	polling timeout, or NULL if the thread wishes to wait

- *			indefinetely for the event.

- *

- * @return 

- *  - zero if timed out (no event).

- *  - (<0) if error occured during polling. Callback will NOT be called.

- *  - (>1) to indicate numbers of events. Callbacks have been called.

- */

-PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque,

-			      const pj_time_val *timeout);

-

-

-/**

- * Instruct the I/O Queue to read from the specified handle. This function

- * returns immediately (i.e. non-blocking) regardless whether some data has 

- * been transfered. If the operation can't complete immediately, caller will 

- * be notified about the completion when it calls pj_ioqueue_poll(). If data

- * is immediately available, the function will return PJ_SUCCESS and the

- * callback WILL NOT be called.

- *

- * @param key	    The key that uniquely identifies the handle.

- * @param op_key    An operation specific key to be associated with the

- *                  pending operation, so that application can keep track of

- *                  which operation has been completed when the callback is

- *                  called. Caller must make sure that this key remains 

- *                  valid until the function completes.

- * @param buffer    The buffer to hold the read data. The caller MUST make sure

- *		    that this buffer remain valid until the framework completes

- *		    reading the handle.

- * @param length    On input, it specifies the size of the buffer. If data is

- *                  available to be read immediately, the function returns

- *                  PJ_SUCCESS and this argument will be filled with the

- *                  amount of data read. If the function is pending, caller

- *                  will be notified about the amount of data read in the

- *                  callback. This parameter can point to local variable in

- *                  caller's stack and doesn't have to remain valid for the

- *                  duration of pending operation.

- * @param flags     Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then

- *		    the function will never return PJ_SUCCESS.

- *

- * @return

- *  - PJ_SUCCESS    If immediate data has been received in the buffer. In this

- *                  case, the callback WILL NOT be called.

- *  - PJ_EPENDING   If the operation has been queued, and the callback will be

- *                  called when data has been received.

- *  - non-zero      The return value indicates the error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,

-                                      pj_ioqueue_op_key_t *op_key,

-				      void *buffer,

-				      pj_ssize_t *length,

-				      pj_uint32_t flags );

-

-/**

- * This function behaves similarly as #pj_ioqueue_recv(), except that it is

- * normally called for socket, and the remote address will also be returned

- * along with the data. Caller MUST make sure that both buffer and addr

- * remain valid until the framework completes reading the data.

- *

- * @param key	    The key that uniquely identifies the handle.

- * @param op_key    An operation specific key to be associated with the

- *                  pending operation, so that application can keep track of

- *                  which operation has been completed when the callback is

- *                  called.

- * @param buffer    The buffer to hold the read data. The caller MUST make sure

- *		    that this buffer remain valid until the framework completes

- *		    reading the handle.

- * @param length    On input, it specifies the size of the buffer. If data is

- *                  available to be read immediately, the function returns

- *                  PJ_SUCCESS and this argument will be filled with the

- *                  amount of data read. If the function is pending, caller

- *                  will be notified about the amount of data read in the

- *                  callback. This parameter can point to local variable in

- *                  caller's stack and doesn't have to remain valid for the

- *                  duration of pending operation.

- * @param flags     Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then

- *		    the function will never return PJ_SUCCESS.

- * @param addr      Optional Pointer to buffer to receive the address.

- * @param addrlen   On input, specifies the length of the address buffer.

- *                  On output, it will be filled with the actual length of

- *                  the address. This argument can be NULL if \c addr is not

- *                  specified.

- *

- * @return

- *  - PJ_SUCCESS    If immediate data has been received. In this case, the 

- *		    callback must have been called before this function 

- *		    returns, and no pending operation is scheduled.

- *  - PJ_EPENDING   If the operation has been queued.

- *  - non-zero      The return value indicates the error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,

-                                          pj_ioqueue_op_key_t *op_key,

-					  void *buffer,

-					  pj_ssize_t *length,

-                                          pj_uint32_t flags,

-					  pj_sockaddr_t *addr,

-					  int *addrlen);

-

-/**

- * Instruct the I/O Queue to write to the handle. This function will return

- * immediately (i.e. non-blocking) regardless whether some data has been 

- * transfered. If the function can't complete immediately, the caller will

- * be notified about the completion when it calls pj_ioqueue_poll(). If 

- * operation completes immediately and data has been transfered, the function

- * returns PJ_SUCCESS and the callback will NOT be called.

- *

- * @param key	    The key that identifies the handle.

- * @param op_key    An operation specific key to be associated with the

- *                  pending operation, so that application can keep track of

- *                  which operation has been completed when the callback is

- *                  called.

- * @param data	    The data to send. Caller MUST make sure that this buffer 

- *		    remains valid until the write operation completes.

- * @param length    On input, it specifies the length of data to send. When

- *                  data was sent immediately, this function returns PJ_SUCCESS

- *                  and this parameter contains the length of data sent. If

- *                  data can not be sent immediately, an asynchronous operation

- *                  is scheduled and caller will be notified via callback the

- *                  number of bytes sent. This parameter can point to local 

- *                  variable on caller's stack and doesn't have to remain 

- *                  valid until the operation has completed.

- * @param flags     Send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then

- *		    the function will never return PJ_SUCCESS.

- *

- * @return

- *  - PJ_SUCCESS    If data was immediately transfered. In this case, no

- *                  pending operation has been scheduled and the callback

- *                  WILL NOT be called.

- *  - PJ_EPENDING   If the operation has been queued. Once data base been

- *                  transfered, the callback will be called.

- *  - non-zero      The return value indicates the error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,

-                                      pj_ioqueue_op_key_t *op_key,

-				      const void *data,

-				      pj_ssize_t *length,

-				      pj_uint32_t flags );

-

-

-/**

- * Instruct the I/O Queue to write to the handle. This function will return

- * immediately (i.e. non-blocking) regardless whether some data has been 

- * transfered. If the function can't complete immediately, the caller will

- * be notified about the completion when it calls pj_ioqueue_poll(). If 

- * operation completes immediately and data has been transfered, the function

- * returns PJ_SUCCESS and the callback will NOT be called.

- *

- * @param key	    the key that identifies the handle.

- * @param op_key    An operation specific key to be associated with the

- *                  pending operation, so that application can keep track of

- *                  which operation has been completed when the callback is

- *                  called.

- * @param data	    the data to send. Caller MUST make sure that this buffer 

- *		    remains valid until the write operation completes.

- * @param length    On input, it specifies the length of data to send. When

- *                  data was sent immediately, this function returns PJ_SUCCESS

- *                  and this parameter contains the length of data sent. If

- *                  data can not be sent immediately, an asynchronous operation

- *                  is scheduled and caller will be notified via callback the

- *                  number of bytes sent. This parameter can point to local 

- *                  variable on caller's stack and doesn't have to remain 

- *                  valid until the operation has completed.

- * @param flags     send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then

- *		    the function will never return PJ_SUCCESS.

- * @param addr      Optional remote address.

- * @param addrlen   Remote address length, \c addr is specified.

- *

- * @return

- *  - PJ_SUCCESS    If data was immediately written.

- *  - PJ_EPENDING   If the operation has been queued.

- *  - non-zero      The return value indicates the error code.

- */

-PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,

-                                        pj_ioqueue_op_key_t *op_key,

-					const void *data,

-					pj_ssize_t *length,

-                                        pj_uint32_t flags,

-					const pj_sockaddr_t *addr,

-					int addrlen);

-

-

-/**

- * !}

- */

-

-PJ_END_DECL

-

-#endif	/* __PJ_IOQUEUE_H__ */

-

+/* $Id$
+ */
+/* 
+ * Copyright (C)2003-2006 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_IOQUEUE_H__
+#define __PJ_IOQUEUE_H__
+
+/**
+ * @file ioqueue.h
+ * @brief I/O Dispatching Mechanism
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_IO Input/Output
+ * @brief Input/Output
+ * @ingroup PJ_OS
+ *
+ * This section contains API building blocks to perform network I/O and 
+ * communications. If provides:
+ *  - @ref PJ_SOCK
+ *\n
+ *    A highly portable socket abstraction, runs on all kind of
+ *    network APIs such as standard BSD socket, Windows socket, Linux
+ *    \b kernel socket, PalmOS networking API, etc.
+ *
+ *  - @ref pj_addr_resolve
+ *\n
+ *    Portable address resolution, which implements #pj_gethostbyname().
+ *
+ *  - @ref PJ_SOCK_SELECT
+ *\n
+ *    A portable \a select() like API (#pj_sock_select()) which can be
+ *    implemented with various back-ends.
+ *
+ *  - @ref PJ_IOQUEUE
+ *\n
+ *    Framework for dispatching network events.
+ *
+ * For more information see the modules below.
+ */
+
+/**
+ * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue
+ * @ingroup PJ_IO
+ * @{
+ *
+ * I/O Queue provides API for performing asynchronous I/O operations. It
+ * conforms to proactor pattern, which allows application to submit an
+ * asynchronous operation and to be notified later when the operation has
+ * completed.
+ *
+ * The I/O Queue can work on both socket and file descriptors. For 
+ * asynchronous file operations however, one must make sure that the correct
+ * file I/O back-end is used, because not all file I/O back-end can be
+ * used with the ioqueue. Please see \ref PJ_FILE_IO for more details.
+ *
+ * The framework works natively in platforms where asynchronous operation API
+ * exists, such as in Windows NT with IoCompletionPort/IOCP. In other 
+ * platforms, the I/O queue abstracts the operating system's event poll API
+ * to provide semantics similar to IoCompletionPort with minimal penalties
+ * (i.e. per ioqueue and per handle mutex protection).
+ *
+ * The I/O queue provides more than just unified abstraction. It also:
+ *  - makes sure that the operation uses the most effective way to utilize
+ *    the underlying mechanism, to achieve the maximum theoritical
+ *    throughput possible on a given platform.
+ *  - choose the most efficient mechanism for event polling on a given
+ *    platform.
+ *
+ * Currently, the I/O Queue is implemented using:
+ *  - <tt><b>select()</b></tt>, as the common denominator, but the least 
+ *    efficient. Also the number of descriptor is limited to 
+ *    \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64).
+ *  - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode), 
+ *    a much faster replacement for select() on Linux (and more importantly
+ *    doesn't have limitation on number of descriptors).
+ *  - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most 
+ *    efficient way to dispatch events in Windows NT based OSes, and most 
+ *    importantly, it doesn't have the limit on how many handles to monitor.
+ *    And it works with files (not only sockets) as well.
+ *
+ *
+ * \section pj_ioqueue_concurrency_sec Concurrency Rules
+ *
+ * The items below describe rules that must be obeyed when using the I/O 
+ * queue, with regard to concurrency:
+ *  - simultaneous operations (by different threads) to different key is safe.
+ *  - simultaneous operations to the same key is also safe, except
+ *    <b>unregistration</b>, which is described below.
+ *  - <b>care must be taken when unregistering a key</b> from the
+ *    ioqueue. Application must take care that when one thread is issuing
+ *    an unregistration, other thread is not simultaneously invoking an
+ *    operation <b>to the same key</b>.
+ *\n
+ *    This happens because the ioqueue functions are working with a pointer
+ *    to the key, and there is a possible race condition where the pointer
+ *    has been rendered invalid by other threads before the ioqueue has a
+ *    chance to acquire mutex on it.
+ *
+ * \section pj_ioqeuue_examples_sec Examples
+ *
+ * For some examples on how to use the I/O Queue, please see:
+ *
+ *  - \ref page_pjlib_ioqueue_tcp_test
+ *  - \ref page_pjlib_ioqueue_udp_test
+ *  - \ref page_pjlib_ioqueue_perf_test
+ */
+
+
+/**
+ * This structure describes operation specific key to be submitted to
+ * I/O Queue when performing the asynchronous operation. This key will
+ * be returned to the application when completion callback is called.
+ *
+ * Application normally wants to attach it's specific data in the
+ * \c user_data field so that it can keep track of which operation has
+ * completed when the callback is called. Alternatively, application can
+ * also extend this struct to include its data, because the pointer that
+ * is returned in the completion callback will be exactly the same as
+ * the pointer supplied when the asynchronous function is called.
+ */
+typedef struct pj_ioqueue_op_key_t
+{ 
+    void *internal__[32];           /**< Internal I/O Queue data.   */
+    void *user_data;                /**< Application data.          */
+} pj_ioqueue_op_key_t;
+
+/**
+ * This structure describes the callbacks to be called when I/O operation
+ * completes.
+ */
+typedef struct pj_ioqueue_callback
+{
+    /**
+     * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom
+     * completes.
+     *
+     * @param key	    The key.
+     * @param op_key        Operation key.
+     * @param bytes_read    >= 0 to indicate the amount of data read, 
+     *                      otherwise negative value containing the error
+     *                      code. To obtain the pj_status_t error code, use
+     *                      (pj_status_t code = -bytes_read).
+     */
+    void (*on_read_complete)(pj_ioqueue_key_t *key, 
+                             pj_ioqueue_op_key_t *op_key, 
+                             pj_ssize_t bytes_read);
+
+    /**
+     * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto
+     * completes.
+     *
+     * @param key	    The key.
+     * @param op_key        Operation key.
+     * @param bytes_sent    >= 0 to indicate the amount of data written, 
+     *                      otherwise negative value containing the error
+     *                      code. To obtain the pj_status_t error code, use
+     *                      (pj_status_t code = -bytes_sent).
+     */
+    void (*on_write_complete)(pj_ioqueue_key_t *key, 
+                              pj_ioqueue_op_key_t *op_key, 
+                              pj_ssize_t bytes_sent);
+
+    /**
+     * This callback is called when #pj_ioqueue_accept completes.
+     *
+     * @param key	    The key.
+     * @param op_key        Operation key.
+     * @param sock          Newly connected socket.
+     * @param status	    Zero if the operation completes successfully.
+     */
+    void (*on_accept_complete)(pj_ioqueue_key_t *key, 
+                               pj_ioqueue_op_key_t *op_key, 
+                               pj_sock_t sock, 
+                               pj_status_t status);
+
+    /**
+     * This callback is called when #pj_ioqueue_connect completes.
+     *
+     * @param key	    The key.
+     * @param status	    PJ_SUCCESS if the operation completes successfully.
+     */
+    void (*on_connect_complete)(pj_ioqueue_key_t *key, 
+                                pj_status_t status);
+} pj_ioqueue_callback;
+
+
+/**
+ * Types of pending I/O Queue operation. This enumeration is only used
+ * internally within the ioqueue.
+ */
+typedef enum pj_ioqueue_operation_e
+{
+    PJ_IOQUEUE_OP_NONE		= 0,	/**< No operation.          */
+    PJ_IOQUEUE_OP_READ		= 1,	/**< read() operation.      */
+    PJ_IOQUEUE_OP_RECV          = 2,    /**< recv() operation.      */
+    PJ_IOQUEUE_OP_RECV_FROM	= 4,	/**< recvfrom() operation.  */
+    PJ_IOQUEUE_OP_WRITE		= 8,	/**< write() operation.     */
+    PJ_IOQUEUE_OP_SEND          = 16,   /**< send() operation.      */
+    PJ_IOQUEUE_OP_SEND_TO	= 32,	/**< sendto() operation.    */
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+    PJ_IOQUEUE_OP_ACCEPT	= 64,	/**< accept() operation.    */
+    PJ_IOQUEUE_OP_CONNECT	= 128,	/**< connect() operation.   */
+#endif	/* PJ_HAS_TCP */
+} pj_ioqueue_operation_e;
+
+
+/**
+ * This macro specifies the maximum number of events that can be
+ * processed by the ioqueue on a single poll cycle, on implementation
+ * that supports it. The value is only meaningfull when specified
+ * during PJLIB build.
+ */
+#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL
+#   define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL     (16)
+#endif
+
+/**
+ * When this flag is specified in ioqueue's recv() or send() operations,
+ * the ioqueue will always mark the operation as asynchronous.
+ */
+#define PJ_IOQUEUE_ALWAYS_ASYNC	    ((pj_uint32_t)1 << (pj_uint32_t)31)
+
+/**
+ * Return the name of the ioqueue implementation.
+ *
+ * @return		Implementation name.
+ */
+PJ_DECL(const char*) pj_ioqueue_name(void);
+
+
+/**
+ * Create a new I/O Queue framework.
+ *
+ * @param pool		The pool to allocate the I/O queue structure. 
+ * @param max_fd	The maximum number of handles to be supported, which 
+ *			should not exceed PJ_IOQUEUE_MAX_HANDLES.
+ * @param ioqueue	Pointer to hold the newly created I/O Queue.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
+					pj_size_t max_fd,
+					pj_ioqueue_t **ioqueue);
+
+/**
+ * Destroy the I/O queue.
+ *
+ * @param ioque	        The I/O Queue to be destroyed.
+ *
+ * @return              PJ_SUCCESS if success.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque );
+
+/**
+ * Set the lock object to be used by the I/O Queue. This function can only
+ * be called right after the I/O queue is created, before any handle is
+ * registered to the I/O queue.
+ *
+ * Initially the I/O queue is created with non-recursive mutex protection. 
+ * Applications can supply alternative lock to be used by calling this 
+ * function.
+ *
+ * @param ioque         The ioqueue instance.
+ * @param lock          The lock to be used by the ioqueue.
+ * @param auto_delete   In non-zero, the lock will be deleted by the ioqueue.
+ *
+ * @return              PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 
+					  pj_lock_t *lock,
+					  pj_bool_t auto_delete );
+
+/**
+ * Register a socket to the I/O queue framework. 
+ * When a socket is registered to the IOQueue, it may be modified to use
+ * non-blocking IO. If it is modified, there is no guarantee that this 
+ * modification will be restored after the socket is unregistered.
+ *
+ * @param pool	    To allocate the resource for the specified handle, 
+ *		    which must be valid until the handle/key is unregistered 
+ *		    from I/O Queue.
+ * @param ioque	    The I/O Queue.
+ * @param sock	    The socket.
+ * @param user_data User data to be associated with the key, which can be
+ *		    retrieved later.
+ * @param cb	    Callback to be called when I/O operation completes. 
+ * @param key       Pointer to receive the key to be associated with this
+ *                  socket. Subsequent I/O queue operation will need this
+ *                  key.
+ *
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					       pj_ioqueue_t *ioque,
+					       pj_sock_t sock,
+					       void *user_data,
+					       const pj_ioqueue_callback *cb,
+                                               pj_ioqueue_key_t **key );
+
+/**
+ * Unregister from the I/O Queue framework. Caller must make sure that
+ * the key doesn't have any pending operations before calling this function,
+ * by calling #pj_ioqueue_is_pending() for all previously submitted
+ * operations except asynchronous connect, and if necessary call
+ * #pj_ioqueue_post_completion() to cancel the pending operations.
+ *
+ * Note that asynchronous connect operation will automatically be 
+ * cancelled during the unregistration.
+ *
+ * @param key	    The key that was previously obtained from registration.
+ *
+ * @return          PJ_SUCCESS on success or the error code.
+ *
+ * @see pj_ioqueue_is_pending
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );
+
+
+/**
+ * Get user data associated with an ioqueue key.
+ *
+ * @param key	    The key that was previously obtained from registration.
+ *
+ * @return          The user data associated with the descriptor, or NULL 
+ *                  on error or if no data is associated with the key during
+ *                  registration.
+ */
+PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key );
+
+/**
+ * Set or change the user data to be associated with the file descriptor or
+ * handle or socket descriptor.
+ *
+ * @param key	    The key that was previously obtained from registration.
+ * @param user_data User data to be associated with the descriptor.
+ * @param old_data  Optional parameter to retrieve the old user data.
+ *
+ * @return          PJ_SUCCESS on success or the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+                                               void *user_data,
+                                               void **old_data);
+
+
+/**
+ * Initialize operation key.
+ *
+ * @param op_key    The operation key to be initialied.
+ * @param size	    The size of the operation key.
+ */
+PJ_DECL(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
+				      pj_size_t size );
+
+/**
+ * Check if operation is pending on the specified operation key.
+ * The \c op_key must have been initialized with #pj_ioqueue_op_key_init() 
+ * or submitted as pending operation before, or otherwise the result 
+ * is undefined.
+ *
+ * @param key       The key.
+ * @param op_key    The operation key, previously submitted to any of
+ *                  the I/O functions and has returned PJ_EPENDING.
+ *
+ * @return          Non-zero if operation is still pending.
+ */
+PJ_DECL(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
+                                          pj_ioqueue_op_key_t *op_key );
+
+
+/**
+ * Post completion status to the specified operation key and call the
+ * appropriate callback. When the callback is called, the number of bytes 
+ * received in read/write callback or the status in accept/connect callback
+ * will be set from the \c bytes_status parameter.
+ *
+ * @param key           The key.
+ * @param op_key        Pending operation key.
+ * @param bytes_status  Number of bytes or status to be set. A good value
+ *                      to put here is -PJ_ECANCELLED.
+ *
+ * @return              PJ_SUCCESS if completion status has been successfully
+ *                      sent.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
+                                                 pj_ioqueue_op_key_t *op_key,
+                                                 pj_ssize_t bytes_status );
+
+
+
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+/**
+ * Instruct I/O Queue to accept incoming connection on the specified 
+ * listening socket. This function will return immediately (i.e. non-blocking)
+ * regardless whether a connection is immediately available. If the function
+ * can't complete immediately, the caller will be notified about the incoming
+ * connection when it calls pj_ioqueue_poll(). If a new connection is
+ * immediately available, the function returns PJ_SUCCESS with the new
+ * connection; in this case, the callback WILL NOT be called.
+ *
+ * @param key	    The key which registered to the server socket.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param new_sock  Argument which contain pointer to receive the new socket
+ *                  for the incoming connection.
+ * @param local	    Optional argument which contain pointer to variable to 
+ *                  receive local address.
+ * @param remote    Optional argument which contain pointer to variable to 
+ *                  receive the remote address.
+ * @param addrlen   On input, contains the length of the buffer for the
+ *		    address, and on output, contains the actual length of the
+ *		    address. This argument is optional.
+ * @return
+ *  - PJ_SUCCESS    When connection is available immediately, and the 
+ *                  parameters will be updated to contain information about 
+ *                  the new connection. In this case, a completion callback
+ *                  WILL NOT be called.
+ *  - PJ_EPENDING   If no connection is available immediately. When a new
+ *                  connection arrives, the callback will be called.
+ *  - non-zero      which indicates the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
+                                        pj_ioqueue_op_key_t *op_key,
+					pj_sock_t *sock,
+					pj_sockaddr_t *local,
+					pj_sockaddr_t *remote,
+					int *addrlen );
+
+/**
+ * Initiate non-blocking socket connect. If the socket can NOT be connected
+ * immediately, asynchronous connect() will be scheduled and caller will be
+ * notified via completion callback when it calls pj_ioqueue_poll(). If
+ * socket is connected immediately, the function returns PJ_SUCCESS and
+ * completion callback WILL NOT be called.
+ *
+ * @param key	    The key associated with TCP socket
+ * @param addr	    The remote address.
+ * @param addrlen   The remote address length.
+ *
+ * @return
+ *  - PJ_SUCCESS    If socket is connected immediately. In this case, the
+ *                  completion callback WILL NOT be called.
+ *  - PJ_EPENDING   If operation is queued, or 
+ *  - non-zero      Indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
+					 const pj_sockaddr_t *addr,
+					 int addrlen );
+
+#endif	/* PJ_HAS_TCP */
+
+/**
+ * Poll the I/O Queue for completed events.
+ *
+ * @param ioque		the I/O Queue.
+ * @param timeout	polling timeout, or NULL if the thread wishes to wait
+ *			indefinetely for the event.
+ *
+ * @return 
+ *  - zero if timed out (no event).
+ *  - (<0) if error occured during polling. Callback will NOT be called.
+ *  - (>1) to indicate numbers of events. Callbacks have been called.
+ */
+PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque,
+			      const pj_time_val *timeout);
+
+
+/**
+ * Instruct the I/O Queue to read from the specified handle. This function
+ * returns immediately (i.e. non-blocking) regardless whether some data has 
+ * been transfered. If the operation can't complete immediately, caller will 
+ * be notified about the completion when it calls pj_ioqueue_poll(). If data
+ * is immediately available, the function will return PJ_SUCCESS and the
+ * callback WILL NOT be called.
+ *
+ * @param key	    The key that uniquely identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called. Caller must make sure that this key remains 
+ *                  valid until the function completes.
+ * @param buffer    The buffer to hold the read data. The caller MUST make sure
+ *		    that this buffer remain valid until the framework completes
+ *		    reading the handle.
+ * @param length    On input, it specifies the size of the buffer. If data is
+ *                  available to be read immediately, the function returns
+ *                  PJ_SUCCESS and this argument will be filled with the
+ *                  amount of data read. If the function is pending, caller
+ *                  will be notified about the amount of data read in the
+ *                  callback. This parameter can point to local variable in
+ *                  caller's stack and doesn't have to remain valid for the
+ *                  duration of pending operation.
+ * @param flags     Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ *
+ * @return
+ *  - PJ_SUCCESS    If immediate data has been received in the buffer. In this
+ *                  case, the callback WILL NOT be called.
+ *  - PJ_EPENDING   If the operation has been queued, and the callback will be
+ *                  called when data has been received.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
+                                      pj_ioqueue_op_key_t *op_key,
+				      void *buffer,
+				      pj_ssize_t *length,
+				      pj_uint32_t flags );
+
+/**
+ * This function behaves similarly as #pj_ioqueue_recv(), except that it is
+ * normally called for socket, and the remote address will also be returned
+ * along with the data. Caller MUST make sure that both buffer and addr
+ * remain valid until the framework completes reading the data.
+ *
+ * @param key	    The key that uniquely identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param buffer    The buffer to hold the read data. The caller MUST make sure
+ *		    that this buffer remain valid until the framework completes
+ *		    reading the handle.
+ * @param length    On input, it specifies the size of the buffer. If data is
+ *                  available to be read immediately, the function returns
+ *                  PJ_SUCCESS and this argument will be filled with the
+ *                  amount of data read. If the function is pending, caller
+ *                  will be notified about the amount of data read in the
+ *                  callback. This parameter can point to local variable in
+ *                  caller's stack and doesn't have to remain valid for the
+ *                  duration of pending operation.
+ * @param flags     Recv flag. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ * @param addr      Optional Pointer to buffer to receive the address.
+ * @param addrlen   On input, specifies the length of the address buffer.
+ *                  On output, it will be filled with the actual length of
+ *                  the address. This argument can be NULL if \c addr is not
+ *                  specified.
+ *
+ * @return
+ *  - PJ_SUCCESS    If immediate data has been received. In this case, the 
+ *		    callback must have been called before this function 
+ *		    returns, and no pending operation is scheduled.
+ *  - PJ_EPENDING   If the operation has been queued.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
+                                          pj_ioqueue_op_key_t *op_key,
+					  void *buffer,
+					  pj_ssize_t *length,
+                                          pj_uint32_t flags,
+					  pj_sockaddr_t *addr,
+					  int *addrlen);
+
+/**
+ * Instruct the I/O Queue to write to the handle. This function will return
+ * immediately (i.e. non-blocking) regardless whether some data has been 
+ * transfered. If the function can't complete immediately, the caller will
+ * be notified about the completion when it calls pj_ioqueue_poll(). If 
+ * operation completes immediately and data has been transfered, the function
+ * returns PJ_SUCCESS and the callback will NOT be called.
+ *
+ * @param key	    The key that identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param data	    The data to send. Caller MUST make sure that this buffer 
+ *		    remains valid until the write operation completes.
+ * @param length    On input, it specifies the length of data to send. When
+ *                  data was sent immediately, this function returns PJ_SUCCESS
+ *                  and this parameter contains the length of data sent. If
+ *                  data can not be sent immediately, an asynchronous operation
+ *                  is scheduled and caller will be notified via callback the
+ *                  number of bytes sent. This parameter can point to local 
+ *                  variable on caller's stack and doesn't have to remain 
+ *                  valid until the operation has completed.
+ * @param flags     Send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ *
+ * @return
+ *  - PJ_SUCCESS    If data was immediately transfered. In this case, no
+ *                  pending operation has been scheduled and the callback
+ *                  WILL NOT be called.
+ *  - PJ_EPENDING   If the operation has been queued. Once data base been
+ *                  transfered, the callback will be called.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
+                                      pj_ioqueue_op_key_t *op_key,
+				      const void *data,
+				      pj_ssize_t *length,
+				      pj_uint32_t flags );
+
+
+/**
+ * Instruct the I/O Queue to write to the handle. This function will return
+ * immediately (i.e. non-blocking) regardless whether some data has been 
+ * transfered. If the function can't complete immediately, the caller will
+ * be notified about the completion when it calls pj_ioqueue_poll(). If 
+ * operation completes immediately and data has been transfered, the function
+ * returns PJ_SUCCESS and the callback will NOT be called.
+ *
+ * @param key	    the key that identifies the handle.
+ * @param op_key    An operation specific key to be associated with the
+ *                  pending operation, so that application can keep track of
+ *                  which operation has been completed when the callback is
+ *                  called.
+ * @param data	    the data to send. Caller MUST make sure that this buffer 
+ *		    remains valid until the write operation completes.
+ * @param length    On input, it specifies the length of data to send. When
+ *                  data was sent immediately, this function returns PJ_SUCCESS
+ *                  and this parameter contains the length of data sent. If
+ *                  data can not be sent immediately, an asynchronous operation
+ *                  is scheduled and caller will be notified via callback the
+ *                  number of bytes sent. This parameter can point to local 
+ *                  variable on caller's stack and doesn't have to remain 
+ *                  valid until the operation has completed.
+ * @param flags     send flags. If flags has PJ_IOQUEUE_ALWAYS_ASYNC then
+ *		    the function will never return PJ_SUCCESS.
+ * @param addr      Optional remote address.
+ * @param addrlen   Remote address length, \c addr is specified.
+ *
+ * @return
+ *  - PJ_SUCCESS    If data was immediately written.
+ *  - PJ_EPENDING   If the operation has been queued.
+ *  - non-zero      The return value indicates the error code.
+ */
+PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
+                                        pj_ioqueue_op_key_t *op_key,
+					const void *data,
+					pj_ssize_t *length,
+                                        pj_uint32_t flags,
+					const pj_sockaddr_t *addr,
+					int addrlen);
+
+
+/**
+ * !}
+ */
+
+PJ_END_DECL
+
+#endif	/* __PJ_IOQUEUE_H__ */
+
diff --git a/pjlib/include/pj/list.h b/pjlib/include/pj/list.h
index 5aca688..fc0223c 100644
--- a/pjlib/include/pj/list.h
+++ b/pjlib/include/pj/list.h
@@ -1,236 +1,236 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_LIST_H__

-#define __PJ_LIST_H__

-

-/**

- * @file list.h

- * @brief Linked List data structure.

- */

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-/*

- * @defgroup PJ_DS Data Structure.

- * @ingroup PJ

- */

-

-/**

- * @defgroup PJ_LIST Linked List

- * @ingroup PJ_DS

- * @{

- *

- * List in PJLIB is implemented as doubly-linked list, and it won't require

- * dynamic memory allocation (just as all PJLIB data structures). The list here

- * should be viewed more like a low level C list instead of high level C++ list

- * (which normally are easier to use but require dynamic memory allocations),

- * therefore all caveats with C list apply here too (such as you can NOT put

- * a node in more than one lists).

- *

- * \section pj_list_example_sec Examples

- *

- * See below for examples on how to manipulate linked list:

- *  - @ref page_pjlib_samples_list_c

- *  - @ref page_pjlib_list_test

- */

-

-

-/**

- * Use this macro in the start of the structure declaration to declare that

- * the structure can be used in the linked list operation. This macro simply

- * declares additional member @a prev and @a next to the structure.

- * @hideinitializer

- */

-#define PJ_DECL_LIST_MEMBER(type)                       \

-                                   /** List @a prev. */ \

-                                   type *prev;          \

-                                   /** List @a next. */ \

-                                   type *next 

-

-

-/**

- * This structure describes generic list node and list. The owner of this list

- * must initialize the 'value' member to an appropriate value (typically the

- * owner itself).

- */

-struct pj_list

-{

-    PJ_DECL_LIST_MEMBER(void);

-};

-

-

-/**

- * Initialize the list.

- * Initially, the list will have no member, and function pj_list_empty() will

- * always return nonzero (which indicates TRUE) for the newly initialized 

- * list.

- *

- * @param node The list head.

- */

-PJ_INLINE(void) pj_list_init(pj_list_type * node)

-{

-    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;

-}

-

-

-/**

- * Check that the list is empty.

- *

- * @param node	The list head.

- *

- * @return Non-zero if the list is not-empty, or zero if it is empty.

- *

- */

-PJ_INLINE(int) pj_list_empty(const pj_list_type * node)

-{

-    return ((pj_list*)node)->next == node;

-}

-

-

-/**

- * Insert the node to the list before the specified element position.

- *

- * @param pos	The element to which the node will be inserted before. 

- * @param node	The element to be inserted.

- *

- * @return void.

- */

-PJ_IDECL(void)	pj_list_insert_before(pj_list_type *pos, pj_list_type *node);

-

-

-/**

- * Inserts all nodes in \a nodes to the target list.

- *

- * @param lst	    The target list.

- * @param nodes	    Nodes list.

- */

-PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst,

-					   pj_list_type *nodes);

-

-/**

- * Insert a node to the list after the specified element position.

- *

- * @param pos	    The element in the list which will precede the inserted 

- *		    element.

- * @param node	    The element to be inserted after the position element.

- *

- * @return void.

- */

-PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node);

-

-/**

- * Insert all nodes in \a nodes to the target list.

- *

- * @param lst	    The target list.

- * @param nodes	    Nodes list.

- */

-PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst,

-					  pj_list_type *nodes);

-

-

-/**

- * Remove elements from the source list, and insert them to the destination

- * list. The elements of the source list will occupy the

- * front elements of the target list. Note that the node pointed by \a list2

- * itself is not considered as a node, but rather as the list descriptor, so

- * it will not be inserted to the \a list1. The elements to be inserted starts

- * at \a list2->next. If \a list2 is to be included in the operation, use

- * \a pj_list_insert_nodes_before.

- *

- * @param list1	The destination list.

- * @param list2	The source list.

- *

- * @return void.

- */

-PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2);

-

-

-/**

- * Remove elements from the second list argument, and insert them to the list 

- * in the first argument. The elements from the second list will be appended

- * to the first list. Note that the node pointed by \a list2

- * itself is not considered as a node, but rather as the list descriptor, so

- * it will not be inserted to the \a list1. The elements to be inserted starts

- * at \a list2->next. If \a list2 is to be included in the operation, use

- * \a pj_list_insert_nodes_before.

- *

- * @param list1	    The element in the list which will precede the inserted 

- *		    element.

- * @param list2	    The element in the list to be inserted.

- *

- * @return void.

- */

-PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2);

-

-

-/**

- * Erase the node from the list it currently belongs.

- *

- * @param node	    The element to be erased.

- */

-PJ_IDECL(void) pj_list_erase(pj_list_type *node);

-

-

-/**

- * Find node in the list.

- *

- * @param list	    The list head.

- * @param node	    The node element to be searched.

- *

- * @return The node itself if it is found in the list, or NULL if it is not 

- *         found in the list.

- */

-PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list, 

-					  pj_list_type *node);

-

-

-/**

- * Search the list for the specified value, using the specified comparison

- * function. This function iterates on nodes in the list, started with the

- * first node, and call the user supplied comparison function until the

- * comparison function returns ZERO.

- *

- * @param list	    The list head.

- * @param value	    The user defined value to be passed in the comparison 

- *		    function

- * @param comp	    The comparison function, which should return ZERO to 

- *		    indicate that the searched value is found.

- *

- * @return The first node that matched, or NULL if it is not found.

- */

-PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value,

-				       int (*comp)(void *value, 

-						   const pj_list_type *node)

-				       );

-

-

-/**

- * @}

- */

-

-#if PJ_FUNCTIONS_ARE_INLINED

-#  include "list_i.h"

-#endif

-

-PJ_END_DECL

-

-#endif	/* __PJ_LIST_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_LIST_H__
+#define __PJ_LIST_H__
+
+/**
+ * @file list.h
+ * @brief Linked List data structure.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/*
+ * @defgroup PJ_DS Data Structure.
+ * @ingroup PJ
+ */
+
+/**
+ * @defgroup PJ_LIST Linked List
+ * @ingroup PJ_DS
+ * @{
+ *
+ * List in PJLIB is implemented as doubly-linked list, and it won't require
+ * dynamic memory allocation (just as all PJLIB data structures). The list here
+ * should be viewed more like a low level C list instead of high level C++ list
+ * (which normally are easier to use but require dynamic memory allocations),
+ * therefore all caveats with C list apply here too (such as you can NOT put
+ * a node in more than one lists).
+ *
+ * \section pj_list_example_sec Examples
+ *
+ * See below for examples on how to manipulate linked list:
+ *  - @ref page_pjlib_samples_list_c
+ *  - @ref page_pjlib_list_test
+ */
+
+
+/**
+ * Use this macro in the start of the structure declaration to declare that
+ * the structure can be used in the linked list operation. This macro simply
+ * declares additional member @a prev and @a next to the structure.
+ * @hideinitializer
+ */
+#define PJ_DECL_LIST_MEMBER(type)                       \
+                                   /** List @a prev. */ \
+                                   type *prev;          \
+                                   /** List @a next. */ \
+                                   type *next 
+
+
+/**
+ * This structure describes generic list node and list. The owner of this list
+ * must initialize the 'value' member to an appropriate value (typically the
+ * owner itself).
+ */
+struct pj_list
+{
+    PJ_DECL_LIST_MEMBER(void);
+};
+
+
+/**
+ * Initialize the list.
+ * Initially, the list will have no member, and function pj_list_empty() will
+ * always return nonzero (which indicates TRUE) for the newly initialized 
+ * list.
+ *
+ * @param node The list head.
+ */
+PJ_INLINE(void) pj_list_init(pj_list_type * node)
+{
+    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;
+}
+
+
+/**
+ * Check that the list is empty.
+ *
+ * @param node	The list head.
+ *
+ * @return Non-zero if the list is not-empty, or zero if it is empty.
+ *
+ */
+PJ_INLINE(int) pj_list_empty(const pj_list_type * node)
+{
+    return ((pj_list*)node)->next == node;
+}
+
+
+/**
+ * Insert the node to the list before the specified element position.
+ *
+ * @param pos	The element to which the node will be inserted before. 
+ * @param node	The element to be inserted.
+ *
+ * @return void.
+ */
+PJ_IDECL(void)	pj_list_insert_before(pj_list_type *pos, pj_list_type *node);
+
+
+/**
+ * Inserts all nodes in \a nodes to the target list.
+ *
+ * @param lst	    The target list.
+ * @param nodes	    Nodes list.
+ */
+PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst,
+					   pj_list_type *nodes);
+
+/**
+ * Insert a node to the list after the specified element position.
+ *
+ * @param pos	    The element in the list which will precede the inserted 
+ *		    element.
+ * @param node	    The element to be inserted after the position element.
+ *
+ * @return void.
+ */
+PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node);
+
+/**
+ * Insert all nodes in \a nodes to the target list.
+ *
+ * @param lst	    The target list.
+ * @param nodes	    Nodes list.
+ */
+PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst,
+					  pj_list_type *nodes);
+
+
+/**
+ * Remove elements from the source list, and insert them to the destination
+ * list. The elements of the source list will occupy the
+ * front elements of the target list. Note that the node pointed by \a list2
+ * itself is not considered as a node, but rather as the list descriptor, so
+ * it will not be inserted to the \a list1. The elements to be inserted starts
+ * at \a list2->next. If \a list2 is to be included in the operation, use
+ * \a pj_list_insert_nodes_before.
+ *
+ * @param list1	The destination list.
+ * @param list2	The source list.
+ *
+ * @return void.
+ */
+PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2);
+
+
+/**
+ * Remove elements from the second list argument, and insert them to the list 
+ * in the first argument. The elements from the second list will be appended
+ * to the first list. Note that the node pointed by \a list2
+ * itself is not considered as a node, but rather as the list descriptor, so
+ * it will not be inserted to the \a list1. The elements to be inserted starts
+ * at \a list2->next. If \a list2 is to be included in the operation, use
+ * \a pj_list_insert_nodes_before.
+ *
+ * @param list1	    The element in the list which will precede the inserted 
+ *		    element.
+ * @param list2	    The element in the list to be inserted.
+ *
+ * @return void.
+ */
+PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2);
+
+
+/**
+ * Erase the node from the list it currently belongs.
+ *
+ * @param node	    The element to be erased.
+ */
+PJ_IDECL(void) pj_list_erase(pj_list_type *node);
+
+
+/**
+ * Find node in the list.
+ *
+ * @param list	    The list head.
+ * @param node	    The node element to be searched.
+ *
+ * @return The node itself if it is found in the list, or NULL if it is not 
+ *         found in the list.
+ */
+PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list, 
+					  pj_list_type *node);
+
+
+/**
+ * Search the list for the specified value, using the specified comparison
+ * function. This function iterates on nodes in the list, started with the
+ * first node, and call the user supplied comparison function until the
+ * comparison function returns ZERO.
+ *
+ * @param list	    The list head.
+ * @param value	    The user defined value to be passed in the comparison 
+ *		    function
+ * @param comp	    The comparison function, which should return ZERO to 
+ *		    indicate that the searched value is found.
+ *
+ * @return The first node that matched, or NULL if it is not found.
+ */
+PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value,
+				       int (*comp)(void *value, 
+						   const pj_list_type *node)
+				       );
+
+
+/**
+ * @}
+ */
+
+#if PJ_FUNCTIONS_ARE_INLINED
+#  include "list_i.h"
+#endif
+
+PJ_END_DECL
+
+#endif	/* __PJ_LIST_H__ */
+
diff --git a/pjlib/include/pj/list_i.h b/pjlib/include/pj/list_i.h
index 1ad0c08..c6d95c8 100644
--- a/pjlib/include/pj/list_i.h
+++ b/pjlib/include/pj/list_i.h
@@ -1,118 +1,118 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 

- */

-

-

-/* Internal */

-PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next)

-{

-    ((pj_list*)prev)->next = next;

-    ((pj_list*)next)->prev = prev;

-}

-

-/*

-PJ_IDEF(void) 

-pj_list_init(pj_list_type * node)

-{

-    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;

-}

-

-PJ_IDEF(int) pj_list_empty(const pj_list_type * node)

-{

-    return ((pj_list*)node)->next == node;

-}

-*/

-

-PJ_IDEF(void) 

-pj_list_insert_after(pj_list_type *pos, pj_list_type *node)

-{

-    ((pj_list*)node)->prev = pos;

-    ((pj_list*)node)->next = ((pj_list*)pos)->next;

-    ((pj_list*) ((pj_list*)pos)->next) ->prev = node;

-    ((pj_list*)pos)->next = node;

-}

-

-

-PJ_IDEF(void) 

-pj_list_insert_before(pj_list_type *pos, pj_list_type *node)

-{

-    pj_list_insert_after(((pj_list*)pos)->prev, node);

-}

-

-

-PJ_IDEF(void)	    

-pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst)

-{

-    pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev;

-    pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next;

-

-    pj_link_node(pos, lst);

-    pj_link_node(lst_last, pos_next);

-}

-

-PJ_IDEF(void) 

-pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst)

-{

-    pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst);

-}

-

-PJ_IDEF(void)

-pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2)

-{

-    pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next);

-    pj_link_node(((pj_list*)lst2)->prev, lst1);

-    pj_list_init(lst2);

-}

-

-PJ_IDEF(void)

-pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2)

-{

-    pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next);

-    pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next);

-    pj_list_init(lst2);

-}

-

-PJ_IDEF(void) 

-pj_list_erase(pj_list_type *node)

-{

-    pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next);

-}

-

-

-PJ_IDEF(pj_list_type*) 

-pj_list_find_node(pj_list_type *list, pj_list_type *node)

-{

-    pj_list *p = (pj_list *) ((pj_list*)list)->next;

-    while (p != list && p != node)

-	p = (pj_list *) p->next;

-

-    return p==node ? p : NULL;

-}

-

-

-PJ_IDEF(pj_list_type*) 

-pj_list_search(pj_list_type *list, void *value,

-	       int (*comp)(void *value, const pj_list_type *node))

-{

-    pj_list *p = (pj_list *) ((pj_list*)list)->next;

-    while (p != list && (*comp)(value, p) != 0)

-	p = (pj_list *) p->next;

-

-    return p==list ? NULL : p;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 
+ */
+
+
+/* Internal */
+PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next)
+{
+    ((pj_list*)prev)->next = next;
+    ((pj_list*)next)->prev = prev;
+}
+
+/*
+PJ_IDEF(void) 
+pj_list_init(pj_list_type * node)
+{
+    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;
+}
+
+PJ_IDEF(int) pj_list_empty(const pj_list_type * node)
+{
+    return ((pj_list*)node)->next == node;
+}
+*/
+
+PJ_IDEF(void) 
+pj_list_insert_after(pj_list_type *pos, pj_list_type *node)
+{
+    ((pj_list*)node)->prev = pos;
+    ((pj_list*)node)->next = ((pj_list*)pos)->next;
+    ((pj_list*) ((pj_list*)pos)->next) ->prev = node;
+    ((pj_list*)pos)->next = node;
+}
+
+
+PJ_IDEF(void) 
+pj_list_insert_before(pj_list_type *pos, pj_list_type *node)
+{
+    pj_list_insert_after(((pj_list*)pos)->prev, node);
+}
+
+
+PJ_IDEF(void)	    
+pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst)
+{
+    pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev;
+    pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next;
+
+    pj_link_node(pos, lst);
+    pj_link_node(lst_last, pos_next);
+}
+
+PJ_IDEF(void) 
+pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst)
+{
+    pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst);
+}
+
+PJ_IDEF(void)
+pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2)
+{
+    pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next);
+    pj_link_node(((pj_list*)lst2)->prev, lst1);
+    pj_list_init(lst2);
+}
+
+PJ_IDEF(void)
+pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2)
+{
+    pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next);
+    pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next);
+    pj_list_init(lst2);
+}
+
+PJ_IDEF(void) 
+pj_list_erase(pj_list_type *node)
+{
+    pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next);
+}
+
+
+PJ_IDEF(pj_list_type*) 
+pj_list_find_node(pj_list_type *list, pj_list_type *node)
+{
+    pj_list *p = (pj_list *) ((pj_list*)list)->next;
+    while (p != list && p != node)
+	p = (pj_list *) p->next;
+
+    return p==node ? p : NULL;
+}
+
+
+PJ_IDEF(pj_list_type*) 
+pj_list_search(pj_list_type *list, void *value,
+	       int (*comp)(void *value, const pj_list_type *node))
+{
+    pj_list *p = (pj_list *) ((pj_list*)list)->next;
+    while (p != list && (*comp)(value, p) != 0)
+	p = (pj_list *) p->next;
+
+    return p==list ? NULL : p;
+}
+
diff --git a/pjlib/include/pj/lock.h b/pjlib/include/pj/lock.h
index 4eb50af..96c9e11 100644
--- a/pjlib/include/pj/lock.h
+++ b/pjlib/include/pj/lock.h
@@ -1,153 +1,153 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_LOCK_H__

-#define __PJ_LOCK_H__

-

-/**

- * @file lock.h

- * @brief Higher abstraction for locking objects.

- */

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_LOCK Lock Objects

- * @ingroup PJ_OS

- * @{

- *

- * <b>Lock Objects</b> are higher abstraction for different lock mechanisms.

- * It offers the same API for manipulating different lock types (e.g.

- * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks).

- * Because Lock Objects have the same API for different types of lock

- * implementation, it can be passed around in function arguments. As the

- * result, it can be used to control locking policy for  a particular

- * feature.

- */

-

-

-/**

- * Create simple, non recursive mutex lock object.

- *

- * @param pool	    Memory pool.

- * @param name	    Lock object's name.

- * @param lock	    Pointer to store the returned handle.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,

-						  const char *name,

-						  pj_lock_t **lock );

-

-/**

- * Create recursive mutex lock object.

- *

- * @param pool	    Memory pool.

- * @param name	    Lock object's name.

- * @param lock	    Pointer to store the returned handle.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,

-						     const char *name,

-						     pj_lock_t **lock );

-

-

-/**

- * Create NULL mutex. A NULL mutex doesn't actually have any synchronization

- * object attached to it.

- *

- * @param pool	    Memory pool.

- * @param name	    Lock object's name.

- * @param lock	    Pointer to store the returned handle.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,

-						const char *name,

-						pj_lock_t **lock );

-

-

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-/**

- * Create semaphore lock object.

- *

- * @param pool	    Memory pool.

- * @param name	    Lock object's name.

- * @param initial   Initial value of the semaphore.

- * @param max	    Maximum value of the semaphore.

- * @param lock	    Pointer to store the returned handle.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool,

-					       const char *name,

-					       unsigned initial,

-					       unsigned max,

-					       pj_lock_t **lock );

-

-#endif	/* PJ_HAS_SEMAPHORE */

-

-/**

- * Acquire lock on the specified lock object.

- *

- * @param lock	    The lock object.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock );

-

-

-/**

- * Try to acquire lock on the specified lock object.

- *

- * @param lock	    The lock object.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock );

-

-

-/**

- * Release lock on the specified lock object.

- *

- * @param lock	    The lock object.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock );

-

-

-/**

- * Destroy the lock object.

- *

- * @param lock	    The lock object.

- *

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock );

-

-

-/** @} */

-

-PJ_END_DECL

-

-

-#endif	/* __PJ_LOCK_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_LOCK_H__
+#define __PJ_LOCK_H__
+
+/**
+ * @file lock.h
+ * @brief Higher abstraction for locking objects.
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_LOCK Lock Objects
+ * @ingroup PJ_OS
+ * @{
+ *
+ * <b>Lock Objects</b> are higher abstraction for different lock mechanisms.
+ * It offers the same API for manipulating different lock types (e.g.
+ * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks).
+ * Because Lock Objects have the same API for different types of lock
+ * implementation, it can be passed around in function arguments. As the
+ * result, it can be used to control locking policy for  a particular
+ * feature.
+ */
+
+
+/**
+ * Create simple, non recursive mutex lock object.
+ *
+ * @param pool	    Memory pool.
+ * @param name	    Lock object's name.
+ * @param lock	    Pointer to store the returned handle.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,
+						  const char *name,
+						  pj_lock_t **lock );
+
+/**
+ * Create recursive mutex lock object.
+ *
+ * @param pool	    Memory pool.
+ * @param name	    Lock object's name.
+ * @param lock	    Pointer to store the returned handle.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,
+						     const char *name,
+						     pj_lock_t **lock );
+
+
+/**
+ * Create NULL mutex. A NULL mutex doesn't actually have any synchronization
+ * object attached to it.
+ *
+ * @param pool	    Memory pool.
+ * @param name	    Lock object's name.
+ * @param lock	    Pointer to store the returned handle.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,
+						const char *name,
+						pj_lock_t **lock );
+
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+/**
+ * Create semaphore lock object.
+ *
+ * @param pool	    Memory pool.
+ * @param name	    Lock object's name.
+ * @param initial   Initial value of the semaphore.
+ * @param max	    Maximum value of the semaphore.
+ * @param lock	    Pointer to store the returned handle.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool,
+					       const char *name,
+					       unsigned initial,
+					       unsigned max,
+					       pj_lock_t **lock );
+
+#endif	/* PJ_HAS_SEMAPHORE */
+
+/**
+ * Acquire lock on the specified lock object.
+ *
+ * @param lock	    The lock object.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock );
+
+
+/**
+ * Try to acquire lock on the specified lock object.
+ *
+ * @param lock	    The lock object.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock );
+
+
+/**
+ * Release lock on the specified lock object.
+ *
+ * @param lock	    The lock object.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock );
+
+
+/**
+ * Destroy the lock object.
+ *
+ * @param lock	    The lock object.
+ *
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock );
+
+
+/** @} */
+
+PJ_END_DECL
+
+
+#endif	/* __PJ_LOCK_H__ */
+
diff --git a/pjlib/include/pj/log.h b/pjlib/include/pj/log.h
index 3f192da..4d8dc14 100644
--- a/pjlib/include/pj/log.h
+++ b/pjlib/include/pj/log.h
@@ -1,331 +1,331 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_LOG_H__

-#define __PJ_LOG_H__

-

-/**

- * @file log.h

- * @brief Logging Utility.

- */

-

-#include <pj/types.h>

-#include <stdarg.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_MISC Miscelaneous

- * @ingroup PJ

- */

-

-/**

- * @defgroup PJ_LOG Logging Facility

- * @ingroup PJ_MISC

- * @{

- *

- * The PJLIB logging facility is a configurable, flexible, and convenient

- * way to write logging or trace information.

- *

- * To write to the log, one uses construct like below:

- *

- * <pre>

- *   ...

- *   PJ_LOG(3, ("main.c", "Starting hello..."));

- *   ...

- *   PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid()));

- *   ...

- * </pre>

- *

- * In the above example, the number @b 3 controls the verbosity level of

- * the information (which means "information", by convention). The string

- * "main.c" specifies the source or sender of the message.

- *

- *

- * \section pj_log_quick_sample_sec Examples

- *

- * For examples, see:

- *  - @ref page_pjlib_samples_log_c.

- *

- */

-

-/**

- * Log decoration flag, to be specified with #pj_log_set_decor().

- */

-enum pj_log_decoration

-{

-    PJ_LOG_HAS_DAY_NAME   =   1, /**< Include day name [default: no].	     */

-    PJ_LOG_HAS_YEAR       =   2, /**< Include year digit [default: no]	     */

-    PJ_LOG_HAS_MONTH	  =   4, /**< Include month [default: no]	     */

-    PJ_LOG_HAS_DAY_OF_MON =   8, /**< Include day of month [default: no]     */

-    PJ_LOG_HAS_TIME	  =  16, /**< Include time [default: yes].	     */

-    PJ_LOG_HAS_MICRO_SEC  =  32, /**< Include microseconds [yes]             */

-    PJ_LOG_HAS_SENDER	  =  64, /**< Include sender in the log [yes].	     */

-    PJ_LOG_HAS_NEWLINE	  = 128, /**< Terminate each call with newline [yes].*/

-};

-

-/**

- * Write log message.

- * This is the main macro used to write text to the logging backend. 

- *

- * @param level	    The logging verbosity level. Lower number indicates higher

- *		    importance, with level zero indicates fatal error. Only

- *		    numeral argument is permitted (e.g. not variable).

- * @param arg	    Enclosed 'printf' like arguments, with the first 

- *		    argument is the sender, the second argument is format 

- *		    string and the following arguments are variable number of 

- *		    arguments suitable for the format string.

- *

- * Sample:

- * \verbatim

-   PJ_LOG(2, (__FILE__, "current value is %d", value));

-   \endverbatim

- * @hideinitializer

- */

-#define PJ_LOG(level,arg)	pj_log_wrapper_##level(arg)

-

-/**

- * Signature for function to be registered to the logging subsystem to

- * write the actual log message to some output device.

- *

- * @param level	    Log level.

- * @param data	    Log message.

- * @param len	    Message length.

- */

-typedef void pj_log_func(int level, const char *data, int len);

-

-/**

- * Default logging writer function used by front end logger function.

- * Application normally should NOT need to call this function, but

- * rather use the PJ_LOG macro.

- *

- * @param level	    Log level.

- * @param buffer    Log message.

- * @param len	    Message length.

- */

-PJ_DECL(void) pj_log_write(int level, const char *buffer, int len);

-

-

-#if PJ_LOG_MAX_LEVEL >= 1

-

-/**

- * Write to log.

- *

- * @param sender    Source of the message.

- * @param level	    Verbosity level.

- * @param format    Format.

- * @param marker    Marker.

- */

-PJ_DECL(void) pj_log(const char *sender, int level, 

-		     const char *format, va_list marker);

-

-/**

- * Change log output function. The front-end logging functions will call

- * this function to write the actual message to the desired device. 

- * By default, the front-end functions use pj_log_write() to write

- * the messages, unless it's changed by calling this function.

- *

- * @param func	    The function that will be called to write the log

- *		    messages to the desired device.

- */

-PJ_DECL(void) pj_log_set_log_func( pj_log_func *func );

-

-/**

- * Get the current log output function that is used to write log messages.

- *

- * @return	    Current log output function.

- */

-PJ_DECL(pj_log_func*) pj_log_get_log_func(void);

-

-/**

- * Set maximum log level. Application can call this function to set 

- * the desired level of verbosity of the logging messages. The bigger the

- * value, the more verbose the logging messages will be printed. However,

- * the maximum level of verbosity can not exceed compile time value of

- * PJ_LOG_MAX_LEVEL.

- *

- * @param level	    The maximum level of verbosity of the logging

- *		    messages (6=very detailed..1=error only, 0=disabled)

- */

-PJ_DECL(void) pj_log_set_level(int level);

-

-/**

- * Get current maximum log verbositylevel.

- *

- * @return	    Current log maximum level.

- */

-PJ_DECL(int) pj_log_get_level(void);

-

-/**

- * Set log decoration. The log decoration flag controls what are printed

- * to output device alongside the actual message. For example, application

- * can specify that date/time information should be displayed with each

- * log message.

- *

- * @param decor	    Bitmask combination of #pj_log_decoration to control

- *		    the layout of the log message.

- */

-PJ_DECL(void) pj_log_set_decor(unsigned decor);

-

-/**

- * Get current log decoration flag.

- *

- * @return	    Log decoration flag.

- */

-PJ_DECL(unsigned) pj_log_get_decor(void);

-

-

-#else	/* #if PJ_LOG_MAX_LEVEL >= 1 */

-

-/**

- * Change log output function. The front-end logging functions will call

- * this function to write the actual message to the desired device. 

- * By default, the front-end functions use pj_log_write() to write

- * the messages, unless it's changed by calling this function.

- *

- * @param func	    The function that will be called to write the log

- *		    messages to the desired device.

- */

-#  define pj_log_set_log_func(func)

-

-/**

- * Set maximum log level. Application can call this function to set 

- * the desired level of verbosity of the logging messages. The bigger the

- * value, the more verbose the logging messages will be printed. However,

- * the maximum level of verbosity can not exceed compile time value of

- * PJ_LOG_MAX_LEVEL.

- *

- * @param level	    The maximum level of verbosity of the logging

- *		    messages (6=very detailed..1=error only, 0=disabled)

- */

-#  define pj_log_set_level(level)

-

-/**

- * Set log decoration. The log decoration flag controls what are printed

- * to output device alongside the actual message. For example, application

- * can specify that date/time information should be displayed with each

- * log message.

- *

- * @param decor	    Bitmask combination of #pj_log_decoration to control

- *		    the layout of the log message.

- */

-#  define pj_log_set_decor(decor)

-

-#endif	/* #if PJ_LOG_MAX_LEVEL >= 1 */

-

-/** 

- * @}

- */

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * Log functions implementation prototypes.

- * These functions are called by PJ_LOG macros according to verbosity

- * level specified when calling the macro. Applications should not normally

- * need to call these functions directly.

- */

-

-/**

- * @def pj_log_wrapper_1(arg)

- * Internal function to write log with verbosity 1. Will evaluate to

- * empty expression if PJ_LOG_MAX_LEVEL is below 1.

- * @param arg       Log expression.

- */

-#if PJ_LOG_MAX_LEVEL >= 1

-    #define pj_log_wrapper_1(arg)	pj_log_1 arg

-    /** Internal function. */

-    PJ_DECL(void) pj_log_1(const char *src, const char *format, ...);

-#else

-    #define pj_log_wrapper_1(arg)

-#endif

-

-/**

- * @def pj_log_wrapper_2(arg)

- * Internal function to write log with verbosity 2. Will evaluate to

- * empty expression if PJ_LOG_MAX_LEVEL is below 2.

- * @param arg       Log expression.

- */

-#if PJ_LOG_MAX_LEVEL >= 2

-    #define pj_log_wrapper_2(arg)	pj_log_2 arg

-    /** Internal function. */

-    PJ_DECL(void) pj_log_2(const char *src, const char *format, ...);

-#else

-    #define pj_log_wrapper_2(arg)

-#endif

-

-/**

- * @def pj_log_wrapper_3(arg)

- * Internal function to write log with verbosity 3. Will evaluate to

- * empty expression if PJ_LOG_MAX_LEVEL is below 3.

- * @param arg       Log expression.

- */

-#if PJ_LOG_MAX_LEVEL >= 3

-    #define pj_log_wrapper_3(arg)	pj_log_3 arg

-    /** Internal function. */

-    PJ_DECL(void) pj_log_3(const char *src, const char *format, ...);

-#else

-    #define pj_log_wrapper_3(arg)

-#endif

-

-/**

- * @def pj_log_wrapper_4(arg)

- * Internal function to write log with verbosity 4. Will evaluate to

- * empty expression if PJ_LOG_MAX_LEVEL is below 4.

- * @param arg       Log expression.

- */

-#if PJ_LOG_MAX_LEVEL >= 4

-    #define pj_log_wrapper_4(arg)	pj_log_4 arg

-    /** Internal function. */

-    PJ_DECL(void) pj_log_4(const char *src, const char *format, ...);

-#else

-    #define pj_log_wrapper_4(arg)

-#endif

-

-/**

- * @def pj_log_wrapper_5(arg)

- * Internal function to write log with verbosity 5. Will evaluate to

- * empty expression if PJ_LOG_MAX_LEVEL is below 5.

- * @param arg       Log expression.

- */

-#if PJ_LOG_MAX_LEVEL >= 5

-    #define pj_log_wrapper_5(arg)	pj_log_5 arg

-    /** Internal function. */

-    PJ_DECL(void) pj_log_5(const char *src, const char *format, ...);

-#else

-    #define pj_log_wrapper_5(arg)

-#endif

-

-/**

- * @def pj_log_wrapper_6(arg)

- * Internal function to write log with verbosity 6. Will evaluate to

- * empty expression if PJ_LOG_MAX_LEVEL is below 6.

- * @param arg       Log expression.

- */

-#if PJ_LOG_MAX_LEVEL >= 6

-    #define pj_log_wrapper_6(arg)	pj_log_6 arg

-    /** Internal function. */

-    PJ_DECL(void) pj_log_6(const char *src, const char *format, ...);

-#else

-    #define pj_log_wrapper_6(arg)

-#endif

-

-

-PJ_END_DECL 

-

-#endif  /* __PJ_LOG_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_LOG_H__
+#define __PJ_LOG_H__
+
+/**
+ * @file log.h
+ * @brief Logging Utility.
+ */
+
+#include <pj/types.h>
+#include <stdarg.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_MISC Miscelaneous
+ * @ingroup PJ
+ */
+
+/**
+ * @defgroup PJ_LOG Logging Facility
+ * @ingroup PJ_MISC
+ * @{
+ *
+ * The PJLIB logging facility is a configurable, flexible, and convenient
+ * way to write logging or trace information.
+ *
+ * To write to the log, one uses construct like below:
+ *
+ * <pre>
+ *   ...
+ *   PJ_LOG(3, ("main.c", "Starting hello..."));
+ *   ...
+ *   PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid()));
+ *   ...
+ * </pre>
+ *
+ * In the above example, the number @b 3 controls the verbosity level of
+ * the information (which means "information", by convention). The string
+ * "main.c" specifies the source or sender of the message.
+ *
+ *
+ * \section pj_log_quick_sample_sec Examples
+ *
+ * For examples, see:
+ *  - @ref page_pjlib_samples_log_c.
+ *
+ */
+
+/**
+ * Log decoration flag, to be specified with #pj_log_set_decor().
+ */
+enum pj_log_decoration
+{
+    PJ_LOG_HAS_DAY_NAME   =   1, /**< Include day name [default: no].	     */
+    PJ_LOG_HAS_YEAR       =   2, /**< Include year digit [default: no]	     */
+    PJ_LOG_HAS_MONTH	  =   4, /**< Include month [default: no]	     */
+    PJ_LOG_HAS_DAY_OF_MON =   8, /**< Include day of month [default: no]     */
+    PJ_LOG_HAS_TIME	  =  16, /**< Include time [default: yes].	     */
+    PJ_LOG_HAS_MICRO_SEC  =  32, /**< Include microseconds [yes]             */
+    PJ_LOG_HAS_SENDER	  =  64, /**< Include sender in the log [yes].	     */
+    PJ_LOG_HAS_NEWLINE	  = 128, /**< Terminate each call with newline [yes].*/
+};
+
+/**
+ * Write log message.
+ * This is the main macro used to write text to the logging backend. 
+ *
+ * @param level	    The logging verbosity level. Lower number indicates higher
+ *		    importance, with level zero indicates fatal error. Only
+ *		    numeral argument is permitted (e.g. not variable).
+ * @param arg	    Enclosed 'printf' like arguments, with the first 
+ *		    argument is the sender, the second argument is format 
+ *		    string and the following arguments are variable number of 
+ *		    arguments suitable for the format string.
+ *
+ * Sample:
+ * \verbatim
+   PJ_LOG(2, (__FILE__, "current value is %d", value));
+   \endverbatim
+ * @hideinitializer
+ */
+#define PJ_LOG(level,arg)	pj_log_wrapper_##level(arg)
+
+/**
+ * Signature for function to be registered to the logging subsystem to
+ * write the actual log message to some output device.
+ *
+ * @param level	    Log level.
+ * @param data	    Log message.
+ * @param len	    Message length.
+ */
+typedef void pj_log_func(int level, const char *data, int len);
+
+/**
+ * Default logging writer function used by front end logger function.
+ * Application normally should NOT need to call this function, but
+ * rather use the PJ_LOG macro.
+ *
+ * @param level	    Log level.
+ * @param buffer    Log message.
+ * @param len	    Message length.
+ */
+PJ_DECL(void) pj_log_write(int level, const char *buffer, int len);
+
+
+#if PJ_LOG_MAX_LEVEL >= 1
+
+/**
+ * Write to log.
+ *
+ * @param sender    Source of the message.
+ * @param level	    Verbosity level.
+ * @param format    Format.
+ * @param marker    Marker.
+ */
+PJ_DECL(void) pj_log(const char *sender, int level, 
+		     const char *format, va_list marker);
+
+/**
+ * Change log output function. The front-end logging functions will call
+ * this function to write the actual message to the desired device. 
+ * By default, the front-end functions use pj_log_write() to write
+ * the messages, unless it's changed by calling this function.
+ *
+ * @param func	    The function that will be called to write the log
+ *		    messages to the desired device.
+ */
+PJ_DECL(void) pj_log_set_log_func( pj_log_func *func );
+
+/**
+ * Get the current log output function that is used to write log messages.
+ *
+ * @return	    Current log output function.
+ */
+PJ_DECL(pj_log_func*) pj_log_get_log_func(void);
+
+/**
+ * Set maximum log level. Application can call this function to set 
+ * the desired level of verbosity of the logging messages. The bigger the
+ * value, the more verbose the logging messages will be printed. However,
+ * the maximum level of verbosity can not exceed compile time value of
+ * PJ_LOG_MAX_LEVEL.
+ *
+ * @param level	    The maximum level of verbosity of the logging
+ *		    messages (6=very detailed..1=error only, 0=disabled)
+ */
+PJ_DECL(void) pj_log_set_level(int level);
+
+/**
+ * Get current maximum log verbositylevel.
+ *
+ * @return	    Current log maximum level.
+ */
+PJ_DECL(int) pj_log_get_level(void);
+
+/**
+ * Set log decoration. The log decoration flag controls what are printed
+ * to output device alongside the actual message. For example, application
+ * can specify that date/time information should be displayed with each
+ * log message.
+ *
+ * @param decor	    Bitmask combination of #pj_log_decoration to control
+ *		    the layout of the log message.
+ */
+PJ_DECL(void) pj_log_set_decor(unsigned decor);
+
+/**
+ * Get current log decoration flag.
+ *
+ * @return	    Log decoration flag.
+ */
+PJ_DECL(unsigned) pj_log_get_decor(void);
+
+
+#else	/* #if PJ_LOG_MAX_LEVEL >= 1 */
+
+/**
+ * Change log output function. The front-end logging functions will call
+ * this function to write the actual message to the desired device. 
+ * By default, the front-end functions use pj_log_write() to write
+ * the messages, unless it's changed by calling this function.
+ *
+ * @param func	    The function that will be called to write the log
+ *		    messages to the desired device.
+ */
+#  define pj_log_set_log_func(func)
+
+/**
+ * Set maximum log level. Application can call this function to set 
+ * the desired level of verbosity of the logging messages. The bigger the
+ * value, the more verbose the logging messages will be printed. However,
+ * the maximum level of verbosity can not exceed compile time value of
+ * PJ_LOG_MAX_LEVEL.
+ *
+ * @param level	    The maximum level of verbosity of the logging
+ *		    messages (6=very detailed..1=error only, 0=disabled)
+ */
+#  define pj_log_set_level(level)
+
+/**
+ * Set log decoration. The log decoration flag controls what are printed
+ * to output device alongside the actual message. For example, application
+ * can specify that date/time information should be displayed with each
+ * log message.
+ *
+ * @param decor	    Bitmask combination of #pj_log_decoration to control
+ *		    the layout of the log message.
+ */
+#  define pj_log_set_decor(decor)
+
+#endif	/* #if PJ_LOG_MAX_LEVEL >= 1 */
+
+/** 
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Log functions implementation prototypes.
+ * These functions are called by PJ_LOG macros according to verbosity
+ * level specified when calling the macro. Applications should not normally
+ * need to call these functions directly.
+ */
+
+/**
+ * @def pj_log_wrapper_1(arg)
+ * Internal function to write log with verbosity 1. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 1.
+ * @param arg       Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 1
+    #define pj_log_wrapper_1(arg)	pj_log_1 arg
+    /** Internal function. */
+    PJ_DECL(void) pj_log_1(const char *src, const char *format, ...);
+#else
+    #define pj_log_wrapper_1(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_2(arg)
+ * Internal function to write log with verbosity 2. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 2.
+ * @param arg       Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 2
+    #define pj_log_wrapper_2(arg)	pj_log_2 arg
+    /** Internal function. */
+    PJ_DECL(void) pj_log_2(const char *src, const char *format, ...);
+#else
+    #define pj_log_wrapper_2(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_3(arg)
+ * Internal function to write log with verbosity 3. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 3.
+ * @param arg       Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 3
+    #define pj_log_wrapper_3(arg)	pj_log_3 arg
+    /** Internal function. */
+    PJ_DECL(void) pj_log_3(const char *src, const char *format, ...);
+#else
+    #define pj_log_wrapper_3(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_4(arg)
+ * Internal function to write log with verbosity 4. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 4.
+ * @param arg       Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 4
+    #define pj_log_wrapper_4(arg)	pj_log_4 arg
+    /** Internal function. */
+    PJ_DECL(void) pj_log_4(const char *src, const char *format, ...);
+#else
+    #define pj_log_wrapper_4(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_5(arg)
+ * Internal function to write log with verbosity 5. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 5.
+ * @param arg       Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 5
+    #define pj_log_wrapper_5(arg)	pj_log_5 arg
+    /** Internal function. */
+    PJ_DECL(void) pj_log_5(const char *src, const char *format, ...);
+#else
+    #define pj_log_wrapper_5(arg)
+#endif
+
+/**
+ * @def pj_log_wrapper_6(arg)
+ * Internal function to write log with verbosity 6. Will evaluate to
+ * empty expression if PJ_LOG_MAX_LEVEL is below 6.
+ * @param arg       Log expression.
+ */
+#if PJ_LOG_MAX_LEVEL >= 6
+    #define pj_log_wrapper_6(arg)	pj_log_6 arg
+    /** Internal function. */
+    PJ_DECL(void) pj_log_6(const char *src, const char *format, ...);
+#else
+    #define pj_log_wrapper_6(arg)
+#endif
+
+
+PJ_END_DECL 
+
+#endif  /* __PJ_LOG_H__ */
+
diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h
index edd5d1d..7b03c96 100644
--- a/pjlib/include/pj/os.h
+++ b/pjlib/include/pj/os.h
@@ -1,995 +1,995 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_OS_H__

-#define __PJ_OS_H__

-

-/**

- * @file os.h

- * @brief OS dependent functions

- */

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_OS Operating System Dependent Functionality.

- * @ingroup PJ

- */

-

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @defgroup PJ_THREAD Threads

- * @ingroup PJ_OS

- * @{

- * This module provides multithreading API.

- *

- * \section pj_thread_examples_sec Examples

- *

- * For examples, please see:

- *  - \ref page_pjlib_thread_test

- *  - \ref page_pjlib_sleep_test

- *

- */

-

-/**

- * Thread creation flags:

- * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended.

- */

-typedef enum pj_thread_create_flags

-{

-    PJ_THREAD_SUSPENDED = 1

-} pj_thread_create_flags;

-

-

-/**

- * Specify this as \a stack_size argument in #pj_thread_create() to specify

- * that thread should use default stack size for the current platform.

- */

-#define PJ_THREAD_DEFAULT_STACK_SIZE    0

-

-/**

- * Type of thread entry function.

- */

-typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*);

-

-/**

- * Size of thread struct.

- */

-#if !defined(PJ_THREAD_DESC_SIZE)

-#   define PJ_THREAD_DESC_SIZE	    (16)

-#endif

-

-/**

- * Thread structure, to thread's state when the thread is created by external

- * or native API. 

- */

-typedef long pj_thread_desc[PJ_THREAD_DESC_SIZE];

-

-/**

- * Get process ID.

- * @return process ID.

- */

-PJ_DECL(pj_uint32_t) pj_getpid(void);

-

-/**

- * Create a new thread.

- *

- * @param pool          The memory pool from which the thread record 

- *                      will be allocated from.

- * @param thread_name   The optional name to be assigned to the thread.

- * @param proc          Thread entry function.

- * @param arg           Argument to be passed to the thread entry function.

- * @param stack_size    The size of the stack for the new thread, or ZERO or

- *                      PJ_THREAD_DEFAULT_STACK_SIZE to let the 

- *		        library choose the reasonable size for the stack. 

- *                      For some systems, the stack will be allocated from 

- *                      the pool, so the pool must have suitable capacity.

- * @param flags         Flags for thread creation, which is bitmask combination 

- *                      from enum pj_thread_create_flags.

- * @param thread        Pointer to hold the newly created thread.

- *

- * @return	        PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(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 **thread );

-

-/**

- * Register a thread that was created by external or native API to PJLIB.

- * This function must be called in the context of the thread being registered.

- * When the thread is created by external function or API call,

- * it must be 'registered' to PJLIB using pj_thread_register(), so that it can

- * cooperate with PJLIB's framework. During registration, some data needs to

- * be maintained, and this data must remain available during the thread's 

- * lifetime.

- *

- * @param thread_name   The optional name to be assigned to the thread.

- * @param desc          Thread descriptor, which must be available throughout 

- *                      the lifetime of the thread.

- * @param thread        Pointer to hold the created thread handle.

- *

- * @return              PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name,

-					  pj_thread_desc desc,

-					  pj_thread_t **thread);

-

-/**

- * Get thread name.

- *

- * @param thread    The thread handle.

- *

- * @return Thread name as null terminated string.

- */

-PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread);

-

-/**

- * Resume a suspended thread.

- *

- * @param thread    The thread handle.

- *

- * @return zero on success.

- */

-PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread);

-

-/**

- * Get the current thread.

- *

- * @return Thread handle of current thread.

- */

-PJ_DECL(pj_thread_t*) pj_thread_this(void);

-

-/**

- * Join thread.

- * This function will block the caller thread until the specified thread exits.

- *

- * @param thread    The thread handle.

- *

- * @return zero on success.

- */

-PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread);

-

-

-/**

- * Destroy thread and release resources allocated for the thread.

- * However, the memory allocated for the pj_thread_t itself will only be released

- * when the pool used to create the thread is destroyed.

- *

- * @param thread    The thread handle.

- *

- * @return zero on success.

- */

-PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread);

-

-

-/**

- * Put the current thread to sleep for the specified miliseconds.

- *

- * @param msec Miliseconds delay.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec);

-

-/**

- * @def PJ_CHECK_STACK()

- * PJ_CHECK_STACK() macro is used to check the sanity of the stack.

- * The OS implementation may check that no stack overflow occurs, and

- * it also may collect statistic about stack usage.

- */

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-

-#  define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__)

-

-/** @internal

- * The implementation of stack checking. 

- */

-PJ_DECL(void) pj_thread_check_stack(const char *file, int line);

-

-/** @internal

- * Get maximum stack usage statistic. 

- */

-PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread);

-

-/** @internal

- * Dump thread stack status. 

- */

-PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread,

-					      const char **file,

-					      int *line);

-#else

-

-#  define PJ_CHECK_STACK()

-/** pj_thread_get_stack_max_usage() for the thread */

-#  define pj_thread_get_stack_max_usage(thread)	    0

-/** pj_thread_get_stack_info() for the thread */

-#  define pj_thread_get_stack_info(thread,f,l)	    (*(f)="",*(l)=0)

-#endif	/* PJ_OS_HAS_CHECK_STACK */

-

-/**

- * @}

- */

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @defgroup PJ_TLS Thread Local Storage.

- * @ingroup PJ_OS

- * @{

- */

-

-/** 

- * Allocate thread local storage index. The initial value of the variable at

- * the index is zero.

- *

- * @param index	    Pointer to hold the return value.

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index);

-

-/**

- * Deallocate thread local variable.

- *

- * @param index	    The variable index.

- */

-PJ_DECL(void) pj_thread_local_free(long index);

-

-/**

- * Set the value of thread local variable.

- *

- * @param index	    The index of the variable.

- * @param value	    The value.

- */

-PJ_DECL(pj_status_t) pj_thread_local_set(long index, void *value);

-

-/**

- * Get the value of thread local variable.

- *

- * @param index	    The index of the variable.

- * @return	    The value.

- */

-PJ_DECL(void*) pj_thread_local_get(long index);

-

-

-/**

- * @}

- */

-

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @defgroup PJ_ATOMIC Atomic Variables

- * @ingroup PJ_OS

- * @{

- *

- * This module provides API to manipulate atomic variables.

- *

- * \section pj_atomic_examples_sec Examples

- *

- * For some example codes, please see:

- *  - @ref page_pjlib_atomic_test

- */

-

-

-/**

- * Create atomic variable.

- *

- * @param pool	    The pool.

- * @param initial   The initial value of the atomic variable.

- * @param atomic    Pointer to hold the atomic variable upon return.

- *

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool, 

-				       pj_atomic_value_t initial,

-				       pj_atomic_t **atomic );

-

-/**

- * Destroy atomic variable.

- *

- * @param atomic_var	the atomic variable.

- *

- * @return PJ_SUCCESS if success.

- */

-PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var );

-

-/**

- * Set the value of an atomic type, and return the previous value.

- *

- * @param atomic_var	the atomic variable.

- * @param value		value to be set to the variable.

- */

-PJ_DECL(void) pj_atomic_set( pj_atomic_t *atomic_var, 

-			     pj_atomic_value_t value);

-

-/**

- * Get the value of an atomic type.

- *

- * @param atomic_var	the atomic variable.

- *

- * @return the value of the atomic variable.

- */

-PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var);

-

-/**

- * Increment the value of an atomic type.

- *

- * @param atomic_var	the atomic variable.

- */

-PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var);

-

-/**

- * Increment the value of an atomic type and get the result.

- *

- * @param atomic_var	the atomic variable.

- *

- * @return              The incremented value.

- */

-PJ_DECL(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var);

-

-/**

- * Decrement the value of an atomic type.

- *

- * @param atomic_var	the atomic variable.

- */

-PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var);

-

-/**

- * Decrement the value of an atomic type and get the result.

- *

- * @param atomic_var	the atomic variable.

- *

- * @return              The decremented value.

- */

-PJ_DECL(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var);

-

-/**

- * Add a value to an atomic type.

- *

- * @param atomic_var	The atomic variable.

- * @param value		Value to be added.

- */

-PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var,

-			     pj_atomic_value_t value);

-

-/**

- * Add a value to an atomic type and get the result.

- *

- * @param atomic_var	The atomic variable.

- * @param value		Value to be added.

- *

- * @return              The result after the addition.

- */

-PJ_DECL(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,

-			                          pj_atomic_value_t value);

-

-/**

- * @}

- */

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @defgroup PJ_MUTEX Mutexes.

- * @ingroup PJ_OS

- * @{

- *

- * Mutex manipulation. Alternatively, application can use higher abstraction

- * for lock objects, which provides uniform API for all kinds of lock 

- * mechanisms, including mutex. See @ref PJ_LOCK for more information.

- */

-

-/**

- * Mutex types:

- *  - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent.

- *  - PJ_MUTEX_SIMPLE: non-recursive mutex.

- *  - PJ_MUTEX_RECURSIVE: recursive mutex.

- */

-typedef enum pj_mutex_type_e

-{

-    PJ_MUTEX_DEFAULT,

-    PJ_MUTEX_SIMPLE,

-    PJ_MUTEX_RECURSE,

-} pj_mutex_type_e;

-

-

-/**

- * Create mutex of the specified type.

- *

- * @param pool	    The pool.

- * @param name	    Name to be associated with the mutex (for debugging).

- * @param type	    The type of the mutex, of type #pj_mutex_type_e.

- * @param mutex	    Pointer to hold the returned mutex instance.

- *

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool, 

-                                     const char *name,

-				     int type, 

-                                     pj_mutex_t **mutex);

-

-/**

- * Create simple, non-recursive mutex.

- * This function is a simple wrapper for #pj_mutex_create to create 

- * non-recursive mutex.

- *

- * @param pool	    The pool.

- * @param name	    Mutex name.

- * @param mutex	    Pointer to hold the returned mutex instance.

- *

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,

-					     pj_mutex_t **mutex );

-

-/**

- * Create recursive mutex.

- * This function is a simple wrapper for #pj_mutex_create to create 

- * recursive mutex.

- *

- * @param pool	    The pool.

- * @param name	    Mutex name.

- * @param mutex	    Pointer to hold the returned mutex instance.

- *

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,

-					        const char *name,

-						pj_mutex_t **mutex );

-

-/**

- * Acquire mutex lock.

- *

- * @param mutex	    The mutex.

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex);

-

-/**

- * Release mutex lock.

- *

- * @param mutex	    The mutex.

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex);

-

-/**

- * Try to acquire mutex lock.

- *

- * @param mutex	    The mutex.

- * @return	    PJ_SUCCESS on success, or the error code if the

- *		    lock couldn't be acquired.

- */

-PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex);

-

-/**

- * Destroy mutex.

- *

- * @param mutex	    Te mutex.

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex);

-

-/**

- * Determine whether calling thread is owning the mutex (only available when

- * PJ_DEBUG is set).

- * @param mutex	    The mutex.

- * @return	    Non-zero if yes.

- */

-#if defined(PJ_DEBUG) && PJ_DEBUG != 0

-   PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex);

-#else

-#  define pj_mutex_is_locked(mutex)	    1

-#endif

-

-/**

- * @}

- */

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @defgroup PJ_CRIT_SEC Critical sections.

- * @ingroup PJ_OS

- * @{

- * Critical section protection can be used to protect regions where:

- *  - mutual exclusion protection is needed.

- *  - it's rather too expensive to create a mutex.

- *  - the time spent in the region is very very brief.

- *

- * Critical section is a global object, and it prevents any threads from

- * entering any regions that are protected by critical section once a thread

- * is already in the section.

- *

- * Critial section is \a not recursive!

- *

- * Application <b>MUST NOT</b> call any functions that may cause current

- * thread to block (such as allocating memory, performing I/O, locking mutex,

- * etc.) while holding the critical section.

- */

-/**

- * Enter critical section.

- */

-PJ_DECL(void) pj_enter_critical_section(void);

-

-/**

- * Leave critical section.

- */

-PJ_DECL(void) pj_leave_critical_section(void);

-

-/**

- * @}

- */

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-/**

- * @defgroup PJ_SEM Semaphores.

- * @ingroup PJ_OS

- * @{

- *

- * This module provides abstraction for semaphores, where available.

- */

-

-/**

- * Create semaphore.

- *

- * @param pool	    The pool.

- * @param name	    Name to be assigned to the semaphore (for logging purpose)

- * @param initial   The initial count of the semaphore.

- * @param max	    The maximum count of the semaphore.

- * @param sem	    Pointer to hold the semaphore created.

- *

- * @return	    PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool, 

-                                    const char *name,

-				    unsigned initial, 

-                                    unsigned max,

-				    pj_sem_t **sem);

-

-/**

- * Wait for semaphore.

- *

- * @param sem	The semaphore.

- *

- * @return	PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem);

-

-/**

- * Try wait for semaphore.

- *

- * @param sem	The semaphore.

- *

- * @return	PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem);

-

-/**

- * Release semaphore.

- *

- * @param sem	The semaphore.

- *

- * @return	PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem);

-

-/**

- * Destroy semaphore.

- *

- * @param sem	The semaphore.

- *

- * @return	PJ_SUCCESS on success, or the error code.

- */

-PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem);

-

-/**

- * @}

- */

-#endif	/* PJ_HAS_SEMAPHORE */

-

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

-/**

- * @defgroup PJ_EVENT Event Object.

- * @ingroup PJ_OS

- * @{

- *

- * This module provides abstraction to event object (e.g. Win32 Event) where

- * available. Event objects can be used for synchronization among threads.

- */

-

-/**

- * Create event object.

- *

- * @param pool		The pool.

- * @param name		The name of the event object (for logging purpose).

- * @param manual_reset	Specify whether the event is manual-reset

- * @param initial	Specify the initial state of the event object.

- * @param event		Pointer to hold the returned event object.

- *

- * @return event handle, or NULL if failed.

- */

-PJ_DECL(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,

-				     pj_bool_t manual_reset, pj_bool_t initial,

-				     pj_event_t **event);

-

-/**

- * Wait for event to be signaled.

- *

- * @param event	    The event object.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event);

-

-/**

- * Try wait for event object to be signalled.

- *

- * @param event The event object.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event);

-

-/**

- * Set the event object state to signaled. For auto-reset event, this 

- * will only release the first thread that are waiting on the event. For

- * manual reset event, the state remains signaled until the event is reset.

- * If there is no thread waiting on the event, the event object state 

- * remains signaled.

- *

- * @param event	    The event object.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event);

-

-/**

- * Set the event object to signaled state to release appropriate number of

- * waiting threads and then reset the event object to non-signaled. For

- * manual-reset event, this function will release all waiting threads. For

- * auto-reset event, this function will only release one waiting thread.

- *

- * @param event	    The event object.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event);

-

-/**

- * Set the event object state to non-signaled.

- *

- * @param event	    The event object.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event);

-

-/**

- * Destroy the event object.

- *

- * @param event	    The event object.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event);

-

-/**

- * @}

- */

-#endif	/* PJ_HAS_EVENT_OBJ */

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @addtogroup PJ_TIME Time Data Type and Manipulation.

- * @ingroup PJ_OS

- * @{

- * This module provides API for manipulating time.

- *

- * \section pj_time_examples_sec Examples

- *

- * For examples, please see:

- *  - \ref page_pjlib_sleep_test

- */

-

-/**

- * Get current time of day in local representation.

- *

- * @param tv	Variable to store the result.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv);

-

-

-/**

- * Parse time value into date/time representation.

- *

- * @param tv	The time.

- * @param pt	Variable to store the date time result.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt);

-

-/**

- * Encode date/time to time value.

- *

- * @param pt	The date/time.

- * @param tv	Variable to store time value result.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);

-

-/**

- * Convert local time to GMT.

- *

- * @param tv	Time to convert.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);

-

-/**

- * Convert GMT to local time.

- *

- * @param tv	Time to convert.

- *

- * @return zero if successfull.

- */

-PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);

-

-/**

- * @}

- */

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

-

-/**

- * @defgroup PJ_TERM Terminal

- * @ingroup PJ_OS

- * @{

- */

-

-/**

- * Set current terminal color.

- *

- * @param color	    The RGB color.

- *

- * @return zero on success.

- */

-PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color);

-

-/**

- * Get current terminal foreground color.

- *

- * @return RGB color.

- */

-PJ_DECL(pj_color_t) pj_term_get_color(void);

-

-/**

- * @}

- */

-

-#endif	/* PJ_TERM_HAS_COLOR */

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @defgroup PJ_TIMESTAMP High Resolution Timestamp

- * @ingroup PJ_OS

- * @{

- *

- * PJLIB provides <b>High Resolution Timestamp</b> API to access highest 

- * resolution timestamp value provided by the platform. The API is usefull

- * to measure precise elapsed time, and can be used in applications such

- * as profiling.

- *

- * The timestamp value is represented in cycles, and can be related to

- * normal time (in seconds or sub-seconds) using various functions provided.

- *

- * \section pj_timestamp_examples_sec Examples

- *

- * For examples, please see:

- *  - \ref page_pjlib_sleep_test

- *  - \ref page_pjlib_timestamp_test

- */

-

-/*

- * High resolution timer.

- */

-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

-

-/**

- * This structure represents high resolution (64bit) time value. The time

- * values represent time in cycles, which is retrieved by calling

- * #pj_get_timestamp().

- */

-typedef union pj_timestamp

-{

-    struct

-    {

-#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0

-	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */

-	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */

-#else

-	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */

-	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */

-#endif

-    } u32;                  /**< The 64-bit value as two 32-bit values. */

-

-#if PJ_HAS_INT64

-    pj_uint64_t u64;        /**< The whole 64-bit value, where available. */

-#endif

-} pj_timestamp;

-

-

-/**

- * Acquire high resolution timer value. The time value are stored

- * in cycles.

- *

- * @param ts	    High resolution timer value.

- * @return	    PJ_SUCCESS or the appropriate error code.

- *

- * @see pj_get_timestamp_freq().

- */

-PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts);

-

-/**

- * Get high resolution timer frequency, in cycles per second.

- *

- * @param freq	    Timer frequency, in cycles per second.

- * @return	    PJ_SUCCESS or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq);

-

-/**

- * Add timestamp t2 to t1.

- * @param t1	    t1.

- * @param t2	    t2.

- */

-PJ_INLINE(void) pj_add_timestamp(pj_timestamp *t1, const pj_timestamp *t2)

-{

-#if PJ_HAS_INT64

-    t1->u64 += t2->u64;

-#else

-    pj_uint32_t old = t1->u32.lo;

-    t1->u32.hi += t2->u32.hi;

-    t1->u32.lo += t2->u32.lo;

-    if (t1->u32.lo < old)

-	++t1->u32.hi;

-#endif

-}

-

-/**

- * Substract timestamp t2 from t1.

- * @param t1	    t1.

- * @param t2	    t2.

- */

-PJ_INLINE(void) pj_sub_timestamp(pj_timestamp *t1, const pj_timestamp *t2)

-{

-#if PJ_HAS_INT64

-    t1->u64 -= t2->u64;

-#else

-    t1->u32.hi -= t2->u32.hi;

-    if (t1->u32.lo >= t2->u32.lo)

-	t1->u32.lo -= t2->u32.lo;

-    else {

-	t1->u32.lo -= t2->u32.lo;

-	--t1->u32.hi;

-    }

-#endif

-}

-

-/**

- * Calculate the elapsed time, and store it in pj_time_val.

- * This function calculates the elapsed time using highest precision

- * calculation that is available for current platform, considering

- * whether floating point or 64-bit precision arithmetic is available. 

- * For maximum portability, application should prefer to use this function

- * rather than calculating the elapsed time by itself.

- *

- * @param start     The starting timestamp.

- * @param stop      The end timestamp.

- *

- * @return	    Elapsed time as #pj_time_val.

- *

- * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec()

- */

-PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start,

-                                      const pj_timestamp *stop );

-

-/**

- * Calculate the elapsed time in 32-bit microseconds.

- * This function calculates the elapsed time using highest precision

- * calculation that is available for current platform, considering

- * whether floating point or 64-bit precision arithmetic is available. 

- * For maximum portability, application should prefer to use this function

- * rather than calculating the elapsed time by itself.

- *

- * @param start     The starting timestamp.

- * @param stop      The end timestamp.

- *

- * @return	    Elapsed time in microsecond.

- *

- * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec()

- */

-PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,

-                                      const pj_timestamp *stop );

-

-/**

- * Calculate the elapsed time in 32-bit nanoseconds.

- * This function calculates the elapsed time using highest precision

- * calculation that is available for current platform, considering

- * whether floating point or 64-bit precision arithmetic is available. 

- * For maximum portability, application should prefer to use this function

- * rather than calculating the elapsed time by itself.

- *

- * @param start     The starting timestamp.

- * @param stop      The end timestamp.

- *

- * @return	    Elapsed time in nanoseconds.

- *

- * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec()

- */

-PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,

-                                         const pj_timestamp *stop );

-

-/**

- * Calculate the elapsed time in 32-bit cycles.

- * This function calculates the elapsed time using highest precision

- * calculation that is available for current platform, considering

- * whether floating point or 64-bit precision arithmetic is available. 

- * For maximum portability, application should prefer to use this function

- * rather than calculating the elapsed time by itself.

- *

- * @param start     The starting timestamp.

- * @param stop      The end timestamp.

- *

- * @return	    Elapsed time in cycles.

- *

- * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec()

- */

-PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,

-                                       const pj_timestamp *stop );

-

-

-#endif	/* PJ_HAS_HIGH_RES_TIMER */

-

-/** @} */

-

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * Internal PJLIB function to initialize the threading subsystem.

- * @return          PJ_SUCCESS or the appropriate error code.

- */

-pj_status_t pj_thread_init(void);

-

-

-PJ_END_DECL

-

-#endif  /* __PJ_OS_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_OS_H__
+#define __PJ_OS_H__
+
+/**
+ * @file os.h
+ * @brief OS dependent functions
+ */
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_OS Operating System Dependent Functionality.
+ * @ingroup PJ
+ */
+
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_THREAD Threads
+ * @ingroup PJ_OS
+ * @{
+ * This module provides multithreading API.
+ *
+ * \section pj_thread_examples_sec Examples
+ *
+ * For examples, please see:
+ *  - \ref page_pjlib_thread_test
+ *  - \ref page_pjlib_sleep_test
+ *
+ */
+
+/**
+ * Thread creation flags:
+ * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended.
+ */
+typedef enum pj_thread_create_flags
+{
+    PJ_THREAD_SUSPENDED = 1
+} pj_thread_create_flags;
+
+
+/**
+ * Specify this as \a stack_size argument in #pj_thread_create() to specify
+ * that thread should use default stack size for the current platform.
+ */
+#define PJ_THREAD_DEFAULT_STACK_SIZE    0
+
+/**
+ * Type of thread entry function.
+ */
+typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*);
+
+/**
+ * Size of thread struct.
+ */
+#if !defined(PJ_THREAD_DESC_SIZE)
+#   define PJ_THREAD_DESC_SIZE	    (16)
+#endif
+
+/**
+ * Thread structure, to thread's state when the thread is created by external
+ * or native API. 
+ */
+typedef long pj_thread_desc[PJ_THREAD_DESC_SIZE];
+
+/**
+ * Get process ID.
+ * @return process ID.
+ */
+PJ_DECL(pj_uint32_t) pj_getpid(void);
+
+/**
+ * Create a new thread.
+ *
+ * @param pool          The memory pool from which the thread record 
+ *                      will be allocated from.
+ * @param thread_name   The optional name to be assigned to the thread.
+ * @param proc          Thread entry function.
+ * @param arg           Argument to be passed to the thread entry function.
+ * @param stack_size    The size of the stack for the new thread, or ZERO or
+ *                      PJ_THREAD_DEFAULT_STACK_SIZE to let the 
+ *		        library choose the reasonable size for the stack. 
+ *                      For some systems, the stack will be allocated from 
+ *                      the pool, so the pool must have suitable capacity.
+ * @param flags         Flags for thread creation, which is bitmask combination 
+ *                      from enum pj_thread_create_flags.
+ * @param thread        Pointer to hold the newly created thread.
+ *
+ * @return	        PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(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 **thread );
+
+/**
+ * Register a thread that was created by external or native API to PJLIB.
+ * This function must be called in the context of the thread being registered.
+ * When the thread is created by external function or API call,
+ * it must be 'registered' to PJLIB using pj_thread_register(), so that it can
+ * cooperate with PJLIB's framework. During registration, some data needs to
+ * be maintained, and this data must remain available during the thread's 
+ * lifetime.
+ *
+ * @param thread_name   The optional name to be assigned to the thread.
+ * @param desc          Thread descriptor, which must be available throughout 
+ *                      the lifetime of the thread.
+ * @param thread        Pointer to hold the created thread handle.
+ *
+ * @return              PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name,
+					  pj_thread_desc desc,
+					  pj_thread_t **thread);
+
+/**
+ * Get thread name.
+ *
+ * @param thread    The thread handle.
+ *
+ * @return Thread name as null terminated string.
+ */
+PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread);
+
+/**
+ * Resume a suspended thread.
+ *
+ * @param thread    The thread handle.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread);
+
+/**
+ * Get the current thread.
+ *
+ * @return Thread handle of current thread.
+ */
+PJ_DECL(pj_thread_t*) pj_thread_this(void);
+
+/**
+ * Join thread.
+ * This function will block the caller thread until the specified thread exits.
+ *
+ * @param thread    The thread handle.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread);
+
+
+/**
+ * Destroy thread and release resources allocated for the thread.
+ * However, the memory allocated for the pj_thread_t itself will only be released
+ * when the pool used to create the thread is destroyed.
+ *
+ * @param thread    The thread handle.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread);
+
+
+/**
+ * Put the current thread to sleep for the specified miliseconds.
+ *
+ * @param msec Miliseconds delay.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec);
+
+/**
+ * @def PJ_CHECK_STACK()
+ * PJ_CHECK_STACK() macro is used to check the sanity of the stack.
+ * The OS implementation may check that no stack overflow occurs, and
+ * it also may collect statistic about stack usage.
+ */
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+
+#  define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__)
+
+/** @internal
+ * The implementation of stack checking. 
+ */
+PJ_DECL(void) pj_thread_check_stack(const char *file, int line);
+
+/** @internal
+ * Get maximum stack usage statistic. 
+ */
+PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread);
+
+/** @internal
+ * Dump thread stack status. 
+ */
+PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread,
+					      const char **file,
+					      int *line);
+#else
+
+#  define PJ_CHECK_STACK()
+/** pj_thread_get_stack_max_usage() for the thread */
+#  define pj_thread_get_stack_max_usage(thread)	    0
+/** pj_thread_get_stack_info() for the thread */
+#  define pj_thread_get_stack_info(thread,f,l)	    (*(f)="",*(l)=0)
+#endif	/* PJ_OS_HAS_CHECK_STACK */
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_TLS Thread Local Storage.
+ * @ingroup PJ_OS
+ * @{
+ */
+
+/** 
+ * Allocate thread local storage index. The initial value of the variable at
+ * the index is zero.
+ *
+ * @param index	    Pointer to hold the return value.
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index);
+
+/**
+ * Deallocate thread local variable.
+ *
+ * @param index	    The variable index.
+ */
+PJ_DECL(void) pj_thread_local_free(long index);
+
+/**
+ * Set the value of thread local variable.
+ *
+ * @param index	    The index of the variable.
+ * @param value	    The value.
+ */
+PJ_DECL(pj_status_t) pj_thread_local_set(long index, void *value);
+
+/**
+ * Get the value of thread local variable.
+ *
+ * @param index	    The index of the variable.
+ * @return	    The value.
+ */
+PJ_DECL(void*) pj_thread_local_get(long index);
+
+
+/**
+ * @}
+ */
+
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_ATOMIC Atomic Variables
+ * @ingroup PJ_OS
+ * @{
+ *
+ * This module provides API to manipulate atomic variables.
+ *
+ * \section pj_atomic_examples_sec Examples
+ *
+ * For some example codes, please see:
+ *  - @ref page_pjlib_atomic_test
+ */
+
+
+/**
+ * Create atomic variable.
+ *
+ * @param pool	    The pool.
+ * @param initial   The initial value of the atomic variable.
+ * @param atomic    Pointer to hold the atomic variable upon return.
+ *
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
+				       pj_atomic_value_t initial,
+				       pj_atomic_t **atomic );
+
+/**
+ * Destroy atomic variable.
+ *
+ * @param atomic_var	the atomic variable.
+ *
+ * @return PJ_SUCCESS if success.
+ */
+PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var );
+
+/**
+ * Set the value of an atomic type, and return the previous value.
+ *
+ * @param atomic_var	the atomic variable.
+ * @param value		value to be set to the variable.
+ */
+PJ_DECL(void) pj_atomic_set( pj_atomic_t *atomic_var, 
+			     pj_atomic_value_t value);
+
+/**
+ * Get the value of an atomic type.
+ *
+ * @param atomic_var	the atomic variable.
+ *
+ * @return the value of the atomic variable.
+ */
+PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var);
+
+/**
+ * Increment the value of an atomic type.
+ *
+ * @param atomic_var	the atomic variable.
+ */
+PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var);
+
+/**
+ * Increment the value of an atomic type and get the result.
+ *
+ * @param atomic_var	the atomic variable.
+ *
+ * @return              The incremented value.
+ */
+PJ_DECL(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var);
+
+/**
+ * Decrement the value of an atomic type.
+ *
+ * @param atomic_var	the atomic variable.
+ */
+PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var);
+
+/**
+ * Decrement the value of an atomic type and get the result.
+ *
+ * @param atomic_var	the atomic variable.
+ *
+ * @return              The decremented value.
+ */
+PJ_DECL(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var);
+
+/**
+ * Add a value to an atomic type.
+ *
+ * @param atomic_var	The atomic variable.
+ * @param value		Value to be added.
+ */
+PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var,
+			     pj_atomic_value_t value);
+
+/**
+ * Add a value to an atomic type and get the result.
+ *
+ * @param atomic_var	The atomic variable.
+ * @param value		Value to be added.
+ *
+ * @return              The result after the addition.
+ */
+PJ_DECL(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
+			                          pj_atomic_value_t value);
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_MUTEX Mutexes.
+ * @ingroup PJ_OS
+ * @{
+ *
+ * Mutex manipulation. Alternatively, application can use higher abstraction
+ * for lock objects, which provides uniform API for all kinds of lock 
+ * mechanisms, including mutex. See @ref PJ_LOCK for more information.
+ */
+
+/**
+ * Mutex types:
+ *  - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent.
+ *  - PJ_MUTEX_SIMPLE: non-recursive mutex.
+ *  - PJ_MUTEX_RECURSIVE: recursive mutex.
+ */
+typedef enum pj_mutex_type_e
+{
+    PJ_MUTEX_DEFAULT,
+    PJ_MUTEX_SIMPLE,
+    PJ_MUTEX_RECURSE,
+} pj_mutex_type_e;
+
+
+/**
+ * Create mutex of the specified type.
+ *
+ * @param pool	    The pool.
+ * @param name	    Name to be associated with the mutex (for debugging).
+ * @param type	    The type of the mutex, of type #pj_mutex_type_e.
+ * @param mutex	    Pointer to hold the returned mutex instance.
+ *
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
+                                     const char *name,
+				     int type, 
+                                     pj_mutex_t **mutex);
+
+/**
+ * Create simple, non-recursive mutex.
+ * This function is a simple wrapper for #pj_mutex_create to create 
+ * non-recursive mutex.
+ *
+ * @param pool	    The pool.
+ * @param name	    Mutex name.
+ * @param mutex	    Pointer to hold the returned mutex instance.
+ *
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
+					     pj_mutex_t **mutex );
+
+/**
+ * Create recursive mutex.
+ * This function is a simple wrapper for #pj_mutex_create to create 
+ * recursive mutex.
+ *
+ * @param pool	    The pool.
+ * @param name	    Mutex name.
+ * @param mutex	    Pointer to hold the returned mutex instance.
+ *
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
+					        const char *name,
+						pj_mutex_t **mutex );
+
+/**
+ * Acquire mutex lock.
+ *
+ * @param mutex	    The mutex.
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex);
+
+/**
+ * Release mutex lock.
+ *
+ * @param mutex	    The mutex.
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex);
+
+/**
+ * Try to acquire mutex lock.
+ *
+ * @param mutex	    The mutex.
+ * @return	    PJ_SUCCESS on success, or the error code if the
+ *		    lock couldn't be acquired.
+ */
+PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex);
+
+/**
+ * Destroy mutex.
+ *
+ * @param mutex	    Te mutex.
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex);
+
+/**
+ * Determine whether calling thread is owning the mutex (only available when
+ * PJ_DEBUG is set).
+ * @param mutex	    The mutex.
+ * @return	    Non-zero if yes.
+ */
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+   PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex);
+#else
+#  define pj_mutex_is_locked(mutex)	    1
+#endif
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_CRIT_SEC Critical sections.
+ * @ingroup PJ_OS
+ * @{
+ * Critical section protection can be used to protect regions where:
+ *  - mutual exclusion protection is needed.
+ *  - it's rather too expensive to create a mutex.
+ *  - the time spent in the region is very very brief.
+ *
+ * Critical section is a global object, and it prevents any threads from
+ * entering any regions that are protected by critical section once a thread
+ * is already in the section.
+ *
+ * Critial section is \a not recursive!
+ *
+ * Application <b>MUST NOT</b> call any functions that may cause current
+ * thread to block (such as allocating memory, performing I/O, locking mutex,
+ * etc.) while holding the critical section.
+ */
+/**
+ * Enter critical section.
+ */
+PJ_DECL(void) pj_enter_critical_section(void);
+
+/**
+ * Leave critical section.
+ */
+PJ_DECL(void) pj_leave_critical_section(void);
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+/**
+ * @defgroup PJ_SEM Semaphores.
+ * @ingroup PJ_OS
+ * @{
+ *
+ * This module provides abstraction for semaphores, where available.
+ */
+
+/**
+ * Create semaphore.
+ *
+ * @param pool	    The pool.
+ * @param name	    Name to be assigned to the semaphore (for logging purpose)
+ * @param initial   The initial count of the semaphore.
+ * @param max	    The maximum count of the semaphore.
+ * @param sem	    Pointer to hold the semaphore created.
+ *
+ * @return	    PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool, 
+                                    const char *name,
+				    unsigned initial, 
+                                    unsigned max,
+				    pj_sem_t **sem);
+
+/**
+ * Wait for semaphore.
+ *
+ * @param sem	The semaphore.
+ *
+ * @return	PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem);
+
+/**
+ * Try wait for semaphore.
+ *
+ * @param sem	The semaphore.
+ *
+ * @return	PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem);
+
+/**
+ * Release semaphore.
+ *
+ * @param sem	The semaphore.
+ *
+ * @return	PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem);
+
+/**
+ * Destroy semaphore.
+ *
+ * @param sem	The semaphore.
+ *
+ * @return	PJ_SUCCESS on success, or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem);
+
+/**
+ * @}
+ */
+#endif	/* PJ_HAS_SEMAPHORE */
+
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+/**
+ * @defgroup PJ_EVENT Event Object.
+ * @ingroup PJ_OS
+ * @{
+ *
+ * This module provides abstraction to event object (e.g. Win32 Event) where
+ * available. Event objects can be used for synchronization among threads.
+ */
+
+/**
+ * Create event object.
+ *
+ * @param pool		The pool.
+ * @param name		The name of the event object (for logging purpose).
+ * @param manual_reset	Specify whether the event is manual-reset
+ * @param initial	Specify the initial state of the event object.
+ * @param event		Pointer to hold the returned event object.
+ *
+ * @return event handle, or NULL if failed.
+ */
+PJ_DECL(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
+				     pj_bool_t manual_reset, pj_bool_t initial,
+				     pj_event_t **event);
+
+/**
+ * Wait for event to be signaled.
+ *
+ * @param event	    The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event);
+
+/**
+ * Try wait for event object to be signalled.
+ *
+ * @param event The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event);
+
+/**
+ * Set the event object state to signaled. For auto-reset event, this 
+ * will only release the first thread that are waiting on the event. For
+ * manual reset event, the state remains signaled until the event is reset.
+ * If there is no thread waiting on the event, the event object state 
+ * remains signaled.
+ *
+ * @param event	    The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event);
+
+/**
+ * Set the event object to signaled state to release appropriate number of
+ * waiting threads and then reset the event object to non-signaled. For
+ * manual-reset event, this function will release all waiting threads. For
+ * auto-reset event, this function will only release one waiting thread.
+ *
+ * @param event	    The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event);
+
+/**
+ * Set the event object state to non-signaled.
+ *
+ * @param event	    The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event);
+
+/**
+ * Destroy the event object.
+ *
+ * @param event	    The event object.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event);
+
+/**
+ * @}
+ */
+#endif	/* PJ_HAS_EVENT_OBJ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @addtogroup PJ_TIME Time Data Type and Manipulation.
+ * @ingroup PJ_OS
+ * @{
+ * This module provides API for manipulating time.
+ *
+ * \section pj_time_examples_sec Examples
+ *
+ * For examples, please see:
+ *  - \ref page_pjlib_sleep_test
+ */
+
+/**
+ * Get current time of day in local representation.
+ *
+ * @param tv	Variable to store the result.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv);
+
+
+/**
+ * Parse time value into date/time representation.
+ *
+ * @param tv	The time.
+ * @param pt	Variable to store the date time result.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt);
+
+/**
+ * Encode date/time to time value.
+ *
+ * @param pt	The date/time.
+ * @param tv	Variable to store time value result.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
+
+/**
+ * Convert local time to GMT.
+ *
+ * @param tv	Time to convert.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
+
+/**
+ * Convert GMT to local time.
+ *
+ * @param tv	Time to convert.
+ *
+ * @return zero if successfull.
+ */
+PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
+
+/**
+ * @}
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+
+/**
+ * @defgroup PJ_TERM Terminal
+ * @ingroup PJ_OS
+ * @{
+ */
+
+/**
+ * Set current terminal color.
+ *
+ * @param color	    The RGB color.
+ *
+ * @return zero on success.
+ */
+PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color);
+
+/**
+ * Get current terminal foreground color.
+ *
+ * @return RGB color.
+ */
+PJ_DECL(pj_color_t) pj_term_get_color(void);
+
+/**
+ * @}
+ */
+
+#endif	/* PJ_TERM_HAS_COLOR */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_TIMESTAMP High Resolution Timestamp
+ * @ingroup PJ_OS
+ * @{
+ *
+ * PJLIB provides <b>High Resolution Timestamp</b> API to access highest 
+ * resolution timestamp value provided by the platform. The API is usefull
+ * to measure precise elapsed time, and can be used in applications such
+ * as profiling.
+ *
+ * The timestamp value is represented in cycles, and can be related to
+ * normal time (in seconds or sub-seconds) using various functions provided.
+ *
+ * \section pj_timestamp_examples_sec Examples
+ *
+ * For examples, please see:
+ *  - \ref page_pjlib_sleep_test
+ *  - \ref page_pjlib_timestamp_test
+ */
+
+/*
+ * High resolution timer.
+ */
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+
+/**
+ * This structure represents high resolution (64bit) time value. The time
+ * values represent time in cycles, which is retrieved by calling
+ * #pj_get_timestamp().
+ */
+typedef union pj_timestamp
+{
+    struct
+    {
+#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
+	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */
+	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */
+#else
+	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */
+	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */
+#endif
+    } u32;                  /**< The 64-bit value as two 32-bit values. */
+
+#if PJ_HAS_INT64
+    pj_uint64_t u64;        /**< The whole 64-bit value, where available. */
+#endif
+} pj_timestamp;
+
+
+/**
+ * Acquire high resolution timer value. The time value are stored
+ * in cycles.
+ *
+ * @param ts	    High resolution timer value.
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ *
+ * @see pj_get_timestamp_freq().
+ */
+PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts);
+
+/**
+ * Get high resolution timer frequency, in cycles per second.
+ *
+ * @param freq	    Timer frequency, in cycles per second.
+ * @return	    PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq);
+
+/**
+ * Add timestamp t2 to t1.
+ * @param t1	    t1.
+ * @param t2	    t2.
+ */
+PJ_INLINE(void) pj_add_timestamp(pj_timestamp *t1, const pj_timestamp *t2)
+{
+#if PJ_HAS_INT64
+    t1->u64 += t2->u64;
+#else
+    pj_uint32_t old = t1->u32.lo;
+    t1->u32.hi += t2->u32.hi;
+    t1->u32.lo += t2->u32.lo;
+    if (t1->u32.lo < old)
+	++t1->u32.hi;
+#endif
+}
+
+/**
+ * Substract timestamp t2 from t1.
+ * @param t1	    t1.
+ * @param t2	    t2.
+ */
+PJ_INLINE(void) pj_sub_timestamp(pj_timestamp *t1, const pj_timestamp *t2)
+{
+#if PJ_HAS_INT64
+    t1->u64 -= t2->u64;
+#else
+    t1->u32.hi -= t2->u32.hi;
+    if (t1->u32.lo >= t2->u32.lo)
+	t1->u32.lo -= t2->u32.lo;
+    else {
+	t1->u32.lo -= t2->u32.lo;
+	--t1->u32.hi;
+    }
+#endif
+}
+
+/**
+ * Calculate the elapsed time, and store it in pj_time_val.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available. 
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start     The starting timestamp.
+ * @param stop      The end timestamp.
+ *
+ * @return	    Elapsed time as #pj_time_val.
+ *
+ * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec()
+ */
+PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
+                                      const pj_timestamp *stop );
+
+/**
+ * Calculate the elapsed time in 32-bit microseconds.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available. 
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start     The starting timestamp.
+ * @param stop      The end timestamp.
+ *
+ * @return	    Elapsed time in microsecond.
+ *
+ * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec()
+ */
+PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
+                                      const pj_timestamp *stop );
+
+/**
+ * Calculate the elapsed time in 32-bit nanoseconds.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available. 
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start     The starting timestamp.
+ * @param stop      The end timestamp.
+ *
+ * @return	    Elapsed time in nanoseconds.
+ *
+ * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec()
+ */
+PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
+                                         const pj_timestamp *stop );
+
+/**
+ * Calculate the elapsed time in 32-bit cycles.
+ * This function calculates the elapsed time using highest precision
+ * calculation that is available for current platform, considering
+ * whether floating point or 64-bit precision arithmetic is available. 
+ * For maximum portability, application should prefer to use this function
+ * rather than calculating the elapsed time by itself.
+ *
+ * @param start     The starting timestamp.
+ * @param stop      The end timestamp.
+ *
+ * @return	    Elapsed time in cycles.
+ *
+ * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec()
+ */
+PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
+                                       const pj_timestamp *stop );
+
+
+#endif	/* PJ_HAS_HIGH_RES_TIMER */
+
+/** @} */
+
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * Internal PJLIB function to initialize the threading subsystem.
+ * @return          PJ_SUCCESS or the appropriate error code.
+ */
+pj_status_t pj_thread_init(void);
+
+
+PJ_END_DECL
+
+#endif  /* __PJ_OS_H__ */
+
diff --git a/pjlib/include/pj/pool.h b/pjlib/include/pj/pool.h
index b3037b3..c47195c 100644
--- a/pjlib/include/pj/pool.h
+++ b/pjlib/include/pj/pool.h
@@ -1,586 +1,586 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_POOL_H__

-#define __PJ_POOL_H__

-

-/**

- * @file pool.h

- * @brief Memory Pool.

- */

-

-#include <pj/list.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_POOL_GROUP Memory Pool Management

- * @ingroup PJ

- * @brief

- * Memory pool management provides API to allocate and deallocate memory from

- * memory pool and to manage and establish policy for pool creation and

- * destruction in pool factory.

- *

- * \section PJ_POOL_FACTORY_SEC Pool Factory

- * See: \ref PJ_POOL_FACTORY "Pool Factory"

- *

- * A memory pool must be created through a factory. A factory not only provides

- * generic interface functions to create and release pool, but also provides 

- * strategy to manage the life time of pools. One sample implementation, 

- * \a pj_caching_pool, can be set to keep the pools released by application for

- * future use as long as the total memory is below the limit.

- * 

- * The pool factory interface declared in PJLIB is designed to be extensible.

- * Application can define its own strategy by creating it's own pool factory

- * implementation, and this strategy can be used even by existing library

- * without recompilation.

- *

- *

- * \section PJ_POOL_POLICY_SEC Pool Factory Policy

- * See: \ref PJ_POOL_FACTORY "Pool Factory Policy"

- *

- * A pool factory only defines functions to create and release pool and how

- * to manage pools, but the rest of the functionalities are controlled by

- * policy. A pool policy defines:

- *  - how memory block is allocated and deallocated (the default implementation

- *    allocates and deallocate memory by calling malloc() and free()).

- *  - callback to be called when memory allocation inside a pool fails (the

- *    default implementation will throw PJ_NO_MEMORY_EXCEPTION exception).

- *  - concurrency when creating and releasing pool from/to the factory.

- *

- * A pool factory can be given different policy during creation to make

- * it behave differently. For example, caching pool factory can be configured

- * to allocate and deallocate from a static/contiguous/preallocated memory 

- * instead of using malloc()/free().

- * 

- * What strategy/factory and what policy to use is not defined by PJLIB, but

- * instead is left to application to make use whichever is most efficient for

- * itself.

- *

- *

- * \section PJ_POOL_POOL_SEC The Pool

- * See: \ref PJ_POOL "Pool"

- *

- * The memory pool is an opaque object created by pool factory.

- * Application uses this object to request a memory chunk, by calling

- * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using

- * the pool, it must call #pj_pool_release to free all the chunks previously

- * allocated and release the pool back to the factory.

- *

- * \section PJ_POOL_THREADING_SEC More on Threading Policies:

- * - By design, memory allocation from a pool is not thread safe. We assumed 

- *   that a pool will be owned by an object, and thread safety should be 

- *   handled by that object. Thus these functions are not thread safe: 

- *	- #pj_pool_alloc, 

- *	- #pj_pool_calloc, 

- *	- and other pool statistic functions.

- * - Threading in the pool factory is decided by the policy set for the

- *   factory when it was created.

- *

- * \section PJ_POOL_EXAMPLES_SEC Examples

- *

- * For some sample codes on how to use the pool, please see:

- *  - @ref page_pjlib_pool_test

- */

-

-/**

- * @defgroup PJ_POOL Memory Pool.

- * @ingroup PJ_POOL_GROUP

- * @brief

- * A memory pool is initialized with an initial amount of memory, which is

- * called a block. Pool can be configured to dynamically allocate more memory 

- * blocks when it runs out of memory. Subsequent memory allocations by user 

- * will use up portions of these block. 

- * The pool doesn't keep track of individual memory allocations

- * by user, and the user doesn't have to free these indidual allocations. This

- * makes memory allocation simple and very fast. All the memory allocated from

- * the pool will be destroyed when the pool itself is destroyed.

- * @{

- */

-

-/**

- * The type for function to receive callback from the pool when it is unable

- * to allocate memory. The elegant way to handle this condition is to throw

- * exception, and this is what is expected by most of this library 

- * components.

- */

-typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size);

-

-/**

- * This class, which is used internally by the pool, describes a single 

- * block of memory from which user memory allocations will be allocated from.

- */

-typedef struct pj_pool_block

-{

-    PJ_DECL_LIST_MEMBER(struct pj_pool_block);  /**< List's prev and next.  */

-    unsigned char    *buf;                      /**< Start of buffer.       */

-    unsigned char    *cur;                      /**< Current alloc ptr.     */

-    unsigned char    *end;                      /**< End of buffer.         */

-} pj_pool_block;

-

-

-/**

- * This structure describes the memory pool. Only implementors of pool factory

- * need to care about the contents of this structure.

- */

-struct pj_pool_t

-{

-    PJ_DECL_LIST_MEMBER(struct pj_pool_t);  /**< Standard list elements.    */

-

-    /** Pool name */

-    char	    obj_name[PJ_MAX_OBJ_NAME];

-

-    /** Pool factory. */

-    pj_pool_factory *factory;

-

-    /** Current capacity allocated by the pool. */

-    pj_size_t	    capacity;

-

-    /** Number of memory used/allocated. */

-    pj_size_t	    used_size;

-

-    /** Size of memory block to be allocated when the pool runs out of memory */

-    pj_size_t	    increment_size;

-

-    /** List of memory blocks allcoated by the pool. */

-    pj_pool_block   block_list;

-

-    /** The callback to be called when the pool is unable to allocate memory. */

-    pj_pool_callback *callback;

-

-};

-

-

-/**

- * Guidance on how much memory required for initial pool administrative data.

- */

-#define PJ_POOL_SIZE	        (sizeof(struct pj_pool_t))

-

-/** 

- * Pool memory alignment (must be power of 2). 

- */

-#ifndef PJ_POOL_ALIGNMENT

-#   define PJ_POOL_ALIGNMENT    4

-#endif

-

-/**

- * Create a new pool from the pool factory. This wrapper will call create_pool

- * member of the pool factory.

- *

- * @param factory	    The pool factory.

- * @param name		    The name to be assigned to the pool. The name should 

- *			    not be longer than PJ_MAX_OBJ_NAME (32 chars), or 

- *			    otherwise it will be truncated.

- * @param initial_size	    The size of initial memory blocks taken by the pool.

- *			    Note that the pool will take 68+20 bytes for 

- *			    administrative area from this block.

- * @param increment_size    the size of each additional blocks to be allocated

- *			    when the pool is running out of memory. If user 

- *			    requests memory which is larger than this size, then 

- *			    an error occurs.

- *			    Note that each time a pool allocates additional block, 

- *			    it needs PJ_POOL_SIZE more to store some 

- *			    administrative info.

- * @param callback	    Callback to be called when error occurs in the pool.

- *			    If this value is NULL, then the callback from pool

- *			    factory policy will be used.

- *			    Note that when an error occurs during pool creation, 

- *			    the callback itself is not called. Instead, NULL 

- *			    will be returned.

- *

- * @return                  The memory pool, or NULL.

- */

-PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory, 

-				    const char *name,

-				    pj_size_t initial_size, 

-				    pj_size_t increment_size,

-				    pj_pool_callback *callback);

-

-/**

- * Release the pool back to pool factory.

- *

- * @param pool	    Memory pool.

- */

-PJ_IDECL(void) pj_pool_release( pj_pool_t *pool );

-

-/**

- * Get pool object name.

- *

- * @param pool the pool.

- *

- * @return pool name as NULL terminated string.

- */

-PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool );

-

-/**

- * Reset the pool to its state when it was initialized.

- * This means that if additional blocks have been allocated during runtime, 

- * then they will be freed. Only the original block allocated during 

- * initialization is retained. This function will also reset the internal 

- * counters, such as pool capacity and used size.

- *

- * @param pool the pool.

- */

-PJ_DECL(void) pj_pool_reset( pj_pool_t *pool );

-

-

-/**

- * Get the pool capacity, that is, the system storage that have been allocated

- * by the pool, and have been used/will be used to allocate user requests.

- * There's no guarantee that the returned value represent a single

- * contiguous block, because the capacity may be spread in several blocks.

- *

- * @param pool	the pool.

- *

- * @return the capacity.

- */

-PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool );

-

-/**

- * Get the total size of user allocation request.

- *

- * @param pool	the pool.

- *

- * @return the total size.

- */

-PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool );

-

-/**

- * Allocate storage with the specified size from the pool.

- * If there's no storage available in the pool, then the pool can allocate more

- * blocks if the increment size is larger than the requested size.

- *

- * @param pool	    the pool.

- * @param size	    the requested size.

- *

- * @return pointer to the allocated memory.

- */

-PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size);

-

-/**

- * Allocate storage  from the pool, and initialize it to zero.

- * This function behaves like pj_pool_alloc(), except that the storage will

- * be initialized to zero.

- *

- * @param pool	    the pool.

- * @param count	    the number of elements in the array.

- * @param elem	    the size of individual element.

- *

- * @return pointer to the allocated memory.

- */

-PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, 

-				pj_size_t elem);

-

-

-/**

- * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)

- * Allocate storage from the pool and initialize it to zero.

- *

- * @param pool	    The pool.

- * @param size	    The size to be allocated.

- *

- * @return	    Pointer to the allocated memory.

- */

-#define pj_pool_zalloc(pool, size)  pj_pool_calloc(pool, 1, size)

-

-

-/**

- * @}	// PJ_POOL

- */

-

-///////////////////////////////////////////////////////////////////////////////

-/**

- * @defgroup PJ_POOL_FACTORY Pool Factory and Policy.

- * @ingroup PJ_POOL_GROUP

- * @brief

- * Pool factory declares an interface to create and destroy pool. There may

- * be several strategies for pool creation, and these strategies should 

- * implement the interface defined by pool factory.

- *

- * \section PJ_POOL_FACTORY_ITF Pool Factory Interface

- * The pool factory defines the following interface:

- *  - \a policy: the memory pool factory policy.

- *  - \a create_pool(): create a new memory pool.

- *  - \a release_pool(): release memory pool back to factory.

- *

- * \section PJ_POOL_FACTORY_POL Pool Factory Policy.

- * The pool factory policy controls the behaviour of memory factories, and

- * defines the following interface:

- *  - \a block_alloc(): allocate memory block from backend memory mgmt/system.

- *  - \a block_free(): free memory block back to backend memory mgmt/system.

- * @{

- */

-

-/* We unfortunately don't have support for factory policy options as now,

-   so we keep this commented at the moment.

-enum PJ_POOL_FACTORY_OPTION

-{

-    PJ_POOL_FACTORY_SERIALIZE = 1

-};

-*/

-

-/**

- * This structure declares pool factory interface.

- */

-typedef struct pj_pool_factory_policy

-{

-    /**

-     * Allocate memory block (for use by pool). This function is called

-     * by memory pool to allocate memory block.

-     * 

-     * @param factory	Pool factory.

-     * @param size	The size of memory block to allocate.

-     *

-     * @return		Memory block.

-     */

-    void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size);

-

-    /**

-     * Free memory block.

-     *

-     * @param factory	Pool factory.

-     * @param mem	Memory block previously allocated by block_alloc().

-     * @param size	The size of memory block.

-     */

-    void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size);

-

-    /**

-     * Default callback to be called when memory allocation fails.

-     */

-    pj_pool_callback *callback;

-

-    /**

-     * Option flags.

-     */

-    unsigned flags;

-

-} pj_pool_factory_policy;

-

-/**

- * This constant denotes the exception number that will be thrown by default

- * memory factory policy when memory allocation fails.

- */

-extern int PJ_NO_MEMORY_EXCEPTION;

-

-/**

- * This global variable points to default memory pool factory policy.

- * The behaviour of the default policy is:

- *  - block allocation and deallocation use malloc() and free().

- *  - callback will raise PJ_NO_MEMORY_EXCEPTION exception.

- *  - access to pool factory is not serialized (i.e. not thread safe).

- */

-extern pj_pool_factory_policy pj_pool_factory_default_policy;

-

-/**

- * This structure contains the declaration for pool factory interface.

- */

-struct pj_pool_factory

-{

-    /**

-     * Memory pool policy.

-     */

-    pj_pool_factory_policy policy;

-

-    /**

-    * Create a new pool from the pool factory.

-    *

-    * @param factory	The pool factory.

-    * @param name	the name to be assigned to the pool. The name should 

-    *			not be longer than PJ_MAX_OBJ_NAME (32 chars), or 

-    *			otherwise it will be truncated.

-    * @param initial_size the size of initial memory blocks taken by the pool.

-    *			Note that the pool will take 68+20 bytes for 

-    *			administrative area from this block.

-    * @param increment_size the size of each additional blocks to be allocated

-    *			when the pool is running out of memory. If user 

-    *			requests memory which is larger than this size, then 

-    *			an error occurs.

-    *			Note that each time a pool allocates additional block, 

-    *			it needs 20 bytes (equal to sizeof(pj_pool_block)) to 

-    *			store some administrative info.

-    * @param callback	Cllback to be called when error occurs in the pool.

-    *			Note that when an error occurs during pool creation, 

-    *			the callback itself is not called. Instead, NULL 

-    *			will be returned.

-    *

-    * @return the memory pool, or NULL.

-    */

-    pj_pool_t*	(*create_pool)( pj_pool_factory *factory,

-				const char *name,

-				pj_size_t initial_size, 

-				pj_size_t increment_size,

-				pj_pool_callback *callback);

-

-    /**

-     * Release the pool to the pool factory.

-     *

-     * @param factory	The pool factory.

-     * @param pool	The pool to be released.

-    */

-    void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool );

-

-    /**

-     * Dump pool status to log.

-     *

-     * @param factory	The pool factory.

-     */

-    void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail );

-};

-

-/**

- * This function is intended to be used by pool factory implementors.

- * @param factory           Pool factory.

- * @param name              Pool name.

- * @param initial_size      Initial size.

- * @param increment_size    Increment size.

- * @param callback          Callback.

- * @return                  The pool object, or NULL.

- */

-PJ_DECL(pj_pool_t*) pj_pool_create_int(	pj_pool_factory *factory, 

-					const char *name,

-					pj_size_t initial_size, 

-					pj_size_t increment_size,

-					pj_pool_callback *callback);

-

-/**

- * This function is intended to be used by pool factory implementors.

- * @param pool              The pool.

- * @param name              Pool name.

- * @param increment_size    Increment size.

- * @param callback          Callback function.

- */

-PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool, 

-				const char *name,

-				pj_size_t increment_size,

-				pj_pool_callback *callback);

-

-/**

- * This function is intended to be used by pool factory implementors.

- * @param pool      The memory pool.

- */

-PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool );

-

-

-/**

- *  @}	// PJ_POOL_FACTORY

- */

-

-///////////////////////////////////////////////////////////////////////////////

-

-/**

- * @defgroup PJ_CACHING_POOL Caching Pool Factory.

- * @ingroup PJ_POOL_GROUP

- * @brief

- * Caching pool is one sample implementation of pool factory where the

- * factory can reuse memory to create a pool. Application defines what the 

- * maximum memory the factory can hold, and when a pool is released the

- * factory decides whether to destroy the pool or to keep it for future use.

- * If the total amount of memory in the internal cache is still within the

- * limit, the factory will keep the pool in the internal cache, otherwise the

- * pool will be destroyed, thus releasing the memory back to the system.

- *

- * @{

- */

-

-/**

- * Number of unique sizes, to be used as index to the free list.

- * Each pool in the free list is organized by it's size.

- */

-#define PJ_CACHING_POOL_ARRAY_SIZE	16

-

-/**

- * Declaration for caching pool. Application doesn't normally need to

- * care about the contents of this struct, it is only provided here because

- * application need to define an instance of this struct (we can not allocate

- * the struct from a pool since there is no pool factory yet!).

- */

-struct pj_caching_pool 

-{

-    /** Pool factory interface, must be declared first. */

-    pj_pool_factory factory;

-

-    /** Current factory's capacity, i.e. number of bytes that are allocated

-     *  and available for application in this factory. The factory's

-     *  capacity represents the size of all pools kept by this factory

-     *  in it's free list, which will be returned to application when it

-     *  requests to create a new pool.

-     */

-    pj_size_t	    capacity;

-

-    /** Maximum size that can be held by this factory. Once the capacity

-     *  has exceeded @a max_capacity, further #pj_pool_release() will

-     *  flush the pool. If the capacity is still below the @a max_capacity,

-     *  #pj_pool_release() will save the pool to the factory's free list.

-     */

-    pj_size_t       max_capacity;

-

-    /**

-     * Number of pools currently held by applications. This number gets

-     * incremented everytime #pj_pool_create() is called, and gets

-     * decremented when #pj_pool_release() is called.

-     */

-    pj_size_t       used_count;

-

-    /**

-     * Lists of pools in the cache, indexed by pool size.

-     */

-    pj_list	    free_list[PJ_CACHING_POOL_ARRAY_SIZE];

-

-    /**

-     * List of pools currently allocated by applications.

-     */

-    pj_list	    used_list;

-};

-

-

-

-/**

- * Initialize caching pool.

- *

- * @param ch_pool	The caching pool factory to be initialized.

- * @param policy	Pool factory policy.

- * @param max_capacity	The total capacity to be retained in the cache. When

- *			the pool is returned to the cache, it will be kept in

- *			recycling list if the total capacity of pools in this

- *			list plus the capacity of the pool is still below this

- *			value.

- */

-PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool, 

-				    const pj_pool_factory_policy *policy,

-				    pj_size_t max_capacity);

-

-

-/**

- * Destroy caching pool, and release all the pools in the recycling list.

- *

- * @param ch_pool	The caching pool.

- */

-PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool );

-

-/**

- * @}	// PJ_CACHING_POOL

- */

-

-#  if PJ_FUNCTIONS_ARE_INLINED

-#    include "pool_i.h"

-#  endif

-

-PJ_END_DECL

-    

-#endif	/* __PJ_POOL_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_POOL_H__
+#define __PJ_POOL_H__
+
+/**
+ * @file pool.h
+ * @brief Memory Pool.
+ */
+
+#include <pj/list.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_POOL_GROUP Memory Pool Management
+ * @ingroup PJ
+ * @brief
+ * Memory pool management provides API to allocate and deallocate memory from
+ * memory pool and to manage and establish policy for pool creation and
+ * destruction in pool factory.
+ *
+ * \section PJ_POOL_FACTORY_SEC Pool Factory
+ * See: \ref PJ_POOL_FACTORY "Pool Factory"
+ *
+ * A memory pool must be created through a factory. A factory not only provides
+ * generic interface functions to create and release pool, but also provides 
+ * strategy to manage the life time of pools. One sample implementation, 
+ * \a pj_caching_pool, can be set to keep the pools released by application for
+ * future use as long as the total memory is below the limit.
+ * 
+ * The pool factory interface declared in PJLIB is designed to be extensible.
+ * Application can define its own strategy by creating it's own pool factory
+ * implementation, and this strategy can be used even by existing library
+ * without recompilation.
+ *
+ *
+ * \section PJ_POOL_POLICY_SEC Pool Factory Policy
+ * See: \ref PJ_POOL_FACTORY "Pool Factory Policy"
+ *
+ * A pool factory only defines functions to create and release pool and how
+ * to manage pools, but the rest of the functionalities are controlled by
+ * policy. A pool policy defines:
+ *  - how memory block is allocated and deallocated (the default implementation
+ *    allocates and deallocate memory by calling malloc() and free()).
+ *  - callback to be called when memory allocation inside a pool fails (the
+ *    default implementation will throw PJ_NO_MEMORY_EXCEPTION exception).
+ *  - concurrency when creating and releasing pool from/to the factory.
+ *
+ * A pool factory can be given different policy during creation to make
+ * it behave differently. For example, caching pool factory can be configured
+ * to allocate and deallocate from a static/contiguous/preallocated memory 
+ * instead of using malloc()/free().
+ * 
+ * What strategy/factory and what policy to use is not defined by PJLIB, but
+ * instead is left to application to make use whichever is most efficient for
+ * itself.
+ *
+ *
+ * \section PJ_POOL_POOL_SEC The Pool
+ * See: \ref PJ_POOL "Pool"
+ *
+ * The memory pool is an opaque object created by pool factory.
+ * Application uses this object to request a memory chunk, by calling
+ * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using
+ * the pool, it must call #pj_pool_release to free all the chunks previously
+ * allocated and release the pool back to the factory.
+ *
+ * \section PJ_POOL_THREADING_SEC More on Threading Policies:
+ * - By design, memory allocation from a pool is not thread safe. We assumed 
+ *   that a pool will be owned by an object, and thread safety should be 
+ *   handled by that object. Thus these functions are not thread safe: 
+ *	- #pj_pool_alloc, 
+ *	- #pj_pool_calloc, 
+ *	- and other pool statistic functions.
+ * - Threading in the pool factory is decided by the policy set for the
+ *   factory when it was created.
+ *
+ * \section PJ_POOL_EXAMPLES_SEC Examples
+ *
+ * For some sample codes on how to use the pool, please see:
+ *  - @ref page_pjlib_pool_test
+ */
+
+/**
+ * @defgroup PJ_POOL Memory Pool.
+ * @ingroup PJ_POOL_GROUP
+ * @brief
+ * A memory pool is initialized with an initial amount of memory, which is
+ * called a block. Pool can be configured to dynamically allocate more memory 
+ * blocks when it runs out of memory. Subsequent memory allocations by user 
+ * will use up portions of these block. 
+ * The pool doesn't keep track of individual memory allocations
+ * by user, and the user doesn't have to free these indidual allocations. This
+ * makes memory allocation simple and very fast. All the memory allocated from
+ * the pool will be destroyed when the pool itself is destroyed.
+ * @{
+ */
+
+/**
+ * The type for function to receive callback from the pool when it is unable
+ * to allocate memory. The elegant way to handle this condition is to throw
+ * exception, and this is what is expected by most of this library 
+ * components.
+ */
+typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size);
+
+/**
+ * This class, which is used internally by the pool, describes a single 
+ * block of memory from which user memory allocations will be allocated from.
+ */
+typedef struct pj_pool_block
+{
+    PJ_DECL_LIST_MEMBER(struct pj_pool_block);  /**< List's prev and next.  */
+    unsigned char    *buf;                      /**< Start of buffer.       */
+    unsigned char    *cur;                      /**< Current alloc ptr.     */
+    unsigned char    *end;                      /**< End of buffer.         */
+} pj_pool_block;
+
+
+/**
+ * This structure describes the memory pool. Only implementors of pool factory
+ * need to care about the contents of this structure.
+ */
+struct pj_pool_t
+{
+    PJ_DECL_LIST_MEMBER(struct pj_pool_t);  /**< Standard list elements.    */
+
+    /** Pool name */
+    char	    obj_name[PJ_MAX_OBJ_NAME];
+
+    /** Pool factory. */
+    pj_pool_factory *factory;
+
+    /** Current capacity allocated by the pool. */
+    pj_size_t	    capacity;
+
+    /** Number of memory used/allocated. */
+    pj_size_t	    used_size;
+
+    /** Size of memory block to be allocated when the pool runs out of memory */
+    pj_size_t	    increment_size;
+
+    /** List of memory blocks allcoated by the pool. */
+    pj_pool_block   block_list;
+
+    /** The callback to be called when the pool is unable to allocate memory. */
+    pj_pool_callback *callback;
+
+};
+
+
+/**
+ * Guidance on how much memory required for initial pool administrative data.
+ */
+#define PJ_POOL_SIZE	        (sizeof(struct pj_pool_t))
+
+/** 
+ * Pool memory alignment (must be power of 2). 
+ */
+#ifndef PJ_POOL_ALIGNMENT
+#   define PJ_POOL_ALIGNMENT    4
+#endif
+
+/**
+ * Create a new pool from the pool factory. This wrapper will call create_pool
+ * member of the pool factory.
+ *
+ * @param factory	    The pool factory.
+ * @param name		    The name to be assigned to the pool. The name should 
+ *			    not be longer than PJ_MAX_OBJ_NAME (32 chars), or 
+ *			    otherwise it will be truncated.
+ * @param initial_size	    The size of initial memory blocks taken by the pool.
+ *			    Note that the pool will take 68+20 bytes for 
+ *			    administrative area from this block.
+ * @param increment_size    the size of each additional blocks to be allocated
+ *			    when the pool is running out of memory. If user 
+ *			    requests memory which is larger than this size, then 
+ *			    an error occurs.
+ *			    Note that each time a pool allocates additional block, 
+ *			    it needs PJ_POOL_SIZE more to store some 
+ *			    administrative info.
+ * @param callback	    Callback to be called when error occurs in the pool.
+ *			    If this value is NULL, then the callback from pool
+ *			    factory policy will be used.
+ *			    Note that when an error occurs during pool creation, 
+ *			    the callback itself is not called. Instead, NULL 
+ *			    will be returned.
+ *
+ * @return                  The memory pool, or NULL.
+ */
+PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory, 
+				    const char *name,
+				    pj_size_t initial_size, 
+				    pj_size_t increment_size,
+				    pj_pool_callback *callback);
+
+/**
+ * Release the pool back to pool factory.
+ *
+ * @param pool	    Memory pool.
+ */
+PJ_IDECL(void) pj_pool_release( pj_pool_t *pool );
+
+/**
+ * Get pool object name.
+ *
+ * @param pool the pool.
+ *
+ * @return pool name as NULL terminated string.
+ */
+PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool );
+
+/**
+ * Reset the pool to its state when it was initialized.
+ * This means that if additional blocks have been allocated during runtime, 
+ * then they will be freed. Only the original block allocated during 
+ * initialization is retained. This function will also reset the internal 
+ * counters, such as pool capacity and used size.
+ *
+ * @param pool the pool.
+ */
+PJ_DECL(void) pj_pool_reset( pj_pool_t *pool );
+
+
+/**
+ * Get the pool capacity, that is, the system storage that have been allocated
+ * by the pool, and have been used/will be used to allocate user requests.
+ * There's no guarantee that the returned value represent a single
+ * contiguous block, because the capacity may be spread in several blocks.
+ *
+ * @param pool	the pool.
+ *
+ * @return the capacity.
+ */
+PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool );
+
+/**
+ * Get the total size of user allocation request.
+ *
+ * @param pool	the pool.
+ *
+ * @return the total size.
+ */
+PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool );
+
+/**
+ * Allocate storage with the specified size from the pool.
+ * If there's no storage available in the pool, then the pool can allocate more
+ * blocks if the increment size is larger than the requested size.
+ *
+ * @param pool	    the pool.
+ * @param size	    the requested size.
+ *
+ * @return pointer to the allocated memory.
+ */
+PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size);
+
+/**
+ * Allocate storage  from the pool, and initialize it to zero.
+ * This function behaves like pj_pool_alloc(), except that the storage will
+ * be initialized to zero.
+ *
+ * @param pool	    the pool.
+ * @param count	    the number of elements in the array.
+ * @param elem	    the size of individual element.
+ *
+ * @return pointer to the allocated memory.
+ */
+PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, 
+				pj_size_t elem);
+
+
+/**
+ * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
+ * Allocate storage from the pool and initialize it to zero.
+ *
+ * @param pool	    The pool.
+ * @param size	    The size to be allocated.
+ *
+ * @return	    Pointer to the allocated memory.
+ */
+#define pj_pool_zalloc(pool, size)  pj_pool_calloc(pool, 1, size)
+
+
+/**
+ * @}	// PJ_POOL
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * @defgroup PJ_POOL_FACTORY Pool Factory and Policy.
+ * @ingroup PJ_POOL_GROUP
+ * @brief
+ * Pool factory declares an interface to create and destroy pool. There may
+ * be several strategies for pool creation, and these strategies should 
+ * implement the interface defined by pool factory.
+ *
+ * \section PJ_POOL_FACTORY_ITF Pool Factory Interface
+ * The pool factory defines the following interface:
+ *  - \a policy: the memory pool factory policy.
+ *  - \a create_pool(): create a new memory pool.
+ *  - \a release_pool(): release memory pool back to factory.
+ *
+ * \section PJ_POOL_FACTORY_POL Pool Factory Policy.
+ * The pool factory policy controls the behaviour of memory factories, and
+ * defines the following interface:
+ *  - \a block_alloc(): allocate memory block from backend memory mgmt/system.
+ *  - \a block_free(): free memory block back to backend memory mgmt/system.
+ * @{
+ */
+
+/* We unfortunately don't have support for factory policy options as now,
+   so we keep this commented at the moment.
+enum PJ_POOL_FACTORY_OPTION
+{
+    PJ_POOL_FACTORY_SERIALIZE = 1
+};
+*/
+
+/**
+ * This structure declares pool factory interface.
+ */
+typedef struct pj_pool_factory_policy
+{
+    /**
+     * Allocate memory block (for use by pool). This function is called
+     * by memory pool to allocate memory block.
+     * 
+     * @param factory	Pool factory.
+     * @param size	The size of memory block to allocate.
+     *
+     * @return		Memory block.
+     */
+    void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size);
+
+    /**
+     * Free memory block.
+     *
+     * @param factory	Pool factory.
+     * @param mem	Memory block previously allocated by block_alloc().
+     * @param size	The size of memory block.
+     */
+    void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size);
+
+    /**
+     * Default callback to be called when memory allocation fails.
+     */
+    pj_pool_callback *callback;
+
+    /**
+     * Option flags.
+     */
+    unsigned flags;
+
+} pj_pool_factory_policy;
+
+/**
+ * This constant denotes the exception number that will be thrown by default
+ * memory factory policy when memory allocation fails.
+ */
+extern int PJ_NO_MEMORY_EXCEPTION;
+
+/**
+ * This global variable points to default memory pool factory policy.
+ * The behaviour of the default policy is:
+ *  - block allocation and deallocation use malloc() and free().
+ *  - callback will raise PJ_NO_MEMORY_EXCEPTION exception.
+ *  - access to pool factory is not serialized (i.e. not thread safe).
+ */
+extern pj_pool_factory_policy pj_pool_factory_default_policy;
+
+/**
+ * This structure contains the declaration for pool factory interface.
+ */
+struct pj_pool_factory
+{
+    /**
+     * Memory pool policy.
+     */
+    pj_pool_factory_policy policy;
+
+    /**
+    * Create a new pool from the pool factory.
+    *
+    * @param factory	The pool factory.
+    * @param name	the name to be assigned to the pool. The name should 
+    *			not be longer than PJ_MAX_OBJ_NAME (32 chars), or 
+    *			otherwise it will be truncated.
+    * @param initial_size the size of initial memory blocks taken by the pool.
+    *			Note that the pool will take 68+20 bytes for 
+    *			administrative area from this block.
+    * @param increment_size the size of each additional blocks to be allocated
+    *			when the pool is running out of memory. If user 
+    *			requests memory which is larger than this size, then 
+    *			an error occurs.
+    *			Note that each time a pool allocates additional block, 
+    *			it needs 20 bytes (equal to sizeof(pj_pool_block)) to 
+    *			store some administrative info.
+    * @param callback	Cllback to be called when error occurs in the pool.
+    *			Note that when an error occurs during pool creation, 
+    *			the callback itself is not called. Instead, NULL 
+    *			will be returned.
+    *
+    * @return the memory pool, or NULL.
+    */
+    pj_pool_t*	(*create_pool)( pj_pool_factory *factory,
+				const char *name,
+				pj_size_t initial_size, 
+				pj_size_t increment_size,
+				pj_pool_callback *callback);
+
+    /**
+     * Release the pool to the pool factory.
+     *
+     * @param factory	The pool factory.
+     * @param pool	The pool to be released.
+    */
+    void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool );
+
+    /**
+     * Dump pool status to log.
+     *
+     * @param factory	The pool factory.
+     */
+    void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail );
+};
+
+/**
+ * This function is intended to be used by pool factory implementors.
+ * @param factory           Pool factory.
+ * @param name              Pool name.
+ * @param initial_size      Initial size.
+ * @param increment_size    Increment size.
+ * @param callback          Callback.
+ * @return                  The pool object, or NULL.
+ */
+PJ_DECL(pj_pool_t*) pj_pool_create_int(	pj_pool_factory *factory, 
+					const char *name,
+					pj_size_t initial_size, 
+					pj_size_t increment_size,
+					pj_pool_callback *callback);
+
+/**
+ * This function is intended to be used by pool factory implementors.
+ * @param pool              The pool.
+ * @param name              Pool name.
+ * @param increment_size    Increment size.
+ * @param callback          Callback function.
+ */
+PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool, 
+				const char *name,
+				pj_size_t increment_size,
+				pj_pool_callback *callback);
+
+/**
+ * This function is intended to be used by pool factory implementors.
+ * @param pool      The memory pool.
+ */
+PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool );
+
+
+/**
+ *  @}	// PJ_POOL_FACTORY
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @defgroup PJ_CACHING_POOL Caching Pool Factory.
+ * @ingroup PJ_POOL_GROUP
+ * @brief
+ * Caching pool is one sample implementation of pool factory where the
+ * factory can reuse memory to create a pool. Application defines what the 
+ * maximum memory the factory can hold, and when a pool is released the
+ * factory decides whether to destroy the pool or to keep it for future use.
+ * If the total amount of memory in the internal cache is still within the
+ * limit, the factory will keep the pool in the internal cache, otherwise the
+ * pool will be destroyed, thus releasing the memory back to the system.
+ *
+ * @{
+ */
+
+/**
+ * Number of unique sizes, to be used as index to the free list.
+ * Each pool in the free list is organized by it's size.
+ */
+#define PJ_CACHING_POOL_ARRAY_SIZE	16
+
+/**
+ * Declaration for caching pool. Application doesn't normally need to
+ * care about the contents of this struct, it is only provided here because
+ * application need to define an instance of this struct (we can not allocate
+ * the struct from a pool since there is no pool factory yet!).
+ */
+struct pj_caching_pool 
+{
+    /** Pool factory interface, must be declared first. */
+    pj_pool_factory factory;
+
+    /** Current factory's capacity, i.e. number of bytes that are allocated
+     *  and available for application in this factory. The factory's
+     *  capacity represents the size of all pools kept by this factory
+     *  in it's free list, which will be returned to application when it
+     *  requests to create a new pool.
+     */
+    pj_size_t	    capacity;
+
+    /** Maximum size that can be held by this factory. Once the capacity
+     *  has exceeded @a max_capacity, further #pj_pool_release() will
+     *  flush the pool. If the capacity is still below the @a max_capacity,
+     *  #pj_pool_release() will save the pool to the factory's free list.
+     */
+    pj_size_t       max_capacity;
+
+    /**
+     * Number of pools currently held by applications. This number gets
+     * incremented everytime #pj_pool_create() is called, and gets
+     * decremented when #pj_pool_release() is called.
+     */
+    pj_size_t       used_count;
+
+    /**
+     * Lists of pools in the cache, indexed by pool size.
+     */
+    pj_list	    free_list[PJ_CACHING_POOL_ARRAY_SIZE];
+
+    /**
+     * List of pools currently allocated by applications.
+     */
+    pj_list	    used_list;
+};
+
+
+
+/**
+ * Initialize caching pool.
+ *
+ * @param ch_pool	The caching pool factory to be initialized.
+ * @param policy	Pool factory policy.
+ * @param max_capacity	The total capacity to be retained in the cache. When
+ *			the pool is returned to the cache, it will be kept in
+ *			recycling list if the total capacity of pools in this
+ *			list plus the capacity of the pool is still below this
+ *			value.
+ */
+PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool, 
+				    const pj_pool_factory_policy *policy,
+				    pj_size_t max_capacity);
+
+
+/**
+ * Destroy caching pool, and release all the pools in the recycling list.
+ *
+ * @param ch_pool	The caching pool.
+ */
+PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool );
+
+/**
+ * @}	// PJ_CACHING_POOL
+ */
+
+#  if PJ_FUNCTIONS_ARE_INLINED
+#    include "pool_i.h"
+#  endif
+
+PJ_END_DECL
+    
+#endif	/* __PJ_POOL_H__ */
+
diff --git a/pjlib/include/pj/pool_i.h b/pjlib/include/pj/pool_i.h
index df9b45d..39c0487 100644
--- a/pjlib/include/pj/pool_i.h
+++ b/pjlib/include/pj/pool_i.h
@@ -1,91 +1,91 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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>

-

-PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size);

-

-PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )

-{

-    return pool->capacity;

-}

-

-PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )

-{

-    return pool->used_size;

-}

-

-PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool,

-					 pj_pool_block *block, pj_size_t size )

-{

-    /* The operation below is valid for size==0. 

-     * When size==0, the function will return the pointer to the pool

-     * memory address, but no memory will be allocated.

-     */

-    if (size & (PJ_POOL_ALIGNMENT-1)) {

-	size &= ~(PJ_POOL_ALIGNMENT-1);

-	size += PJ_POOL_ALIGNMENT;

-    }

-    if ((unsigned)(block->end - block->cur) >= size) {

-	void *ptr = block->cur;

-	block->cur += size;

-	pool->used_size += size;

-	return ptr;

-    }

-    return NULL;

-}

-

-PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size)

-{

-    pj_pool_block *block = pool->block_list.next;

-    void *ptr = pj_pool_alloc_from_block(pool, block, size);

-    if (!ptr)

-	ptr = pj_pool_allocate_find(pool, size);

-    return ptr;

-}

-

-

-PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size)

-{

-    void *buf = pj_pool_alloc( pool, size*count);

-    if (buf)

-	pj_memset(buf, 0, size * count);

-    return buf;

-}

-

-PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool )

-{

-    return pool->obj_name;

-}

-

-PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f, 

-				    const char *name,

-				    pj_size_t initial_size, 

-				    pj_size_t increment_size,

-				    pj_pool_callback *callback)

-{

-    return (*f->create_pool)(f, name, initial_size, increment_size, callback);

-}

-

-PJ_IDEF(void) pj_pool_release( pj_pool_t *pool )

-{

-    (*pool->factory->release_pool)(pool->factory, pool);

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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>
+
+PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size);
+
+PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
+{
+    return pool->capacity;
+}
+
+PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
+{
+    return pool->used_size;
+}
+
+PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool,
+					 pj_pool_block *block, pj_size_t size )
+{
+    /* The operation below is valid for size==0. 
+     * When size==0, the function will return the pointer to the pool
+     * memory address, but no memory will be allocated.
+     */
+    if (size & (PJ_POOL_ALIGNMENT-1)) {
+	size &= ~(PJ_POOL_ALIGNMENT-1);
+	size += PJ_POOL_ALIGNMENT;
+    }
+    if ((unsigned)(block->end - block->cur) >= size) {
+	void *ptr = block->cur;
+	block->cur += size;
+	pool->used_size += size;
+	return ptr;
+    }
+    return NULL;
+}
+
+PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size)
+{
+    pj_pool_block *block = pool->block_list.next;
+    void *ptr = pj_pool_alloc_from_block(pool, block, size);
+    if (!ptr)
+	ptr = pj_pool_allocate_find(pool, size);
+    return ptr;
+}
+
+
+PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size)
+{
+    void *buf = pj_pool_alloc( pool, size*count);
+    if (buf)
+	pj_memset(buf, 0, size * count);
+    return buf;
+}
+
+PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool )
+{
+    return pool->obj_name;
+}
+
+PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f, 
+				    const char *name,
+				    pj_size_t initial_size, 
+				    pj_size_t increment_size,
+				    pj_pool_callback *callback)
+{
+    return (*f->create_pool)(f, name, initial_size, increment_size, callback);
+}
+
+PJ_IDEF(void) pj_pool_release( pj_pool_t *pool )
+{
+    (*pool->factory->release_pool)(pool->factory, pool);
+}
+
diff --git a/pjlib/include/pj/rand.h b/pjlib/include/pj/rand.h
index 36e5574..a1cd333 100644
--- a/pjlib/include/pj/rand.h
+++ b/pjlib/include/pj/rand.h
@@ -1,65 +1,65 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_RAND_H__

-#define __PJ_RAND_H__

-

-/**

- * @file rand.h

- * @brief Random Number Generator.

- */

-

-#include <pj/config.h>

-

-PJ_BEGIN_DECL

-

-

-/**

- * @defgroup PJ_RAND Random Number Generator

- * @ingroup PJ_MISC

- * @{

- * This module contains functions for generating random numbers.

- * This abstraction is needed not only because not all platforms have

- * \a rand() and \a srand(), but also on some platforms \a rand()

- * only has 16-bit randomness, which is not good enough.

- */

-

-/**

- * Put in seed to random number generator.

- *

- * @param seed	    Seed value.

- */

-PJ_DECL(void) pj_srand(unsigned int seed);

-

-

-/**

- * Generate random integer with 32bit randomness.

- *

- * @return a random integer.

- */

-PJ_DECL(int) pj_rand(void);

-

-

-/** @} */

-

-

-PJ_END_DECL

-

-

-#endif	/* __PJ_RAND_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_RAND_H__
+#define __PJ_RAND_H__
+
+/**
+ * @file rand.h
+ * @brief Random Number Generator.
+ */
+
+#include <pj/config.h>
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_RAND Random Number Generator
+ * @ingroup PJ_MISC
+ * @{
+ * This module contains functions for generating random numbers.
+ * This abstraction is needed not only because not all platforms have
+ * \a rand() and \a srand(), but also on some platforms \a rand()
+ * only has 16-bit randomness, which is not good enough.
+ */
+
+/**
+ * Put in seed to random number generator.
+ *
+ * @param seed	    Seed value.
+ */
+PJ_DECL(void) pj_srand(unsigned int seed);
+
+
+/**
+ * Generate random integer with 32bit randomness.
+ *
+ * @return a random integer.
+ */
+PJ_DECL(int) pj_rand(void);
+
+
+/** @} */
+
+
+PJ_END_DECL
+
+
+#endif	/* __PJ_RAND_H__ */
+
diff --git a/pjlib/include/pj/rbtree.h b/pjlib/include/pj/rbtree.h
index 1d4df0b..ed6607f 100644
--- a/pjlib/include/pj/rbtree.h
+++ b/pjlib/include/pj/rbtree.h
@@ -1,209 +1,209 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_RBTREE_H__

-#define __PJ_RBTREE_H__

-

-/**

- * @file rbtree.h

- * @brief Red/Black Tree

- */

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_RBTREE Red/Black Balanced Tree

- * @ingroup PJ_DS

- * @brief

- * Red/Black tree is the variant of balanced tree, where the search, insert, 

- * and delete operation is \b guaranteed to take at most \a O( lg(n) ).

- * @{

- */

-/**

- * Color type for Red-Black tree.

- */ 

-typedef enum pj_rbcolor_t

-{

-    PJ_RBCOLOR_BLACK,

-    PJ_RBCOLOR_RED

-} pj_rbcolor_t;

-

-/**

- * The type of the node of the R/B Tree.

- */

-typedef struct pj_rbtree_node 

-{

-    /** Pointers to the node's parent, and left and right siblings. */

-    struct pj_rbtree_node *parent, *left, *right;

-

-    /** Key associated with the node. */

-    const void *key;

-

-    /** User data associated with the node. */

-    void *user_data;

-

-    /** The R/B Tree node color. */

-    pj_rbcolor_t color;

-

-} pj_rbtree_node;

-

-

-/**

- * The type of function use to compare key value of tree node.

- * @return

- *  0 if the keys are equal

- * <0 if key1 is lower than key2

- * >0 if key1 is greater than key2.

- */

-typedef int pj_rbtree_comp(const void *key1, const void *key2);

-

-

-/**

- * Declaration of a red-black tree. All elements in the tree must have UNIQUE

- * key.

- * A red black tree always maintains the balance of the tree, so that the

- * tree height will not be greater than lg(N). Insert, search, and delete

- * operation will take lg(N) on the worst case. But for insert and delete,

- * there is additional time needed to maintain the balance of the tree.

- */

-typedef struct pj_rbtree

-{

-    pj_rbtree_node null_node;   /**< Constant to indicate NULL node.    */

-    pj_rbtree_node *null;       /**< Constant to indicate NULL node.    */

-    pj_rbtree_node *root;       /**< Root tree node.                    */

-    unsigned size;              /**< Number of elements in the tree.    */

-    pj_rbtree_comp *comp;       /**< Key comparison function.           */

-} pj_rbtree;

-

-

-/**

- * Guidance on how much memory required for each of the node.

- */

-#define PJ_RBTREE_NODE_SIZE	    (sizeof(pj_rbtree_node))

-

-

-/**

- * Guidance on memory required for the tree.

- */

-#define PJ_RBTREE_SIZE		    (sizeof(pj_rbtree))

-

-

-/**

- * Initialize the tree.

- * @param tree the tree to be initialized.

- * @param comp key comparison function to be used for this tree.

- */

-PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp);

-

-/**

- * Get the first element in the tree.

- * The first element always has the least value for the key, according to

- * the comparison function.

- * @param tree the tree.

- * @return the tree node, or NULL if the tree has no element.

- */

-PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree );

-

-/**

- * Get the last element in the tree.

- * The last element always has the greatest key value, according to the

- * comparison function defined for the tree.

- * @param tree the tree.

- * @return the tree node, or NULL if the tree has no element.

- */

-PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree );

-

-/**

- * Get the successive element for the specified node.

- * The successive element is an element with greater key value.

- * @param tree the tree.

- * @param node the node.

- * @return the successive node, or NULL if the node has no successor.

- */

-PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 

-					 pj_rbtree_node *node );

-

-/**

- * The the previous node for the specified node.

- * The previous node is an element with less key value.

- * @param tree the tree.

- * @param node the node.

- * @return the previous node, or NULL if the node has no previous node.

- */

-PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 

-					 pj_rbtree_node *node );

-

-/**

- * Insert a new node. 

- * The node will be inserted at sorted location. The key of the node must 

- * be UNIQUE, i.e. it hasn't existed in the tree.

- * @param tree the tree.

- * @param node the node to be inserted.

- * @return zero on success, or -1 if the key already exist.

- */

-PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree, 

-			       pj_rbtree_node *node );

-

-/**

- * Find a node which has the specified key.

- * @param tree the tree.

- * @param key the key to search.

- * @return the tree node with the specified key, or NULL if the key can not

- *         be found.

- */

-PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,

-					 const void *key );

-

-/**

- * Erase a node from the tree.

- * @param tree the tree.

- * @param node the node to be erased.

- * @return the tree node itself.

- */

-PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,

-					  pj_rbtree_node *node );

-

-/**

- * Get the maximum tree height from the specified node.

- * @param tree the tree.

- * @param node the node, or NULL to get the root of the tree.

- * @return the maximum height, which should be at most lg(N)

- */

-PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree,

-					pj_rbtree_node *node );

-

-/**

- * Get the minumum tree height from the specified node.

- * @param tree the tree.

- * @param node the node, or NULL to get the root of the tree.

- * @return the height

- */

-PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree,

-					pj_rbtree_node *node );

-

-

-/**

- * @}

- */

-

-PJ_END_DECL

-

-#endif	/* __PJ_RBTREE_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_RBTREE_H__
+#define __PJ_RBTREE_H__
+
+/**
+ * @file rbtree.h
+ * @brief Red/Black Tree
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_RBTREE Red/Black Balanced Tree
+ * @ingroup PJ_DS
+ * @brief
+ * Red/Black tree is the variant of balanced tree, where the search, insert, 
+ * and delete operation is \b guaranteed to take at most \a O( lg(n) ).
+ * @{
+ */
+/**
+ * Color type for Red-Black tree.
+ */ 
+typedef enum pj_rbcolor_t
+{
+    PJ_RBCOLOR_BLACK,
+    PJ_RBCOLOR_RED
+} pj_rbcolor_t;
+
+/**
+ * The type of the node of the R/B Tree.
+ */
+typedef struct pj_rbtree_node 
+{
+    /** Pointers to the node's parent, and left and right siblings. */
+    struct pj_rbtree_node *parent, *left, *right;
+
+    /** Key associated with the node. */
+    const void *key;
+
+    /** User data associated with the node. */
+    void *user_data;
+
+    /** The R/B Tree node color. */
+    pj_rbcolor_t color;
+
+} pj_rbtree_node;
+
+
+/**
+ * The type of function use to compare key value of tree node.
+ * @return
+ *  0 if the keys are equal
+ * <0 if key1 is lower than key2
+ * >0 if key1 is greater than key2.
+ */
+typedef int pj_rbtree_comp(const void *key1, const void *key2);
+
+
+/**
+ * Declaration of a red-black tree. All elements in the tree must have UNIQUE
+ * key.
+ * A red black tree always maintains the balance of the tree, so that the
+ * tree height will not be greater than lg(N). Insert, search, and delete
+ * operation will take lg(N) on the worst case. But for insert and delete,
+ * there is additional time needed to maintain the balance of the tree.
+ */
+typedef struct pj_rbtree
+{
+    pj_rbtree_node null_node;   /**< Constant to indicate NULL node.    */
+    pj_rbtree_node *null;       /**< Constant to indicate NULL node.    */
+    pj_rbtree_node *root;       /**< Root tree node.                    */
+    unsigned size;              /**< Number of elements in the tree.    */
+    pj_rbtree_comp *comp;       /**< Key comparison function.           */
+} pj_rbtree;
+
+
+/**
+ * Guidance on how much memory required for each of the node.
+ */
+#define PJ_RBTREE_NODE_SIZE	    (sizeof(pj_rbtree_node))
+
+
+/**
+ * Guidance on memory required for the tree.
+ */
+#define PJ_RBTREE_SIZE		    (sizeof(pj_rbtree))
+
+
+/**
+ * Initialize the tree.
+ * @param tree the tree to be initialized.
+ * @param comp key comparison function to be used for this tree.
+ */
+PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp);
+
+/**
+ * Get the first element in the tree.
+ * The first element always has the least value for the key, according to
+ * the comparison function.
+ * @param tree the tree.
+ * @return the tree node, or NULL if the tree has no element.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree );
+
+/**
+ * Get the last element in the tree.
+ * The last element always has the greatest key value, according to the
+ * comparison function defined for the tree.
+ * @param tree the tree.
+ * @return the tree node, or NULL if the tree has no element.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree );
+
+/**
+ * Get the successive element for the specified node.
+ * The successive element is an element with greater key value.
+ * @param tree the tree.
+ * @param node the node.
+ * @return the successive node, or NULL if the node has no successor.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 
+					 pj_rbtree_node *node );
+
+/**
+ * The the previous node for the specified node.
+ * The previous node is an element with less key value.
+ * @param tree the tree.
+ * @param node the node.
+ * @return the previous node, or NULL if the node has no previous node.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 
+					 pj_rbtree_node *node );
+
+/**
+ * Insert a new node. 
+ * The node will be inserted at sorted location. The key of the node must 
+ * be UNIQUE, i.e. it hasn't existed in the tree.
+ * @param tree the tree.
+ * @param node the node to be inserted.
+ * @return zero on success, or -1 if the key already exist.
+ */
+PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree, 
+			       pj_rbtree_node *node );
+
+/**
+ * Find a node which has the specified key.
+ * @param tree the tree.
+ * @param key the key to search.
+ * @return the tree node with the specified key, or NULL if the key can not
+ *         be found.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,
+					 const void *key );
+
+/**
+ * Erase a node from the tree.
+ * @param tree the tree.
+ * @param node the node to be erased.
+ * @return the tree node itself.
+ */
+PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,
+					  pj_rbtree_node *node );
+
+/**
+ * Get the maximum tree height from the specified node.
+ * @param tree the tree.
+ * @param node the node, or NULL to get the root of the tree.
+ * @return the maximum height, which should be at most lg(N)
+ */
+PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree,
+					pj_rbtree_node *node );
+
+/**
+ * Get the minumum tree height from the specified node.
+ * @param tree the tree.
+ * @param node the node, or NULL to get the root of the tree.
+ * @return the height
+ */
+PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree,
+					pj_rbtree_node *node );
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif	/* __PJ_RBTREE_H__ */
+
diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
index ebadcf3..02d88c1 100644
--- a/pjlib/include/pj/sock.h
+++ b/pjlib/include/pj/sock.h
@@ -1,700 +1,700 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_SOCK_H__

-#define __PJ_SOCK_H__

-

-/**

- * @file sock.h

- * @brief Socket Abstraction.

- */

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL 

-

-

-/**

- * @defgroup PJ_SOCK Socket Abstraction

- * @ingroup PJ_IO

- * @{

- *

- * The PJLIB socket abstraction layer is a thin and very portable abstraction

- * for socket API. It provides API similar to BSD socket API. The abstraction

- * is needed because BSD socket API is not always available on all platforms,

- * therefore it wouldn't be possible to create a trully portable network

- * programs unless we provide such abstraction.

- *

- * Applications can use this API directly in their application, just

- * as they would when using traditional BSD socket API, provided they

- * call #pj_init() first.

- *

- * \section pj_sock_examples_sec Examples

- *

- * For some examples on how to use the socket API, please see:

- *

- *  - \ref page_pjlib_sock_test

- *  - \ref page_pjlib_select_test

- *  - \ref page_pjlib_sock_perf_test

- */

-

-

-/**

- * Supported address families. 

- * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE

- * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE.

- */

-extern const pj_uint16_t PJ_AF_UNIX;    /**< Unix domain socket.	*/

-#define PJ_AF_LOCAL	 PJ_AF_UNIX;    /**< POSIX name for AF_UNIX	*/

-extern const pj_uint16_t PJ_AF_INET;    /**< Internet IP protocol.	*/

-extern const pj_uint16_t PJ_AF_INET6;   /**< IP version 6.		*/

-extern const pj_uint16_t PJ_AF_PACKET;  /**< Packet family.		*/

-extern const pj_uint16_t PJ_AF_IRDA;    /**< IRDA sockets.		*/

-

-

-/**

- * Supported types of sockets.

- * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE

- * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.

- */

-

-extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection-

-					      based byte streams.           */

-extern const pj_uint16_t PJ_SOCK_DGRAM;  /**< Connectionless, unreliable 

-					      datagrams of fixed maximum 

-					      lengths.                      */

-extern const pj_uint16_t PJ_SOCK_RAW;    /**< Raw protocol interface.       */

-extern const pj_uint16_t PJ_SOCK_RDM;    /**< Reliably-delivered messages.  */

-

-

-/**

- * Socket level specified in #pj_sock_setsockopt() or #pj_sock_getsockopt().

- * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE

- * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.

- */

-extern const pj_uint16_t PJ_SOL_SOCKET;	/**< Socket level.  */

-extern const pj_uint16_t PJ_SOL_IP;	/**< IP level.	    */

-extern const pj_uint16_t PJ_SOL_TCP;	/**< TCP level.	    */

-extern const pj_uint16_t PJ_SOL_UDP;	/**< UDP level.	    */

-extern const pj_uint16_t PJ_SOL_IPV6;	/**< IP version 6   */

-

-/**

- * Values to be specified as \c optname when calling #pj_sock_setsockopt() 

- * or #pj_sock_getsockopt().

- */

-extern const pj_uint16_t PJ_SO_TYPE;    /**< Socket type.               */

-extern const pj_uint16_t PJ_SO_RCVBUF;  /**< Buffer size for receive.   */

-extern const pj_uint16_t PJ_SO_SNDBUF;  /**< Buffer size for send.      */

-

-

-/**

- * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc.

- */

-typedef enum pj_sock_msg_flag

-{

-    PJ_MSG_OOB		= 0x01,	    /**< Out-of-band messages.		 */

-    PJ_MSG_PEEK		= 0x02,	    /**< Peek, don't remove from buffer. */

-    PJ_MSG_DONTROUTE	= 0x04,	    /**< Don't route.			 */

-} pj_sock_msg_flag;

-

-

-/**

- * Flag to be specified in #pj_sock_shutdown.

- */

-typedef enum pj_socket_sd_type

-{

-    PJ_SD_RECEIVE   = 0,    /**< No more receive.	    */

-    PJ_SHUT_RD	    = 0,    /**< Alias for SD_RECEIVE.	    */

-    PJ_SD_SEND	    = 1,    /**< No more sending.	    */

-    PJ_SHUT_WR	    = 1,    /**< Alias for SD_SEND.	    */

-    PJ_SD_BOTH	    = 2,    /**< No more send and receive.  */

-    PJ_SHUT_RDWR    = 2,    /**< Alias for SD_BOTH.	    */

-} pj_socket_sd_type;

-

-

-

-/** Address to accept any incoming messages. */

-#define PJ_INADDR_ANY	    ((pj_uint32_t)0)

-

-/** Address indicating an error return */

-#define PJ_INADDR_NONE	    ((pj_uint32_t)0xffffffff)

-

-/** Address to send to all hosts. */

-#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff)

-

-

-/** 

- * Maximum length specifiable by #pj_sock_listen().

- * If the build system doesn't override this value, then the lowest 

- * denominator (five, in Win32 systems) will be used.

- */

-#if !defined(PJ_SOMAXCONN)

-#  define PJ_SOMAXCONN	5

-#endif

-

-

-/**

- * Constant for invalid socket returned by #pj_sock_socket() and

- * #pj_sock_accept().

- */

-#define PJ_INVALID_SOCKET   (-1)

-

-/**

- * Structure describing a generic socket address.

- */

-typedef struct pj_sockaddr

-{

-    pj_uint16_t	sa_family;	/**< Common data: address family.   */

-    char	sa_data[14];	/**< Address data.		    */

-} pj_sockaddr;

-

-

-/**

- * This structure describes Internet address.

- */

-typedef struct pj_in_addr

-{

-    pj_uint32_t	s_addr;		/**< The 32bit IP address.	    */

-} pj_in_addr;

-

-

-/**

- * This structure describes Internet socket address.

- */

-typedef struct pj_sockaddr_in

-{

-    pj_uint16_t	sin_family;	/**< Address family.		    */

-    pj_uint16_t	sin_port;	/**< Transport layer port number.   */

-    pj_in_addr	sin_addr;	/**< IP address.		    */

-    char	sin_zero[8];	/**< Padding.			    */

-} pj_sockaddr_in;

-

-

-/**

- * This structure describes IPv6 address.

- */

-typedef struct pj_in6_addr

-{

-    /** Union of address formats. */

-    union {

-	pj_uint8_t  u6_addr8[16];   /**< u6_addr8   */

-	pj_uint16_t u6_addr16[8];   /**< u6_addr16  */

-	pj_uint32_t u6_addr32[4];   /**< u6_addr32  */

-    } in6_u;

-/** Shortcut to access in6_u.u6_addr8. */

-#define s6_addr                 in6_u.u6_addr8

-/** Shortcut to access in6_u.u6_addr16. */

-#define s6_addr16               in6_u.u6_addr16

-/** Shortcut to access in6_u.u6_addr32. */

-#define s6_addr32               in6_u.u6_addr32

-} pj_in6_addr;

-

-/** Initializer value for pj_in6_addr. */

-#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }

-

-/** Initializer value for pj_in6_addr. */

-#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }

-

-/**

- * This structure describes IPv6 socket address.

- */

-typedef struct pj_sockaddr_in6

-{

-    pj_uint16_t	sin6_family;	    /**< Address family		    */

-    pj_uint16_t	sin6_port;	    /**< Transport layer port number. */

-    pj_uint32_t	sin6_flowinfo;	    /**< IPv6 flow information	    */

-    pj_in6_addr sin6_addr;	    /**< IPv6 address.		    */

-    pj_uint32_t sin6_scope_id;	    /**< IPv6 scope-id		    */

-} pj_sockaddr_in6;

-

-

-/*****************************************************************************

- *

- * SOCKET ADDRESS MANIPULATION.

- *

- *****************************************************************************

- */

-

-/**

- * Convert 16-bit value from network byte order to host byte order.

- *

- * @param netshort  16-bit network value.

- * @return	    16-bit host value.

- */

-PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort);

-

-/**

- * Convert 16-bit value from host byte order to network byte order.

- *

- * @param hostshort 16-bit host value.

- * @return	    16-bit network value.

- */

-PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort);

-

-/**

- * Convert 32-bit value from network byte order to host byte order.

- *

- * @param netlong   32-bit network value.

- * @return	    32-bit host value.

- */

-PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong);

-

-/**

- * Convert 32-bit value from host byte order to network byte order.

- *

- * @param hostlong  32-bit host value.

- * @return	    32-bit network value.

- */

-PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong);

-

-/**

- * Convert an Internet host address given in network byte order

- * to string in standard numbers and dots notation.

- *

- * @param inaddr    The host address.

- * @return	    The string address.

- */

-PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr);

-

-/**

- * This function converts the Internet host address cp from the standard

- * numbers-and-dots notation into binary data and stores it in the structure

- * that inp points to. 

- *

- * @param cp	IP address in standard numbers-and-dots notation.

- * @param inp	Structure that holds the output of the conversion.

- *

- * @return	nonzero if the address is valid, zero if not.

- */

-PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp);

-

-/**

- * Convert address string with numbers and dots to binary IP address.

- * 

- * @param cp	    The IP address in numbers and dots notation.

- * @return	    If success, the IP address is returned in network

- *		    byte order. If failed, PJ_INADDR_NONE will be

- *		    returned.

- * @remark

- * This is an obsolete interface to #pj_inet_aton(); it is obsolete

- * because -1 is a valid address (255.255.255.255), and #pj_inet_aton()

- * provides a cleaner way to indicate error return.

- */

-PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp);

-

-

-/**

- * Get the transport layer port number of an Internet socket address.

- * The port is returned in host byte order.

- *

- * @param addr	    The IP socket address.

- * @return	    Port number, in host byte order.

- */

-PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)

-{

-    return pj_ntohs(addr->sin_port);

-}

-

-/**

- * Set the port number of an Internet socket address.

- *

- * @param addr	    The IP socket address.

- * @param hostport  The port number, in host byte order.

- */

-PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 

-					pj_uint16_t hostport)

-{

-    addr->sin_port = pj_htons(hostport);

-}

-

-/**

- * Get the IP address of an Internet socket address.

- * The address is returned as 32bit value in host byte order.

- *

- * @param addr	    The IP socket address.

- * @return	    32bit address, in host byte order.

- */

-PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)

-{

-    pj_in_addr in_addr;

-    in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);

-    return in_addr;

-};

-

-/**

- * Set the IP address of an Internet socket address.

- *

- * @param addr	    The IP socket address.

- * @param hostaddr  The host address, in host byte order.

- */

-PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,

-					pj_uint32_t hostaddr)

-{

-    addr->sin_addr.s_addr = pj_htonl(hostaddr);

-}

-

-/**

- * 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.

- *

- * @param addr	    The IP socket address to be set.

- * @param cp	    The address string, which can be in a standard 

- *		    dotted numbers or a hostname to be resolved.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,

-					          const pj_str_t *cp);

-

-/**

- * 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.

- *

- * @param addr	    The IP socket address to be set.

- * @param cp	    The address string, which can be in a standard 

- *		    dotted numbers or a hostname to be resolved.

- * @param port	    The port number, in host byte order.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,

-				          const pj_str_t *cp,

-					  pj_uint16_t port);

-

-

-/*****************************************************************************

- *

- * HOST NAME AND ADDRESS.

- *

- *****************************************************************************

- */

-

-/**

- * Get system's host name.

- *

- * @return	    The hostname, or empty string if the hostname can not

- *		    be identified.

- */

-PJ_DECL(const pj_str_t*) pj_gethostname(void);

-

-/**

- * Get host's IP address, which the the first IP address that is resolved

- * from the hostname.

- *

- * @return	    The host's IP address, PJ_INADDR_NONE if the host

- *		    IP address can not be identified.

- */

-PJ_DECL(pj_in_addr) pj_gethostaddr(void);

-

-

-/*****************************************************************************

- *

- * SOCKET API.

- *

- *****************************************************************************

- */

-

-/**

- * Create new socket/endpoint for communication.

- *

- * @param family    Specifies a communication domain; this selects the

- *		    protocol family which will be used for communication.

- * @param type	    The socket has the indicated type, which specifies the 

- *		    communication semantics.

- * @param protocol  Specifies  a  particular  protocol  to  be used with the

- *		    socket.  Normally only a single protocol exists to support 

- *		    a particular socket  type  within  a given protocol family, 

- *		    in which a case protocol can be specified as 0.

- * @param sock	    New socket descriptor, or PJ_INVALID_SOCKET on error.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_socket(int family, 

-				    int type, 

-				    int protocol,

-				    pj_sock_t *sock);

-

-/**

- * Close the socket descriptor.

- *

- * @param sockfd    The socket descriptor.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd);

-

-

-/**

- * This function gives the socket sockfd the local address my_addr. my_addr is

- * addrlen bytes long.  Traditionally, this is called assigning a name to

- * a socket. When a socket is created with #pj_sock_socket(), it exists in a

- * name space (address family) but has no name assigned.

- *

- * @param sockfd    The socket desriptor.

- * @param my_addr   The local address to bind the socket to.

- * @param addrlen   The length of the address.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd, 

-				   const pj_sockaddr_t *my_addr,

-				   int addrlen);

-

-/**

- * Bind the IP socket sockfd to the given address and port.

- *

- * @param sockfd    The socket descriptor.

- * @param addr	    Local address to bind the socket to, in host byte order.

- * @param port	    The local port to bind the socket to, in host byte order.

- *

- * @return	    Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, 

-				      pj_uint32_t addr,

-				      pj_uint16_t port);

-

-#if PJ_HAS_TCP

-/**

- * Listen for incoming connection. This function only applies to connection

- * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it

- * indicates the willingness to accept incoming connections.

- *

- * @param sockfd	The socket descriptor.

- * @param backlog	Defines the maximum length the queue of pending

- *			connections may grow to.

- *

- * @return		Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd, 

-				     int backlog );

-

-/**

- * Accept new connection on the specified connection oriented server socket.

- *

- * @param serverfd  The server socket.

- * @param newsock   New socket on success, of PJ_INVALID_SOCKET if failed.

- * @param addr	    A pointer to sockaddr type. If the argument is not NULL,

- *		    it will be filled by the address of connecting entity.

- * @param addrlen   Initially specifies the length of the address, and upon

- *		    return will be filled with the exact address length.

- *

- * @return	    Zero on success, or the error number.

- */

-PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd,

-				     pj_sock_t *newsock,

-				     pj_sockaddr_t *addr,

-				     int *addrlen);

-#endif

-

-/**

- * The file descriptor sockfd must refer to a socket.  If the socket is of

- * type PJ_SOCK_DGRAM  then the serv_addr address is the address to which

- * datagrams are sent by default, and the only address from which datagrams

- * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET,

- * this call attempts to make a connection to another socket.  The

- * other socket is specified by serv_addr, which is an address (of length

- * addrlen) in the communications space of the  socket.  Each  communications

- * space interprets the serv_addr parameter in its own way.

- *

- * @param sockfd	The socket descriptor.

- * @param serv_addr	Server address to connect to.

- * @param addrlen	The length of server address.

- *

- * @return		Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd,

-				      const pj_sockaddr_t *serv_addr,

-				      int addrlen);

-

-/**

- * Return the address of peer which is connected to socket sockfd.

- *

- * @param sockfd	The socket descriptor.

- * @param addr		Pointer to sockaddr structure to which the address

- *			will be returned.

- * @param namelen	Initially the length of the addr. Upon return the value

- *			will be set to the actual length of the address.

- *

- * @return		Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd,

-					  pj_sockaddr_t *addr,

-					  int *namelen);

-

-/**

- * Return the current name of the specified socket.

- *

- * @param sockfd	The socket descriptor.

- * @param addr		Pointer to sockaddr structure to which the address

- *			will be returned.

- * @param namelen	Initially the length of the addr. Upon return the value

- *			will be set to the actual length of the address.

- *

- * @return		Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,

-					  pj_sockaddr_t *addr,

-					  int *namelen);

-

-/**

- * Get socket option associated with a socket. Options may exist at multiple

- * protocol levels; they are always present at the uppermost socket level.

- *

- * @param sockfd	The socket descriptor.

- * @param level		The level which to get the option from.

- * @param optname	The option name.

- * @param optval	Identifies the buffer which the value will be

- *			returned.

- * @param optlen	Initially contains the length of the buffer, upon

- *			return will be set to the actual size of the value.

- *

- * @return		Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,

-					 pj_uint16_t level,

-					 pj_uint16_t optname,

-					 void *optval,

-					 int *optlen);

-/**

- * Manipulate the options associated with a socket. Options may exist at 

- * multiple protocol levels; they are always present at the uppermost socket 

- * level.

- *

- * @param sockfd	The socket descriptor.

- * @param level		The level which to get the option from.

- * @param optname	The option name.

- * @param optval	Identifies the buffer which contain the value.

- * @param optlen	The length of the value.

- *

- * @return		PJ_SUCCESS or the status code.

- */

-PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,

-					 pj_uint16_t level,

-					 pj_uint16_t optname,

-					 const void *optval,

-					 int optlen);

-

-

-/**

- * Receives data stream or message coming to the specified socket.

- *

- * @param sockfd	The socket descriptor.

- * @param buf		The buffer to receive the data or message.

- * @param len		On input, the length of the buffer. On return,

- *			contains the length of data received.

- * @param flags		Combination of #pj_sock_msg_flag.

- *

- * @return		PJ_SUCCESS or the error code.

- */

-PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd,

-				  void *buf,

-				  pj_ssize_t *len,

-				  unsigned flags);

-

-/**

- * Receives data stream or message coming to the specified socket.

- *

- * @param sockfd	The socket descriptor.

- * @param buf		The buffer to receive the data or message.

- * @param len		On input, the length of the buffer. On return,

- *			contains the length of data received.

- * @param flags		Bitmask combination of #pj_sock_msg_flag.

- * @param from		If not NULL, it will be filled with the source

- *			address of the connection.

- * @param fromlen	Initially contains the length of from address,

- *			and upon return will be filled with the actual

- *			length of the address.

- *

- * @return		PJ_SUCCESS or the error code.

- */

-PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,

-				      void *buf,

-				      pj_ssize_t *len,

-				      unsigned flags,

-				      pj_sockaddr_t *from,

-				      int *fromlen);

-

-/**

- * Transmit data to the socket.

- *

- * @param sockfd	Socket descriptor.

- * @param buf		Buffer containing data to be sent.

- * @param len		On input, the length of the data in the buffer.

- *			Upon return, it will be filled with the length

- *			of data sent.

- * @param flags		Bitmask combination of #pj_sock_msg_flag.

- *

- * @return		PJ_SUCCESS or the status code.

- */

-PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd,

-				  const void *buf,

-				  pj_ssize_t *len,

-				  unsigned flags);

-

-/**

- * Transmit data to the socket to the specified address.

- *

- * @param sockfd	Socket descriptor.

- * @param buf		Buffer containing data to be sent.

- * @param len		On input, the length of the data in the buffer.

- *			Upon return, it will be filled with the length

- *			of data sent.

- * @param flags		Bitmask combination of #pj_sock_msg_flag.

- * @param to		The address to send.

- * @param tolen		The length of the address in bytes.

- *

- * @return		The length of data successfully sent.

- */

-PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd,

-				    const void *buf,

-				    pj_ssize_t *len,

-				    unsigned flags,

-				    const pj_sockaddr_t *to,

-				    int tolen);

-

-#if PJ_HAS_TCP

-/**

- * The shutdown call causes all or part of a full-duplex connection on the

- * socket associated with sockfd to be shut down.

- *

- * @param sockfd	The socket descriptor.

- * @param how		If how is PJ_SHUT_RD, further receptions will be 

- *			disallowed. If how is PJ_SHUT_WR, further transmissions

- *			will be disallowed. If how is PJ_SHUT_RDWR, further 

- *			receptions andtransmissions will be disallowed.

- *

- * @return		Zero on success.

- */

-PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,

-				       int how);

-#endif

-

-/**

- * @}

- */

-

-

-PJ_END_DECL

-

-#endif	/* __PJ_SOCK_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_SOCK_H__
+#define __PJ_SOCK_H__
+
+/**
+ * @file sock.h
+ * @brief Socket Abstraction.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL 
+
+
+/**
+ * @defgroup PJ_SOCK Socket Abstraction
+ * @ingroup PJ_IO
+ * @{
+ *
+ * The PJLIB socket abstraction layer is a thin and very portable abstraction
+ * for socket API. It provides API similar to BSD socket API. The abstraction
+ * is needed because BSD socket API is not always available on all platforms,
+ * therefore it wouldn't be possible to create a trully portable network
+ * programs unless we provide such abstraction.
+ *
+ * Applications can use this API directly in their application, just
+ * as they would when using traditional BSD socket API, provided they
+ * call #pj_init() first.
+ *
+ * \section pj_sock_examples_sec Examples
+ *
+ * For some examples on how to use the socket API, please see:
+ *
+ *  - \ref page_pjlib_sock_test
+ *  - \ref page_pjlib_select_test
+ *  - \ref page_pjlib_sock_perf_test
+ */
+
+
+/**
+ * Supported address families. 
+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE
+ * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE.
+ */
+extern const pj_uint16_t PJ_AF_UNIX;    /**< Unix domain socket.	*/
+#define PJ_AF_LOCAL	 PJ_AF_UNIX;    /**< POSIX name for AF_UNIX	*/
+extern const pj_uint16_t PJ_AF_INET;    /**< Internet IP protocol.	*/
+extern const pj_uint16_t PJ_AF_INET6;   /**< IP version 6.		*/
+extern const pj_uint16_t PJ_AF_PACKET;  /**< Packet family.		*/
+extern const pj_uint16_t PJ_AF_IRDA;    /**< IRDA sockets.		*/
+
+
+/**
+ * Supported types of sockets.
+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE
+ * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.
+ */
+
+extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection-
+					      based byte streams.           */
+extern const pj_uint16_t PJ_SOCK_DGRAM;  /**< Connectionless, unreliable 
+					      datagrams of fixed maximum 
+					      lengths.                      */
+extern const pj_uint16_t PJ_SOCK_RAW;    /**< Raw protocol interface.       */
+extern const pj_uint16_t PJ_SOCK_RDM;    /**< Reliably-delivered messages.  */
+
+
+/**
+ * Socket level specified in #pj_sock_setsockopt() or #pj_sock_getsockopt().
+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE
+ * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.
+ */
+extern const pj_uint16_t PJ_SOL_SOCKET;	/**< Socket level.  */
+extern const pj_uint16_t PJ_SOL_IP;	/**< IP level.	    */
+extern const pj_uint16_t PJ_SOL_TCP;	/**< TCP level.	    */
+extern const pj_uint16_t PJ_SOL_UDP;	/**< UDP level.	    */
+extern const pj_uint16_t PJ_SOL_IPV6;	/**< IP version 6   */
+
+/**
+ * Values to be specified as \c optname when calling #pj_sock_setsockopt() 
+ * or #pj_sock_getsockopt().
+ */
+extern const pj_uint16_t PJ_SO_TYPE;    /**< Socket type.               */
+extern const pj_uint16_t PJ_SO_RCVBUF;  /**< Buffer size for receive.   */
+extern const pj_uint16_t PJ_SO_SNDBUF;  /**< Buffer size for send.      */
+
+
+/**
+ * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc.
+ */
+typedef enum pj_sock_msg_flag
+{
+    PJ_MSG_OOB		= 0x01,	    /**< Out-of-band messages.		 */
+    PJ_MSG_PEEK		= 0x02,	    /**< Peek, don't remove from buffer. */
+    PJ_MSG_DONTROUTE	= 0x04,	    /**< Don't route.			 */
+} pj_sock_msg_flag;
+
+
+/**
+ * Flag to be specified in #pj_sock_shutdown.
+ */
+typedef enum pj_socket_sd_type
+{
+    PJ_SD_RECEIVE   = 0,    /**< No more receive.	    */
+    PJ_SHUT_RD	    = 0,    /**< Alias for SD_RECEIVE.	    */
+    PJ_SD_SEND	    = 1,    /**< No more sending.	    */
+    PJ_SHUT_WR	    = 1,    /**< Alias for SD_SEND.	    */
+    PJ_SD_BOTH	    = 2,    /**< No more send and receive.  */
+    PJ_SHUT_RDWR    = 2,    /**< Alias for SD_BOTH.	    */
+} pj_socket_sd_type;
+
+
+
+/** Address to accept any incoming messages. */
+#define PJ_INADDR_ANY	    ((pj_uint32_t)0)
+
+/** Address indicating an error return */
+#define PJ_INADDR_NONE	    ((pj_uint32_t)0xffffffff)
+
+/** Address to send to all hosts. */
+#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff)
+
+
+/** 
+ * Maximum length specifiable by #pj_sock_listen().
+ * If the build system doesn't override this value, then the lowest 
+ * denominator (five, in Win32 systems) will be used.
+ */
+#if !defined(PJ_SOMAXCONN)
+#  define PJ_SOMAXCONN	5
+#endif
+
+
+/**
+ * Constant for invalid socket returned by #pj_sock_socket() and
+ * #pj_sock_accept().
+ */
+#define PJ_INVALID_SOCKET   (-1)
+
+/**
+ * Structure describing a generic socket address.
+ */
+typedef struct pj_sockaddr
+{
+    pj_uint16_t	sa_family;	/**< Common data: address family.   */
+    char	sa_data[14];	/**< Address data.		    */
+} pj_sockaddr;
+
+
+/**
+ * This structure describes Internet address.
+ */
+typedef struct pj_in_addr
+{
+    pj_uint32_t	s_addr;		/**< The 32bit IP address.	    */
+} pj_in_addr;
+
+
+/**
+ * This structure describes Internet socket address.
+ */
+typedef struct pj_sockaddr_in
+{
+    pj_uint16_t	sin_family;	/**< Address family.		    */
+    pj_uint16_t	sin_port;	/**< Transport layer port number.   */
+    pj_in_addr	sin_addr;	/**< IP address.		    */
+    char	sin_zero[8];	/**< Padding.			    */
+} pj_sockaddr_in;
+
+
+/**
+ * This structure describes IPv6 address.
+ */
+typedef struct pj_in6_addr
+{
+    /** Union of address formats. */
+    union {
+	pj_uint8_t  u6_addr8[16];   /**< u6_addr8   */
+	pj_uint16_t u6_addr16[8];   /**< u6_addr16  */
+	pj_uint32_t u6_addr32[4];   /**< u6_addr32  */
+    } in6_u;
+/** Shortcut to access in6_u.u6_addr8. */
+#define s6_addr                 in6_u.u6_addr8
+/** Shortcut to access in6_u.u6_addr16. */
+#define s6_addr16               in6_u.u6_addr16
+/** Shortcut to access in6_u.u6_addr32. */
+#define s6_addr32               in6_u.u6_addr32
+} pj_in6_addr;
+
+/** Initializer value for pj_in6_addr. */
+#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+
+/** Initializer value for pj_in6_addr. */
+#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+
+/**
+ * This structure describes IPv6 socket address.
+ */
+typedef struct pj_sockaddr_in6
+{
+    pj_uint16_t	sin6_family;	    /**< Address family		    */
+    pj_uint16_t	sin6_port;	    /**< Transport layer port number. */
+    pj_uint32_t	sin6_flowinfo;	    /**< IPv6 flow information	    */
+    pj_in6_addr sin6_addr;	    /**< IPv6 address.		    */
+    pj_uint32_t sin6_scope_id;	    /**< IPv6 scope-id		    */
+} pj_sockaddr_in6;
+
+
+/*****************************************************************************
+ *
+ * SOCKET ADDRESS MANIPULATION.
+ *
+ *****************************************************************************
+ */
+
+/**
+ * Convert 16-bit value from network byte order to host byte order.
+ *
+ * @param netshort  16-bit network value.
+ * @return	    16-bit host value.
+ */
+PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort);
+
+/**
+ * Convert 16-bit value from host byte order to network byte order.
+ *
+ * @param hostshort 16-bit host value.
+ * @return	    16-bit network value.
+ */
+PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort);
+
+/**
+ * Convert 32-bit value from network byte order to host byte order.
+ *
+ * @param netlong   32-bit network value.
+ * @return	    32-bit host value.
+ */
+PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong);
+
+/**
+ * Convert 32-bit value from host byte order to network byte order.
+ *
+ * @param hostlong  32-bit host value.
+ * @return	    32-bit network value.
+ */
+PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong);
+
+/**
+ * Convert an Internet host address given in network byte order
+ * to string in standard numbers and dots notation.
+ *
+ * @param inaddr    The host address.
+ * @return	    The string address.
+ */
+PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr);
+
+/**
+ * This function converts the Internet host address cp from the standard
+ * numbers-and-dots notation into binary data and stores it in the structure
+ * that inp points to. 
+ *
+ * @param cp	IP address in standard numbers-and-dots notation.
+ * @param inp	Structure that holds the output of the conversion.
+ *
+ * @return	nonzero if the address is valid, zero if not.
+ */
+PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp);
+
+/**
+ * Convert address string with numbers and dots to binary IP address.
+ * 
+ * @param cp	    The IP address in numbers and dots notation.
+ * @return	    If success, the IP address is returned in network
+ *		    byte order. If failed, PJ_INADDR_NONE will be
+ *		    returned.
+ * @remark
+ * This is an obsolete interface to #pj_inet_aton(); it is obsolete
+ * because -1 is a valid address (255.255.255.255), and #pj_inet_aton()
+ * provides a cleaner way to indicate error return.
+ */
+PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp);
+
+
+/**
+ * Get the transport layer port number of an Internet socket address.
+ * The port is returned in host byte order.
+ *
+ * @param addr	    The IP socket address.
+ * @return	    Port number, in host byte order.
+ */
+PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
+{
+    return pj_ntohs(addr->sin_port);
+}
+
+/**
+ * Set the port number of an Internet socket address.
+ *
+ * @param addr	    The IP socket address.
+ * @param hostport  The port number, in host byte order.
+ */
+PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 
+					pj_uint16_t hostport)
+{
+    addr->sin_port = pj_htons(hostport);
+}
+
+/**
+ * Get the IP address of an Internet socket address.
+ * The address is returned as 32bit value in host byte order.
+ *
+ * @param addr	    The IP socket address.
+ * @return	    32bit address, in host byte order.
+ */
+PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)
+{
+    pj_in_addr in_addr;
+    in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);
+    return in_addr;
+};
+
+/**
+ * Set the IP address of an Internet socket address.
+ *
+ * @param addr	    The IP socket address.
+ * @param hostaddr  The host address, in host byte order.
+ */
+PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
+					pj_uint32_t hostaddr)
+{
+    addr->sin_addr.s_addr = pj_htonl(hostaddr);
+}
+
+/**
+ * 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.
+ *
+ * @param addr	    The IP socket address to be set.
+ * @param cp	    The address string, which can be in a standard 
+ *		    dotted numbers or a hostname to be resolved.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
+					          const pj_str_t *cp);
+
+/**
+ * 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.
+ *
+ * @param addr	    The IP socket address to be set.
+ * @param cp	    The address string, which can be in a standard 
+ *		    dotted numbers or a hostname to be resolved.
+ * @param port	    The port number, in host byte order.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
+				          const pj_str_t *cp,
+					  pj_uint16_t port);
+
+
+/*****************************************************************************
+ *
+ * HOST NAME AND ADDRESS.
+ *
+ *****************************************************************************
+ */
+
+/**
+ * Get system's host name.
+ *
+ * @return	    The hostname, or empty string if the hostname can not
+ *		    be identified.
+ */
+PJ_DECL(const pj_str_t*) pj_gethostname(void);
+
+/**
+ * Get host's IP address, which the the first IP address that is resolved
+ * from the hostname.
+ *
+ * @return	    The host's IP address, PJ_INADDR_NONE if the host
+ *		    IP address can not be identified.
+ */
+PJ_DECL(pj_in_addr) pj_gethostaddr(void);
+
+
+/*****************************************************************************
+ *
+ * SOCKET API.
+ *
+ *****************************************************************************
+ */
+
+/**
+ * Create new socket/endpoint for communication.
+ *
+ * @param family    Specifies a communication domain; this selects the
+ *		    protocol family which will be used for communication.
+ * @param type	    The socket has the indicated type, which specifies the 
+ *		    communication semantics.
+ * @param protocol  Specifies  a  particular  protocol  to  be used with the
+ *		    socket.  Normally only a single protocol exists to support 
+ *		    a particular socket  type  within  a given protocol family, 
+ *		    in which a case protocol can be specified as 0.
+ * @param sock	    New socket descriptor, or PJ_INVALID_SOCKET on error.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_socket(int family, 
+				    int type, 
+				    int protocol,
+				    pj_sock_t *sock);
+
+/**
+ * Close the socket descriptor.
+ *
+ * @param sockfd    The socket descriptor.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd);
+
+
+/**
+ * This function gives the socket sockfd the local address my_addr. my_addr is
+ * addrlen bytes long.  Traditionally, this is called assigning a name to
+ * a socket. When a socket is created with #pj_sock_socket(), it exists in a
+ * name space (address family) but has no name assigned.
+ *
+ * @param sockfd    The socket desriptor.
+ * @param my_addr   The local address to bind the socket to.
+ * @param addrlen   The length of the address.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd, 
+				   const pj_sockaddr_t *my_addr,
+				   int addrlen);
+
+/**
+ * Bind the IP socket sockfd to the given address and port.
+ *
+ * @param sockfd    The socket descriptor.
+ * @param addr	    Local address to bind the socket to, in host byte order.
+ * @param port	    The local port to bind the socket to, in host byte order.
+ *
+ * @return	    Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, 
+				      pj_uint32_t addr,
+				      pj_uint16_t port);
+
+#if PJ_HAS_TCP
+/**
+ * Listen for incoming connection. This function only applies to connection
+ * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it
+ * indicates the willingness to accept incoming connections.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param backlog	Defines the maximum length the queue of pending
+ *			connections may grow to.
+ *
+ * @return		Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd, 
+				     int backlog );
+
+/**
+ * Accept new connection on the specified connection oriented server socket.
+ *
+ * @param serverfd  The server socket.
+ * @param newsock   New socket on success, of PJ_INVALID_SOCKET if failed.
+ * @param addr	    A pointer to sockaddr type. If the argument is not NULL,
+ *		    it will be filled by the address of connecting entity.
+ * @param addrlen   Initially specifies the length of the address, and upon
+ *		    return will be filled with the exact address length.
+ *
+ * @return	    Zero on success, or the error number.
+ */
+PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
+				     pj_sock_t *newsock,
+				     pj_sockaddr_t *addr,
+				     int *addrlen);
+#endif
+
+/**
+ * The file descriptor sockfd must refer to a socket.  If the socket is of
+ * type PJ_SOCK_DGRAM  then the serv_addr address is the address to which
+ * datagrams are sent by default, and the only address from which datagrams
+ * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET,
+ * this call attempts to make a connection to another socket.  The
+ * other socket is specified by serv_addr, which is an address (of length
+ * addrlen) in the communications space of the  socket.  Each  communications
+ * space interprets the serv_addr parameter in its own way.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param serv_addr	Server address to connect to.
+ * @param addrlen	The length of server address.
+ *
+ * @return		Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
+				      const pj_sockaddr_t *serv_addr,
+				      int addrlen);
+
+/**
+ * Return the address of peer which is connected to socket sockfd.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param addr		Pointer to sockaddr structure to which the address
+ *			will be returned.
+ * @param namelen	Initially the length of the addr. Upon return the value
+ *			will be set to the actual length of the address.
+ *
+ * @return		Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd,
+					  pj_sockaddr_t *addr,
+					  int *namelen);
+
+/**
+ * Return the current name of the specified socket.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param addr		Pointer to sockaddr structure to which the address
+ *			will be returned.
+ * @param namelen	Initially the length of the addr. Upon return the value
+ *			will be set to the actual length of the address.
+ *
+ * @return		Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
+					  pj_sockaddr_t *addr,
+					  int *namelen);
+
+/**
+ * Get socket option associated with a socket. Options may exist at multiple
+ * protocol levels; they are always present at the uppermost socket level.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param level		The level which to get the option from.
+ * @param optname	The option name.
+ * @param optval	Identifies the buffer which the value will be
+ *			returned.
+ * @param optlen	Initially contains the length of the buffer, upon
+ *			return will be set to the actual size of the value.
+ *
+ * @return		Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
+					 pj_uint16_t level,
+					 pj_uint16_t optname,
+					 void *optval,
+					 int *optlen);
+/**
+ * Manipulate the options associated with a socket. Options may exist at 
+ * multiple protocol levels; they are always present at the uppermost socket 
+ * level.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param level		The level which to get the option from.
+ * @param optname	The option name.
+ * @param optval	Identifies the buffer which contain the value.
+ * @param optlen	The length of the value.
+ *
+ * @return		PJ_SUCCESS or the status code.
+ */
+PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
+					 pj_uint16_t level,
+					 pj_uint16_t optname,
+					 const void *optval,
+					 int optlen);
+
+
+/**
+ * Receives data stream or message coming to the specified socket.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param buf		The buffer to receive the data or message.
+ * @param len		On input, the length of the buffer. On return,
+ *			contains the length of data received.
+ * @param flags		Combination of #pj_sock_msg_flag.
+ *
+ * @return		PJ_SUCCESS or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd,
+				  void *buf,
+				  pj_ssize_t *len,
+				  unsigned flags);
+
+/**
+ * Receives data stream or message coming to the specified socket.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param buf		The buffer to receive the data or message.
+ * @param len		On input, the length of the buffer. On return,
+ *			contains the length of data received.
+ * @param flags		Bitmask combination of #pj_sock_msg_flag.
+ * @param from		If not NULL, it will be filled with the source
+ *			address of the connection.
+ * @param fromlen	Initially contains the length of from address,
+ *			and upon return will be filled with the actual
+ *			length of the address.
+ *
+ * @return		PJ_SUCCESS or the error code.
+ */
+PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
+				      void *buf,
+				      pj_ssize_t *len,
+				      unsigned flags,
+				      pj_sockaddr_t *from,
+				      int *fromlen);
+
+/**
+ * Transmit data to the socket.
+ *
+ * @param sockfd	Socket descriptor.
+ * @param buf		Buffer containing data to be sent.
+ * @param len		On input, the length of the data in the buffer.
+ *			Upon return, it will be filled with the length
+ *			of data sent.
+ * @param flags		Bitmask combination of #pj_sock_msg_flag.
+ *
+ * @return		PJ_SUCCESS or the status code.
+ */
+PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd,
+				  const void *buf,
+				  pj_ssize_t *len,
+				  unsigned flags);
+
+/**
+ * Transmit data to the socket to the specified address.
+ *
+ * @param sockfd	Socket descriptor.
+ * @param buf		Buffer containing data to be sent.
+ * @param len		On input, the length of the data in the buffer.
+ *			Upon return, it will be filled with the length
+ *			of data sent.
+ * @param flags		Bitmask combination of #pj_sock_msg_flag.
+ * @param to		The address to send.
+ * @param tolen		The length of the address in bytes.
+ *
+ * @return		The length of data successfully sent.
+ */
+PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd,
+				    const void *buf,
+				    pj_ssize_t *len,
+				    unsigned flags,
+				    const pj_sockaddr_t *to,
+				    int tolen);
+
+#if PJ_HAS_TCP
+/**
+ * The shutdown call causes all or part of a full-duplex connection on the
+ * socket associated with sockfd to be shut down.
+ *
+ * @param sockfd	The socket descriptor.
+ * @param how		If how is PJ_SHUT_RD, further receptions will be 
+ *			disallowed. If how is PJ_SHUT_WR, further transmissions
+ *			will be disallowed. If how is PJ_SHUT_RDWR, further 
+ *			receptions andtransmissions will be disallowed.
+ *
+ * @return		Zero on success.
+ */
+PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
+				       int how);
+#endif
+
+/**
+ * @}
+ */
+
+
+PJ_END_DECL
+
+#endif	/* __PJ_SOCK_H__ */
+
diff --git a/pjlib/include/pj/sock_select.h b/pjlib/include/pj/sock_select.h
index 4a97438..0b94de8 100644
--- a/pjlib/include/pj/sock_select.h
+++ b/pjlib/include/pj/sock_select.h
@@ -1,136 +1,136 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_SELECT_H__

-#define __PJ_SELECT_H__

-

-/**

- * @file sock_select.h

- * @brief Socket select().

- */

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL 

-

-/**

- * @defgroup PJ_SOCK_SELECT Socket select() API.

- * @ingroup PJ_IO

- * @{

- * This module provides portable abstraction for \a select() like API.

- * The abstraction is needed so that it can utilize various event

- * dispatching mechanisms that are available across platforms.

- *

- * The API is very similar to normal \a select() usage. 

- *

- * \section pj_sock_select_examples_sec Examples

- *

- * For some examples on how to use the select API, please see:

- *

- *  - \ref page_pjlib_select_test

- */

-

-/**

- * Portable structure declarations for pj_fd_set.

- * The implementation of pj_sock_select() does not use this structure 

- * per-se, but instead it will use the native fd_set structure. However,

- * we must make sure that the size of pj_fd_set_t can accomodate the

- * native fd_set structure.

- */

-typedef struct pj_fd_set_t

-{

-    pj_sock_t	data[FD_SETSIZE + 4];   /**< Opaque buffer for fd_set */

-} pj_fd_set_t;

-

-

-/**

- * Initialize the descriptor set pointed to by fdsetp to the null set.

- *

- * @param fdsetp    The descriptor set.

- */

-PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp);

-

-

-/**

- * Add the file descriptor fd to the set pointed to by fdsetp. 

- * If the file descriptor fd is already in this set, there shall be no effect

- * on the set, nor will an error be returned.

- *

- * @param fd	    The socket descriptor.

- * @param fdsetp    The descriptor set.

- */

-PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp);

-

-/**

- * Remove the file descriptor fd from the set pointed to by fdsetp. 

- * If fd is not a member of this set, there shall be no effect on the set, 

- * nor will an error be returned.

- *

- * @param fd	    The socket descriptor.

- * @param fdsetp    The descriptor set.

- */

-PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp);

-

-

-/**

- * Evaluate to non-zero if the file descriptor fd is a member of the set 

- * pointed to by fdsetp, and shall evaluate to zero otherwise.

- *

- * @param fd	    The socket descriptor.

- * @param fdsetp    The descriptor set.

- *

- * @return	    Nonzero if fd is member of the descriptor set.

- */

-PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp);

-

-

-/**

- * This function wait for a number of file  descriptors to change status.

- * The behaviour is the same as select() function call which appear in

- * standard BSD socket libraries.

- *

- * @param n	    On Unices, this specifies the highest-numbered

- *		    descriptor in any of the three set, plus 1. On Windows,

- *		    the value is ignored.

- * @param readfds   Optional pointer to a set of sockets to be checked for 

- *		    readability.

- * @param writefds  Optional pointer to a set of sockets to be checked for 

- *		    writability.

- * @param exceptfds Optional pointer to a set of sockets to be checked for 

- *		    errors.

- * @param timeout   Maximum time for select to wait, or null for blocking 

- *		    operations.

- *

- * @return	    The total number of socket handles that are ready, or

- *		    zero if the time limit expired, or -1 if an error occurred.

- */

-PJ_DECL(int) pj_sock_select( int n, 

-			     pj_fd_set_t *readfds, 

-			     pj_fd_set_t *writefds,

-			     pj_fd_set_t *exceptfds, 

-			     const pj_time_val *timeout);

-

-

-/**

- * @}

- */

-

-

-PJ_END_DECL

-

-#endif	/* __PJ_SELECT_H__ */

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_SELECT_H__
+#define __PJ_SELECT_H__
+
+/**
+ * @file sock_select.h
+ * @brief Socket select().
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL 
+
+/**
+ * @defgroup PJ_SOCK_SELECT Socket select() API.
+ * @ingroup PJ_IO
+ * @{
+ * This module provides portable abstraction for \a select() like API.
+ * The abstraction is needed so that it can utilize various event
+ * dispatching mechanisms that are available across platforms.
+ *
+ * The API is very similar to normal \a select() usage. 
+ *
+ * \section pj_sock_select_examples_sec Examples
+ *
+ * For some examples on how to use the select API, please see:
+ *
+ *  - \ref page_pjlib_select_test
+ */
+
+/**
+ * Portable structure declarations for pj_fd_set.
+ * The implementation of pj_sock_select() does not use this structure 
+ * per-se, but instead it will use the native fd_set structure. However,
+ * we must make sure that the size of pj_fd_set_t can accomodate the
+ * native fd_set structure.
+ */
+typedef struct pj_fd_set_t
+{
+    pj_sock_t	data[FD_SETSIZE + 4];   /**< Opaque buffer for fd_set */
+} pj_fd_set_t;
+
+
+/**
+ * Initialize the descriptor set pointed to by fdsetp to the null set.
+ *
+ * @param fdsetp    The descriptor set.
+ */
+PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp);
+
+
+/**
+ * Add the file descriptor fd to the set pointed to by fdsetp. 
+ * If the file descriptor fd is already in this set, there shall be no effect
+ * on the set, nor will an error be returned.
+ *
+ * @param fd	    The socket descriptor.
+ * @param fdsetp    The descriptor set.
+ */
+PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp);
+
+/**
+ * Remove the file descriptor fd from the set pointed to by fdsetp. 
+ * If fd is not a member of this set, there shall be no effect on the set, 
+ * nor will an error be returned.
+ *
+ * @param fd	    The socket descriptor.
+ * @param fdsetp    The descriptor set.
+ */
+PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp);
+
+
+/**
+ * Evaluate to non-zero if the file descriptor fd is a member of the set 
+ * pointed to by fdsetp, and shall evaluate to zero otherwise.
+ *
+ * @param fd	    The socket descriptor.
+ * @param fdsetp    The descriptor set.
+ *
+ * @return	    Nonzero if fd is member of the descriptor set.
+ */
+PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp);
+
+
+/**
+ * This function wait for a number of file  descriptors to change status.
+ * The behaviour is the same as select() function call which appear in
+ * standard BSD socket libraries.
+ *
+ * @param n	    On Unices, this specifies the highest-numbered
+ *		    descriptor in any of the three set, plus 1. On Windows,
+ *		    the value is ignored.
+ * @param readfds   Optional pointer to a set of sockets to be checked for 
+ *		    readability.
+ * @param writefds  Optional pointer to a set of sockets to be checked for 
+ *		    writability.
+ * @param exceptfds Optional pointer to a set of sockets to be checked for 
+ *		    errors.
+ * @param timeout   Maximum time for select to wait, or null for blocking 
+ *		    operations.
+ *
+ * @return	    The total number of socket handles that are ready, or
+ *		    zero if the time limit expired, or -1 if an error occurred.
+ */
+PJ_DECL(int) pj_sock_select( int n, 
+			     pj_fd_set_t *readfds, 
+			     pj_fd_set_t *writefds,
+			     pj_fd_set_t *exceptfds, 
+			     const pj_time_val *timeout);
+
+
+/**
+ * @}
+ */
+
+
+PJ_END_DECL
+
+#endif	/* __PJ_SELECT_H__ */
diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h
index 8edcba8..c7310b5 100644
--- a/pjlib/include/pj/string.h
+++ b/pjlib/include/pj/string.h
@@ -1,561 +1,561 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_STRING_H__

-#define __PJ_STRING_H__

-

-/**

- * @file string.h

- * @brief PJLIB String Operations.

- */

-

-#include <pj/types.h>

-#include <pj/compat/string.h>

-#include <pj/compat/sprintf.h>

-#include <pj/compat/vsprintf.h>

-

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_PSTR String Operations

- * @ingroup PJ_DS

- * @{

- * This module provides string manipulation API.

- *

- * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated!

- *

- * That is the first information that developers need to know. Instead

- * of using normal C string, strings in PJLIB are represented as

- * pj_str_t structure below:

- *

- * <pre>

- *   typedef struct pj_str_t

- *   {

- *       char      *ptr;

- *       pj_size_t  slen;

- *   } pj_str_t;

- * </pre>

- *

- * There are some advantages of using this approach:

- *  - the string can point to arbitrary location in memory even

- *    if the string in that location is not null terminated. This is

- *    most usefull for text parsing, where the parsed text can just

- *    point to the original text in the input. If we use C string,

- *    then we will have to copy the text portion from the input

- *    to a string variable.

- *  - because the length of the string is known, string copy operation

- *    can be made more efficient.

- *

- * Most of APIs in PJLIB that expect or return string will represent

- * the string as pj_str_t instead of normal C string.

- *

- * \section pj_pstr_examples_sec Examples

- *

- * For some examples, please see:

- *  - @ref page_pjlib_string_test

- */

-

-/**

- * Create string initializer from a normal C string.

- *

- * @param str	Null terminated string to be stored.

- *

- * @return	pj_str_t.

- */

-PJ_IDECL(pj_str_t) pj_str(char *str);

-

-/**

- * Create constant string from normal C string.

- *

- * @param str	The string to be initialized.

- * @param s	Null terminated string.

- *

- * @return	pj_str_t.

- */

-PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s)

-{

-    str->ptr = (char*)s;

-    str->slen = s ? strlen(s) : 0;

-    return str;

-}

-

-/**

- * Set the pointer and length to the specified value.

- *

- * @param str	    the string.

- * @param ptr	    pointer to set.

- * @param length    length to set.

- *

- * @return the string.

- */

-PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length)

-{

-    str->ptr = ptr;

-    str->slen = length;

-    return str;

-}

-

-/**

- * Set the pointer and length of the string to the source string, which

- * must be NULL terminated.

- *

- * @param str	    the string.

- * @param src	    pointer to set.

- *

- * @return the string.

- */

-PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src)

-{

-    str->ptr = src;

-    str->slen = src ? strlen(src) : 0;

-    return str;

-}

-

-/**

- * Set the pointer and the length of the string.

- *

- * @param str	    The target string.

- * @param begin	    The start of the string.

- * @param end	    The end of the string.

- *

- * @return the target string.

- */

-PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end )

-{

-    str->ptr = begin;

-    str->slen = end-begin;

-    return str;

-}

-

-/**

- * Assign string.

- *

- * @param dst	    The target string.

- * @param src	    The source string.

- *

- * @return the target string.

- */

-PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src );

-

-/**

- * Copy string contents.

- *

- * @param dst	    The target string.

- * @param src	    The source string.

- *

- * @return the target string.

- */

-PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src);

-

-/**

- * Copy string contents.

- *

- * @param dst	    The target string.

- * @param src	    The source string.

- *

- * @return the target string.

- */

-PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src);

-

-/**

- * Copy source string to destination up to the specified max length.

- *

- * @param dst	    The target string.

- * @param src	    The source string.

- * @param max	    Maximum characters to copy.

- *

- * @return the target string.

- */

-PJ_IDECL(pj_str_t*) pj_strncpy(pj_str_t *dst, const pj_str_t *src, 

-			       pj_ssize_t max);

-

-/**

- * Copy source string to destination up to the specified max length,

- * and NULL terminate the destination. If source string length is

- * greater than or equal to max, then max-1 will be copied.

- *

- * @param dst	    The target string.

- * @param src	    The source string.

- * @param max	    Maximum characters to copy.

- *

- * @return the target string.

- */

-PJ_IDECL(pj_str_t*) pj_strncpy_with_null(pj_str_t *dst, const pj_str_t *src,

-					 pj_ssize_t max);

-

-/**

- * Duplicate string.

- *

- * @param pool	    The pool.

- * @param dst	    The string result.

- * @param src	    The string to duplicate.

- *

- * @return the string result.

- */

-PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool,

-			      pj_str_t *dst,

-			      const pj_str_t *src);

-

-/**

- * Duplicate string and NULL terminate the destination string.

- *

- * @param pool

- * @param dst

- * @param src

- */

-PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool,

-					pj_str_t *dst,

-					const pj_str_t *src);

-

-/**

- * Duplicate string.

- *

- * @param pool	    The pool.

- * @param dst	    The string result.

- * @param src	    The string to duplicate.

- *

- * @return the string result.

- */

-PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool,

-			       pj_str_t *dst,

-			       const char *src);

-

-/**

- * Duplicate string.

- *

- * @param pool	    The pool.

- * @param src	    The string to duplicate.

- *

- * @return the string result.

- */

-PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src);

-

-/**

- * Return the length of the string.

- *

- * @param str	    The string.

- *

- * @return the length of the string.

- */

-PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str )

-{

-    return str->slen;

-}

-

-/**

- * Return the pointer to the string data.

- *

- * @param str	    The string.

- *

- * @return the pointer to the string buffer.

- */

-PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str )

-{

-    return str->ptr;

-}

-

-/**

- * Compare strings. 

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2);

-

-/**

- * Compare strings.

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 );

-

-/**

- * Compare strings. 

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- * @param len	    The maximum number of characters to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 

-			  pj_size_t len);

-

-/**

- * Compare strings. 

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- * @param len	    The maximum number of characters to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 

-			   pj_size_t len);

-

-/**

- * Perform lowercase comparison to the strings.

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2);

-

-/**

- * Perform lowercase comparison to the strings.

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2);

-

-/**

- * Perform lowercase comparison to the strings.

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- * @param len	    The maximum number of characters to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 

-			   pj_size_t len);

-

-/**

- * Perform lowercase comparison to the strings.

- *

- * @param str1	    The string to compare.

- * @param str2	    The string to compare.

- * @param len	    The maximum number of characters to compare.

- *

- * @return 

- *	- < 0 if str1 is less than str2

- *      - 0   if str1 is identical to str2

- *      - > 0 if str1 is greater than str2

- */

-PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 

-			    pj_size_t len);

-

-/**

- * Concatenate strings.

- *

- * @param dst	    The destination string.

- * @param src	    The source string.

- */

-PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src);

-

-/**

- * Finds a character in a string.

- *

- * @param str	    The string.

- * @param chr	    The character to find.

- *

- * @return the pointer to first character found, or NULL.

- */

-PJ_INLINE(char*) pj_strchr( const pj_str_t *str, int chr)

-{

-    return (char*) memchr(str->ptr, chr, str->slen);

-}

-

-/**

- * Remove (trim) leading whitespaces from the string.

- *

- * @param str	    The string.

- *

- * @return the string.

- */

-PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str );

-

-/**

- * Remove (trim) the trailing whitespaces from the string.

- *

- * @param str	    The string.

- *

- * @return the string.

- */

-PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str );

-

-/**

- * Remove (trim) leading and trailing whitespaces from the string.

- *

- * @param str	    The string.

- *

- * @return the string.

- */

-PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str );

-

-/**

- * Initialize the buffer with some random string.

- *

- * @param str	    the string to store the result.

- * @param length    the length of the random string to generate.

- *

- * @return the string.

- */

-PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length);

-

-/**

- * Convert string to unsigned integer.

- *

- * @param str	the string.

- *

- * @return the unsigned integer.

- */

-PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str);

-

-/**

- * Utility to convert unsigned integer to string. Note that the

- * string will be NULL terminated.

- *

- * @param val	    the unsigned integer value.

- * @param buf	    the buffer

- *

- * @return the number of characters written

- */

-PJ_DECL(int) pj_utoa(unsigned long val, char *buf);

-

-/**

- * Convert unsigned integer to string with minimum digits. Note that the

- * string will be NULL terminated.

- *

- * @param val	    The unsigned integer value.

- * @param buf	    The buffer.

- * @param min_dig   Minimum digits to be printed, or zero to specify no

- *		    minimum digit.

- * @param pad	    The padding character to be put in front of the string

- *		    when the digits is less than minimum.

- *

- * @return the number of characters written.

- */

-PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad);

-

-/**

- * Fill the memory location with value.

- *

- * @param dst	    The destination buffer.

- * @param c	    Character to set.

- * @param size	    The number of characters.

- *

- * @return the value of dst.

- */

-PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size)

-{

-    return memset(dst, c, size);

-}

-

-/**

- * Copy buffer.

- *

- * @param dst	    The destination buffer.

- * @param src	    The source buffer.

- * @param size	    The size to copy.

- *

- * @return the destination buffer.

- */

-PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size)

-{

-    return memcpy(dst, src, size);

-}

-

-/**

- * Move memory.

- *

- * @param dst	    The destination buffer.

- * @param src	    The source buffer.

- * @param size	    The size to copy.

- *

- * @return the destination buffer.

- */

-PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size)

-{

-    return memmove(dst, src, size);

-}

-

-/**

- * Compare buffers.

- *

- * @param buf1	    The first buffer.

- * @param buf2	    The second buffer.

- * @param size	    The size to compare.

- *

- * @return negative, zero, or positive value.

- */

-PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size)

-{

-    return memcmp(buf1, buf2, size);

-}

-

-/**

- * Find character in the buffer.

- *

- * @param buf	    The buffer.

- * @param c	    The character to find.

- * @param size	    The size to check.

- *

- * @return the pointer to location where the character is found, or NULL if

- *         not found.

- */

-PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size)

-{

-    return memchr(buf, c, size);

-}

-

-

-/**

- * @}

- */

-

-#if PJ_FUNCTIONS_ARE_INLINED

-#  include <pj/string_i.h>

-#endif

-

-PJ_END_DECL

-

-#endif	/* __PJ_STRING_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_STRING_H__
+#define __PJ_STRING_H__
+
+/**
+ * @file string.h
+ * @brief PJLIB String Operations.
+ */
+
+#include <pj/types.h>
+#include <pj/compat/string.h>
+#include <pj/compat/sprintf.h>
+#include <pj/compat/vsprintf.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_PSTR String Operations
+ * @ingroup PJ_DS
+ * @{
+ * This module provides string manipulation API.
+ *
+ * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated!
+ *
+ * That is the first information that developers need to know. Instead
+ * of using normal C string, strings in PJLIB are represented as
+ * pj_str_t structure below:
+ *
+ * <pre>
+ *   typedef struct pj_str_t
+ *   {
+ *       char      *ptr;
+ *       pj_size_t  slen;
+ *   } pj_str_t;
+ * </pre>
+ *
+ * There are some advantages of using this approach:
+ *  - the string can point to arbitrary location in memory even
+ *    if the string in that location is not null terminated. This is
+ *    most usefull for text parsing, where the parsed text can just
+ *    point to the original text in the input. If we use C string,
+ *    then we will have to copy the text portion from the input
+ *    to a string variable.
+ *  - because the length of the string is known, string copy operation
+ *    can be made more efficient.
+ *
+ * Most of APIs in PJLIB that expect or return string will represent
+ * the string as pj_str_t instead of normal C string.
+ *
+ * \section pj_pstr_examples_sec Examples
+ *
+ * For some examples, please see:
+ *  - @ref page_pjlib_string_test
+ */
+
+/**
+ * Create string initializer from a normal C string.
+ *
+ * @param str	Null terminated string to be stored.
+ *
+ * @return	pj_str_t.
+ */
+PJ_IDECL(pj_str_t) pj_str(char *str);
+
+/**
+ * Create constant string from normal C string.
+ *
+ * @param str	The string to be initialized.
+ * @param s	Null terminated string.
+ *
+ * @return	pj_str_t.
+ */
+PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s)
+{
+    str->ptr = (char*)s;
+    str->slen = s ? strlen(s) : 0;
+    return str;
+}
+
+/**
+ * Set the pointer and length to the specified value.
+ *
+ * @param str	    the string.
+ * @param ptr	    pointer to set.
+ * @param length    length to set.
+ *
+ * @return the string.
+ */
+PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length)
+{
+    str->ptr = ptr;
+    str->slen = length;
+    return str;
+}
+
+/**
+ * Set the pointer and length of the string to the source string, which
+ * must be NULL terminated.
+ *
+ * @param str	    the string.
+ * @param src	    pointer to set.
+ *
+ * @return the string.
+ */
+PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src)
+{
+    str->ptr = src;
+    str->slen = src ? strlen(src) : 0;
+    return str;
+}
+
+/**
+ * Set the pointer and the length of the string.
+ *
+ * @param str	    The target string.
+ * @param begin	    The start of the string.
+ * @param end	    The end of the string.
+ *
+ * @return the target string.
+ */
+PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end )
+{
+    str->ptr = begin;
+    str->slen = end-begin;
+    return str;
+}
+
+/**
+ * Assign string.
+ *
+ * @param dst	    The target string.
+ * @param src	    The source string.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src );
+
+/**
+ * Copy string contents.
+ *
+ * @param dst	    The target string.
+ * @param src	    The source string.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src);
+
+/**
+ * Copy string contents.
+ *
+ * @param dst	    The target string.
+ * @param src	    The source string.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src);
+
+/**
+ * Copy source string to destination up to the specified max length.
+ *
+ * @param dst	    The target string.
+ * @param src	    The source string.
+ * @param max	    Maximum characters to copy.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strncpy(pj_str_t *dst, const pj_str_t *src, 
+			       pj_ssize_t max);
+
+/**
+ * Copy source string to destination up to the specified max length,
+ * and NULL terminate the destination. If source string length is
+ * greater than or equal to max, then max-1 will be copied.
+ *
+ * @param dst	    The target string.
+ * @param src	    The source string.
+ * @param max	    Maximum characters to copy.
+ *
+ * @return the target string.
+ */
+PJ_IDECL(pj_str_t*) pj_strncpy_with_null(pj_str_t *dst, const pj_str_t *src,
+					 pj_ssize_t max);
+
+/**
+ * Duplicate string.
+ *
+ * @param pool	    The pool.
+ * @param dst	    The string result.
+ * @param src	    The string to duplicate.
+ *
+ * @return the string result.
+ */
+PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool,
+			      pj_str_t *dst,
+			      const pj_str_t *src);
+
+/**
+ * Duplicate string and NULL terminate the destination string.
+ *
+ * @param pool
+ * @param dst
+ * @param src
+ */
+PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool,
+					pj_str_t *dst,
+					const pj_str_t *src);
+
+/**
+ * Duplicate string.
+ *
+ * @param pool	    The pool.
+ * @param dst	    The string result.
+ * @param src	    The string to duplicate.
+ *
+ * @return the string result.
+ */
+PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool,
+			       pj_str_t *dst,
+			       const char *src);
+
+/**
+ * Duplicate string.
+ *
+ * @param pool	    The pool.
+ * @param src	    The string to duplicate.
+ *
+ * @return the string result.
+ */
+PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src);
+
+/**
+ * Return the length of the string.
+ *
+ * @param str	    The string.
+ *
+ * @return the length of the string.
+ */
+PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str )
+{
+    return str->slen;
+}
+
+/**
+ * Return the pointer to the string data.
+ *
+ * @param str	    The string.
+ *
+ * @return the pointer to the string buffer.
+ */
+PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str )
+{
+    return str->ptr;
+}
+
+/**
+ * Compare strings. 
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2);
+
+/**
+ * Compare strings.
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 );
+
+/**
+ * Compare strings. 
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ * @param len	    The maximum number of characters to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 
+			  pj_size_t len);
+
+/**
+ * Compare strings. 
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ * @param len	    The maximum number of characters to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 
+			   pj_size_t len);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ * @param len	    The maximum number of characters to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 
+			   pj_size_t len);
+
+/**
+ * Perform lowercase comparison to the strings.
+ *
+ * @param str1	    The string to compare.
+ * @param str2	    The string to compare.
+ * @param len	    The maximum number of characters to compare.
+ *
+ * @return 
+ *	- < 0 if str1 is less than str2
+ *      - 0   if str1 is identical to str2
+ *      - > 0 if str1 is greater than str2
+ */
+PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 
+			    pj_size_t len);
+
+/**
+ * Concatenate strings.
+ *
+ * @param dst	    The destination string.
+ * @param src	    The source string.
+ */
+PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src);
+
+/**
+ * Finds a character in a string.
+ *
+ * @param str	    The string.
+ * @param chr	    The character to find.
+ *
+ * @return the pointer to first character found, or NULL.
+ */
+PJ_INLINE(char*) pj_strchr( const pj_str_t *str, int chr)
+{
+    return (char*) memchr(str->ptr, chr, str->slen);
+}
+
+/**
+ * Remove (trim) leading whitespaces from the string.
+ *
+ * @param str	    The string.
+ *
+ * @return the string.
+ */
+PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str );
+
+/**
+ * Remove (trim) the trailing whitespaces from the string.
+ *
+ * @param str	    The string.
+ *
+ * @return the string.
+ */
+PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str );
+
+/**
+ * Remove (trim) leading and trailing whitespaces from the string.
+ *
+ * @param str	    The string.
+ *
+ * @return the string.
+ */
+PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str );
+
+/**
+ * Initialize the buffer with some random string.
+ *
+ * @param str	    the string to store the result.
+ * @param length    the length of the random string to generate.
+ *
+ * @return the string.
+ */
+PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length);
+
+/**
+ * Convert string to unsigned integer.
+ *
+ * @param str	the string.
+ *
+ * @return the unsigned integer.
+ */
+PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str);
+
+/**
+ * Utility to convert unsigned integer to string. Note that the
+ * string will be NULL terminated.
+ *
+ * @param val	    the unsigned integer value.
+ * @param buf	    the buffer
+ *
+ * @return the number of characters written
+ */
+PJ_DECL(int) pj_utoa(unsigned long val, char *buf);
+
+/**
+ * Convert unsigned integer to string with minimum digits. Note that the
+ * string will be NULL terminated.
+ *
+ * @param val	    The unsigned integer value.
+ * @param buf	    The buffer.
+ * @param min_dig   Minimum digits to be printed, or zero to specify no
+ *		    minimum digit.
+ * @param pad	    The padding character to be put in front of the string
+ *		    when the digits is less than minimum.
+ *
+ * @return the number of characters written.
+ */
+PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad);
+
+/**
+ * Fill the memory location with value.
+ *
+ * @param dst	    The destination buffer.
+ * @param c	    Character to set.
+ * @param size	    The number of characters.
+ *
+ * @return the value of dst.
+ */
+PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size)
+{
+    return memset(dst, c, size);
+}
+
+/**
+ * Copy buffer.
+ *
+ * @param dst	    The destination buffer.
+ * @param src	    The source buffer.
+ * @param size	    The size to copy.
+ *
+ * @return the destination buffer.
+ */
+PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size)
+{
+    return memcpy(dst, src, size);
+}
+
+/**
+ * Move memory.
+ *
+ * @param dst	    The destination buffer.
+ * @param src	    The source buffer.
+ * @param size	    The size to copy.
+ *
+ * @return the destination buffer.
+ */
+PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size)
+{
+    return memmove(dst, src, size);
+}
+
+/**
+ * Compare buffers.
+ *
+ * @param buf1	    The first buffer.
+ * @param buf2	    The second buffer.
+ * @param size	    The size to compare.
+ *
+ * @return negative, zero, or positive value.
+ */
+PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size)
+{
+    return memcmp(buf1, buf2, size);
+}
+
+/**
+ * Find character in the buffer.
+ *
+ * @param buf	    The buffer.
+ * @param c	    The character to find.
+ * @param size	    The size to check.
+ *
+ * @return the pointer to location where the character is found, or NULL if
+ *         not found.
+ */
+PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size)
+{
+    return memchr(buf, c, size);
+}
+
+
+/**
+ * @}
+ */
+
+#if PJ_FUNCTIONS_ARE_INLINED
+#  include <pj/string_i.h>
+#endif
+
+PJ_END_DECL
+
+#endif	/* __PJ_STRING_H__ */
+
diff --git a/pjlib/include/pj/string_i.h b/pjlib/include/pj/string_i.h
index 7163b13..3fdcd2c 100644
--- a/pjlib/include/pj/string_i.h
+++ b/pjlib/include/pj/string_i.h
@@ -1,207 +1,207 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 

- */

-

-PJ_IDEF(pj_str_t) pj_str(char *str)

-{

-    pj_str_t dst;

-    dst.ptr = str;

-    dst.slen = str ? pj_native_strlen(str) : 0;

-    return dst;

-}

-

-PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool,

-			      pj_str_t *dst,

-			      const pj_str_t *src)

-{

-    if (src->slen) {

-	dst->ptr = (char*)pj_pool_alloc(pool, src->slen);

-	pj_memcpy(dst->ptr, src->ptr, src->slen);

-    }

-    dst->slen = src->slen;

-    return dst;

-}

-

-PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool,

-					pj_str_t *dst,

-					const pj_str_t *src)

-{

-    if (src->slen) {

-	dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1);

-	pj_memcpy(dst->ptr, src->ptr, src->slen);

-    } else {

-	dst->ptr = (char*)pj_pool_alloc(pool, 1);

-    }

-    dst->slen = src->slen;

-    dst->ptr[dst->slen] = '\0';

-    return dst;

-}

-

-PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool,

-			      pj_str_t *dst,

-			      const char *src)

-{

-    dst->slen = src ? pj_native_strlen(src) : 0;

-    if (dst->slen) {

-	dst->ptr = (char*)pj_pool_alloc(pool, dst->slen);

-	pj_memcpy(dst->ptr, src, dst->slen);

-    } else {

-	dst->ptr = NULL;

-    }

-    return dst;

-}

-

-

-PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src)

-{

-    pj_str_t temp;

-    pj_strdup2(pool, &temp, src);

-    return temp;

-}

-

-PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src )

-{

-    dst->ptr = src->ptr;

-    dst->slen = src->slen;

-    return dst;

-}

-

-PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src)

-{

-    dst->slen = src->slen;

-    if (src->slen > 0)

-	pj_memcpy(dst->ptr, src->ptr, src->slen);

-    return dst;

-}

-

-PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src)

-{

-    dst->slen = src ? pj_native_strlen(src) : 0;

-    if (dst->slen > 0)

-	pj_memcpy(dst->ptr, src, dst->slen);

-    return dst;

-}

-

-PJ_IDEF(pj_str_t*) pj_strncpy( pj_str_t *dst, const pj_str_t *src, 

-			       pj_ssize_t max)

-{

-    if (max > src->slen) max = src->slen;

-    pj_memcpy(dst->ptr, src->ptr, max);

-    dst->slen = max;

-    return dst;

-}

-

-PJ_IDEF(pj_str_t*) pj_strncpy_with_null( pj_str_t *dst, const pj_str_t *src,

-					 pj_ssize_t max)

-{

-    if (max <= src->slen)

-	max = max-1;

-    else

-	max = src->slen;

-

-    pj_memcpy(dst->ptr, src->ptr, max);

-    dst->ptr[max] = '\0';

-    dst->slen = max;

-    return dst;

-}

-

-

-PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2)

-{

-    pj_ssize_t diff;

-

-    diff = str1->slen - str2->slen;

-    if (diff) {

-	return (int)diff;

-    } else if (str1->ptr && str1->slen) {

-	return pj_native_strncmp(str1->ptr, str2->ptr, str1->slen);

-    } else {

-	return 0;

-    }

-}

-

-PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 

-			 pj_size_t len)

-{

-    return (str1->ptr && str2->ptr) ? 

-	    pj_native_strncmp(str1->ptr, str2->ptr, len) :

-	    (str1->ptr == str2->ptr ? 0 : 1);

-}

-

-PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 

-			  pj_size_t len)

-{

-    return (str1->ptr && str2) ? pj_native_strncmp(str1->ptr, str2, len) :

-	   (str1->ptr==str2 ? 0 : 1);

-}

-

-PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 )

-{

-    return pj_strncmp2( str1, str2, str1->slen);

-}

-

-PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2)

-{

-    pj_ssize_t diff;

-

-    diff = str1->slen - str2->slen;

-    if (diff) {

-	return (int)diff;

-    } else {

-	return pj_native_strnicmp(str1->ptr, str2->ptr, str1->slen);

-    }

-}

-

-PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2)

-{

-    return (str1->ptr && str2) ? 

-	    pj_native_strnicmp(str1->ptr, str2, str1->slen) :

-	    (str1->ptr==str2 ? 0 : 1);

-}

-

-PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 

-			  pj_size_t len)

-{

-    return (str1->ptr && str2->ptr) ? 

-	    pj_native_strnicmp(str1->ptr, str2->ptr, len) :

-	    (str1->ptr == str2->ptr ? 0 : 1);

-}

-

-PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 

-			   pj_size_t len)

-{

-    return (str1->ptr && str2) ? 

-	    pj_native_strnicmp(str1->ptr, str2, len) :

-	    (str1->ptr == str2 ? 0 : 1);

-}

-

-PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src)

-{

-    if (src->slen) {

-	pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen);

-	dst->slen += src->slen;

-    }

-}

-

-PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str )

-{

-    pj_strltrim(str);

-    pj_strrtrim(str);

-    return str;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 
+ */
+
+PJ_IDEF(pj_str_t) pj_str(char *str)
+{
+    pj_str_t dst;
+    dst.ptr = str;
+    dst.slen = str ? pj_native_strlen(str) : 0;
+    return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool,
+			      pj_str_t *dst,
+			      const pj_str_t *src)
+{
+    if (src->slen) {
+	dst->ptr = (char*)pj_pool_alloc(pool, src->slen);
+	pj_memcpy(dst->ptr, src->ptr, src->slen);
+    }
+    dst->slen = src->slen;
+    return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool,
+					pj_str_t *dst,
+					const pj_str_t *src)
+{
+    if (src->slen) {
+	dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1);
+	pj_memcpy(dst->ptr, src->ptr, src->slen);
+    } else {
+	dst->ptr = (char*)pj_pool_alloc(pool, 1);
+    }
+    dst->slen = src->slen;
+    dst->ptr[dst->slen] = '\0';
+    return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool,
+			      pj_str_t *dst,
+			      const char *src)
+{
+    dst->slen = src ? pj_native_strlen(src) : 0;
+    if (dst->slen) {
+	dst->ptr = (char*)pj_pool_alloc(pool, dst->slen);
+	pj_memcpy(dst->ptr, src, dst->slen);
+    } else {
+	dst->ptr = NULL;
+    }
+    return dst;
+}
+
+
+PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src)
+{
+    pj_str_t temp;
+    pj_strdup2(pool, &temp, src);
+    return temp;
+}
+
+PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src )
+{
+    dst->ptr = src->ptr;
+    dst->slen = src->slen;
+    return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src)
+{
+    dst->slen = src->slen;
+    if (src->slen > 0)
+	pj_memcpy(dst->ptr, src->ptr, src->slen);
+    return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src)
+{
+    dst->slen = src ? pj_native_strlen(src) : 0;
+    if (dst->slen > 0)
+	pj_memcpy(dst->ptr, src, dst->slen);
+    return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strncpy( pj_str_t *dst, const pj_str_t *src, 
+			       pj_ssize_t max)
+{
+    if (max > src->slen) max = src->slen;
+    pj_memcpy(dst->ptr, src->ptr, max);
+    dst->slen = max;
+    return dst;
+}
+
+PJ_IDEF(pj_str_t*) pj_strncpy_with_null( pj_str_t *dst, const pj_str_t *src,
+					 pj_ssize_t max)
+{
+    if (max <= src->slen)
+	max = max-1;
+    else
+	max = src->slen;
+
+    pj_memcpy(dst->ptr, src->ptr, max);
+    dst->ptr[max] = '\0';
+    dst->slen = max;
+    return dst;
+}
+
+
+PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2)
+{
+    pj_ssize_t diff;
+
+    diff = str1->slen - str2->slen;
+    if (diff) {
+	return (int)diff;
+    } else if (str1->ptr && str1->slen) {
+	return pj_native_strncmp(str1->ptr, str2->ptr, str1->slen);
+    } else {
+	return 0;
+    }
+}
+
+PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 
+			 pj_size_t len)
+{
+    return (str1->ptr && str2->ptr) ? 
+	    pj_native_strncmp(str1->ptr, str2->ptr, len) :
+	    (str1->ptr == str2->ptr ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 
+			  pj_size_t len)
+{
+    return (str1->ptr && str2) ? pj_native_strncmp(str1->ptr, str2, len) :
+	   (str1->ptr==str2 ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 )
+{
+    return pj_strncmp2( str1, str2, str1->slen);
+}
+
+PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2)
+{
+    pj_ssize_t diff;
+
+    diff = str1->slen - str2->slen;
+    if (diff) {
+	return (int)diff;
+    } else {
+	return pj_native_strnicmp(str1->ptr, str2->ptr, str1->slen);
+    }
+}
+
+PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2)
+{
+    return (str1->ptr && str2) ? 
+	    pj_native_strnicmp(str1->ptr, str2, str1->slen) :
+	    (str1->ptr==str2 ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 
+			  pj_size_t len)
+{
+    return (str1->ptr && str2->ptr) ? 
+	    pj_native_strnicmp(str1->ptr, str2->ptr, len) :
+	    (str1->ptr == str2->ptr ? 0 : 1);
+}
+
+PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 
+			   pj_size_t len)
+{
+    return (str1->ptr && str2) ? 
+	    pj_native_strnicmp(str1->ptr, str2, len) :
+	    (str1->ptr == str2 ? 0 : 1);
+}
+
+PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src)
+{
+    if (src->slen) {
+	pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen);
+	dst->slen += src->slen;
+    }
+}
+
+PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str )
+{
+    pj_strltrim(str);
+    pj_strrtrim(str);
+    return str;
+}
+
diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h
index eac6ba5..bcc4bb9 100644
--- a/pjlib/include/pj/timer.h
+++ b/pjlib/include/pj/timer.h
@@ -1,265 +1,265 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_TIMER_H__

-#define __PJ_TIMER_H__

-

-/**

- * @file timer.h

- * @brief Timer Heap

- */

-

-#include <pj/types.h>

-

-PJ_BEGIN_DECL

-

-/**

- * @defgroup PJ_TIMER Timer Heap Management.

- * @ingroup PJ_MISC

- * @brief

- * The timer scheduling implementation here is based on ACE library's 

- * ACE_Timer_Heap, with only little modification to suit our library's style

- * (I even left most of the comments in the original source).

- *

- * To quote the original quote in ACE_Timer_Heap_T class:

- *

- *      This implementation uses a heap-based callout queue of

- *      absolute times.  Therefore, in the average and worst case,

- *      scheduling, canceling, and expiring timers is O(log N) (where

- *      N is the total number of timers).  In addition, we can also

- *      preallocate as many \a ACE_Timer_Nodes as there are slots in

- *      the heap.  This allows us to completely remove the need for

- *      dynamic memory allocation, which is important for real-time

- *      systems.

- * @{

- *

- * \section pj_timer_examples_sec Examples

- *

- * For some examples on how to use the timer heap, please see the link below.

- *

- *  - \ref page_pjlib_timer_test

- */

-

-

-/**

- * The type for internal timer ID.

- */

-typedef int pj_timer_id_t;

-

-/** 

- * Forward declaration for pj_timer_entry. 

- */

-struct pj_timer_entry;

-

-/**

- * The type of callback function to be called by timer scheduler when a timer

- * has expired.

- *

- * @param timer_heap    The timer heap.

- * @param entry         Timer entry which timer's has expired.

- */

-typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap,

-				    struct pj_timer_entry *entry);

-

-

-/**

- * This structure represents an entry to the timer.

- */

-struct pj_timer_entry

-{

-    /** 

-     * User data to be associated with this entry. 

-     * Applications normally will put the instance of object that

-     * owns the timer entry in this field.

-     */

-    void *user_data;

-

-    /** 

-     * Arbitrary ID assigned by the user/owner of this entry. 

-     * Applications can use this ID to distinguish multiple

-     * timer entries that share the same callback and user_data.

-     */

-    int id;

-

-    /** 

-     * Callback to be called when the timer expires. 

-     */

-    pj_timer_heap_callback *cb;

-

-    /** 

-     * Internal unique timer ID, which is assigned by the timer heap. 

-     * Application should not touch this ID.

-     */

-    pj_timer_id_t _timer_id;

-

-    /** 

-     * The future time when the timer expires, which the value is updated

-     * by timer heap when the timer is scheduled.

-     */

-    pj_time_val _timer_value;

-};

-

-

-/**

- * Calculate memory size required to create a timer heap.

- *

- * @param count     Number of timer entries to be supported.

- * @return          Memory size requirement in bytes.

- */

-PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count);

-

-/**

- * Create a timer heap.

- *

- * @param pool      The pool where allocations in the timer heap will be 

- *                  allocated. The timer heap will dynamicly allocate 

- *                  more storate from the pool if the number of timer 

- *                  entries registered is more than the size originally 

- *                  requested when calling this function.

- * @param count     The maximum number of timer entries to be supported 

- *                  initially. If the application registers more entries 

- *                  during runtime, then the timer heap will resize.

- * @param ht        Pointer to receive the created timer heap.

- *

- * @return          PJ_SUCCESS, or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,

-					   pj_size_t count,

-                                           pj_timer_heap_t **ht);

-

-/**

- * Destroy the timer heap.

- *

- * @param ht        The timer heap.

- */

-PJ_DECL(void) pj_timer_heap_destroy( pj_timer_heap_t *ht );

-

-

-/**

- * Set lock object to be used by the timer heap. By default, the timer heap

- * uses dummy synchronization.

- *

- * @param ht        The timer heap.

- * @param lock      The lock object to be used for synchronization.

- * @param auto_del  If nonzero, the lock object will be destroyed when

- *                  the timer heap is destroyed.

- */

-PJ_DECL(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht,

-                                      pj_lock_t *lock,

-                                      pj_bool_t auto_del );

-

-/**

- * Set maximum number of timed out entries to process in a single poll.

- *

- * @param ht        The timer heap.

- * @param count     Number of entries.

- *

- * @return          The old number.

- */

-PJ_DECL(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,

-                                                           unsigned count );

-

-/**

- * Initialize a timer entry. Application should call this function at least

- * once before scheduling the entry to the timer heap, to properly initialize

- * the timer entry.

- *

- * @param entry     The timer entry to be initialized.

- * @param id        Arbitrary ID assigned by the user/owner of this entry.

- *                  Applications can use this ID to distinguish multiple

- *                  timer entries that share the same callback and user_data.

- * @param user_data User data to be associated with this entry. 

- *                  Applications normally will put the instance of object that

- *                  owns the timer entry in this field.

- * @param cb        Callback function to be called when the timer elapses.

- *

- * @return          The timer entry itself.

- */

-PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,

-                                              int id,

-                                              void *user_data,

-                                              pj_timer_heap_callback *cb );

-

-/**

- * Schedule a timer entry which will expire AFTER the specified delay.

- *

- * @param ht        The timer heap.

- * @param entry     The entry to be registered. 

- * @param delay     The interval to expire.

- * @return          PJ_SUCCESS, or the appropriate error code.

- */

-PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,

-					     pj_timer_entry *entry, 

-					     const pj_time_val *delay);

-

-/**

- * Cancel a previously registered timer.

- *

- * @param ht        The timer heap.

- * @param entry     The entry to be cancelled.

- * @return          The number of timer cancelled, which should be one if the

- *                  entry has really been registered, or zero if no timer was

- *                  cancelled.

- */

-PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,

-				   pj_timer_entry *entry);

-

-/**

- * Get the number of timer entries.

- *

- * @param ht        The timer heap.

- * @return          The number of timer entries.

- */

-PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht );

-

-/**

- * Get the earliest time registered in the timer heap. The timer heap

- * MUST have at least one timer being scheduled (application should use

- * #pj_timer_heap_count() before calling this function).

- *

- * @param ht        The timer heap.

- * @param timeval   The time deadline of the earliest timer entry.

- *

- * @return          PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled.

- */

-PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, 

-					          pj_time_val *timeval);

-

-/**

- * Poll the timer heap, check for expired timers and call the callback for

- * each of the expired timers.

- *

- * @param ht         The timer heap.

- * @param next_delay If this parameter is not NULL, it will be filled up with

- *		     the time delay until the next timer elapsed, or -1 in

- *		     the sec part if no entry exist.

- *

- * @return           The number of timers expired.

- */

-PJ_DECL(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 

-                                      pj_time_val *next_delay);

-

-/**

- * @}

- */

-

-PJ_END_DECL

-

-#endif	/* __PJ_TIMER_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_TIMER_H__
+#define __PJ_TIMER_H__
+
+/**
+ * @file timer.h
+ * @brief Timer Heap
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJ_TIMER Timer Heap Management.
+ * @ingroup PJ_MISC
+ * @brief
+ * The timer scheduling implementation here is based on ACE library's 
+ * ACE_Timer_Heap, with only little modification to suit our library's style
+ * (I even left most of the comments in the original source).
+ *
+ * To quote the original quote in ACE_Timer_Heap_T class:
+ *
+ *      This implementation uses a heap-based callout queue of
+ *      absolute times.  Therefore, in the average and worst case,
+ *      scheduling, canceling, and expiring timers is O(log N) (where
+ *      N is the total number of timers).  In addition, we can also
+ *      preallocate as many \a ACE_Timer_Nodes as there are slots in
+ *      the heap.  This allows us to completely remove the need for
+ *      dynamic memory allocation, which is important for real-time
+ *      systems.
+ * @{
+ *
+ * \section pj_timer_examples_sec Examples
+ *
+ * For some examples on how to use the timer heap, please see the link below.
+ *
+ *  - \ref page_pjlib_timer_test
+ */
+
+
+/**
+ * The type for internal timer ID.
+ */
+typedef int pj_timer_id_t;
+
+/** 
+ * Forward declaration for pj_timer_entry. 
+ */
+struct pj_timer_entry;
+
+/**
+ * The type of callback function to be called by timer scheduler when a timer
+ * has expired.
+ *
+ * @param timer_heap    The timer heap.
+ * @param entry         Timer entry which timer's has expired.
+ */
+typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap,
+				    struct pj_timer_entry *entry);
+
+
+/**
+ * This structure represents an entry to the timer.
+ */
+struct pj_timer_entry
+{
+    /** 
+     * User data to be associated with this entry. 
+     * Applications normally will put the instance of object that
+     * owns the timer entry in this field.
+     */
+    void *user_data;
+
+    /** 
+     * Arbitrary ID assigned by the user/owner of this entry. 
+     * Applications can use this ID to distinguish multiple
+     * timer entries that share the same callback and user_data.
+     */
+    int id;
+
+    /** 
+     * Callback to be called when the timer expires. 
+     */
+    pj_timer_heap_callback *cb;
+
+    /** 
+     * Internal unique timer ID, which is assigned by the timer heap. 
+     * Application should not touch this ID.
+     */
+    pj_timer_id_t _timer_id;
+
+    /** 
+     * The future time when the timer expires, which the value is updated
+     * by timer heap when the timer is scheduled.
+     */
+    pj_time_val _timer_value;
+};
+
+
+/**
+ * Calculate memory size required to create a timer heap.
+ *
+ * @param count     Number of timer entries to be supported.
+ * @return          Memory size requirement in bytes.
+ */
+PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count);
+
+/**
+ * Create a timer heap.
+ *
+ * @param pool      The pool where allocations in the timer heap will be 
+ *                  allocated. The timer heap will dynamicly allocate 
+ *                  more storate from the pool if the number of timer 
+ *                  entries registered is more than the size originally 
+ *                  requested when calling this function.
+ * @param count     The maximum number of timer entries to be supported 
+ *                  initially. If the application registers more entries 
+ *                  during runtime, then the timer heap will resize.
+ * @param ht        Pointer to receive the created timer heap.
+ *
+ * @return          PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
+					   pj_size_t count,
+                                           pj_timer_heap_t **ht);
+
+/**
+ * Destroy the timer heap.
+ *
+ * @param ht        The timer heap.
+ */
+PJ_DECL(void) pj_timer_heap_destroy( pj_timer_heap_t *ht );
+
+
+/**
+ * Set lock object to be used by the timer heap. By default, the timer heap
+ * uses dummy synchronization.
+ *
+ * @param ht        The timer heap.
+ * @param lock      The lock object to be used for synchronization.
+ * @param auto_del  If nonzero, the lock object will be destroyed when
+ *                  the timer heap is destroyed.
+ */
+PJ_DECL(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht,
+                                      pj_lock_t *lock,
+                                      pj_bool_t auto_del );
+
+/**
+ * Set maximum number of timed out entries to process in a single poll.
+ *
+ * @param ht        The timer heap.
+ * @param count     Number of entries.
+ *
+ * @return          The old number.
+ */
+PJ_DECL(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
+                                                           unsigned count );
+
+/**
+ * Initialize a timer entry. Application should call this function at least
+ * once before scheduling the entry to the timer heap, to properly initialize
+ * the timer entry.
+ *
+ * @param entry     The timer entry to be initialized.
+ * @param id        Arbitrary ID assigned by the user/owner of this entry.
+ *                  Applications can use this ID to distinguish multiple
+ *                  timer entries that share the same callback and user_data.
+ * @param user_data User data to be associated with this entry. 
+ *                  Applications normally will put the instance of object that
+ *                  owns the timer entry in this field.
+ * @param cb        Callback function to be called when the timer elapses.
+ *
+ * @return          The timer entry itself.
+ */
+PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
+                                              int id,
+                                              void *user_data,
+                                              pj_timer_heap_callback *cb );
+
+/**
+ * Schedule a timer entry which will expire AFTER the specified delay.
+ *
+ * @param ht        The timer heap.
+ * @param entry     The entry to be registered. 
+ * @param delay     The interval to expire.
+ * @return          PJ_SUCCESS, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
+					     pj_timer_entry *entry, 
+					     const pj_time_val *delay);
+
+/**
+ * Cancel a previously registered timer.
+ *
+ * @param ht        The timer heap.
+ * @param entry     The entry to be cancelled.
+ * @return          The number of timer cancelled, which should be one if the
+ *                  entry has really been registered, or zero if no timer was
+ *                  cancelled.
+ */
+PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
+				   pj_timer_entry *entry);
+
+/**
+ * Get the number of timer entries.
+ *
+ * @param ht        The timer heap.
+ * @return          The number of timer entries.
+ */
+PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht );
+
+/**
+ * Get the earliest time registered in the timer heap. The timer heap
+ * MUST have at least one timer being scheduled (application should use
+ * #pj_timer_heap_count() before calling this function).
+ *
+ * @param ht        The timer heap.
+ * @param timeval   The time deadline of the earliest timer entry.
+ *
+ * @return          PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled.
+ */
+PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, 
+					          pj_time_val *timeval);
+
+/**
+ * Poll the timer heap, check for expired timers and call the callback for
+ * each of the expired timers.
+ *
+ * @param ht         The timer heap.
+ * @param next_delay If this parameter is not NULL, it will be filled up with
+ *		     the time delay until the next timer elapsed, or -1 in
+ *		     the sec part if no entry exist.
+ *
+ * @return           The number of timers expired.
+ */
+PJ_DECL(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 
+                                      pj_time_val *next_delay);
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+#endif	/* __PJ_TIMER_H__ */
+
diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h
index e1e0df4..62e2c0f 100644
--- a/pjlib/include/pj/types.h
+++ b/pjlib/include/pj/types.h
@@ -1,442 +1,442 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_TYPES_H__

-#define __PJ_TYPES_H__

-

-

-/**

- * @defgroup PJ PJ Library

- */

-/**

- * @file types.h

- * @brief Declaration of basic types and utility.

- */

-/**

- * @defgroup PJ_BASIC Basic Data Types and Library Functionality.

- * @ingroup PJ_DS

- * @{

- */

-#include <pj/config.h>

-

-PJ_BEGIN_DECL

-

-///////////////////////////////////////////////////////////////////////////////

-

-/** Unsigned 32bit integer. */

-typedef int		pj_int32_t;

-

-/** Signed 32bit integer. */

-typedef unsigned int	pj_uint32_t;

-

-/** Unsigned 16bit integer. */

-typedef short		pj_int16_t;

-

-/** Signed 16bit integer. */

-typedef unsigned short	pj_uint16_t;

-

-/** Unsigned 8bit integer. */

-typedef signed char	pj_int8_t;

-

-/** Signed 16bit integer. */

-typedef unsigned char	pj_uint8_t;

-

-/** Large unsigned integer. */

-typedef size_t		pj_size_t;

-

-/** Large signed integer. */

-typedef long		pj_ssize_t;

-

-/** Status code. */

-typedef int		pj_status_t;

-

-/** Boolean. */

-typedef int		pj_bool_t;

-

-/** Status is OK. */

-#define PJ_SUCCESS  0

-

-/** True value. */

-#define PJ_TRUE	    1

-

-/** False value. */

-#define PJ_FALSE    0

-

-/**

- * File offset type.

- */

-#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0

-typedef pj_int64_t pj_off_t;

-#else

-typedef pj_ssize_t pj_off_t;

-#endif

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * Data structure types.

- */

-/**

- * This type is used as replacement to legacy C string, and used throughout

- * the library. By convention, the string is NOT null terminated.

- */

-struct pj_str_t

-{

-    /** Buffer pointer, which is by convention NOT null terminated. */

-    char       *ptr;

-

-    /** The length of the string. */

-    pj_ssize_t  slen;

-};

-

-

-/**

- * The opaque data type for linked list, which is used as arguments throughout

- * the linked list operations.

- */

-typedef void pj_list_type;

-

-/** 

- * List.

- */

-typedef struct pj_list pj_list;

-

-/**

- * Opaque data type for hash tables.

- */

-typedef struct pj_hash_table_t pj_hash_table_t;

-

-/**

- * Opaque data type for hash entry (only used internally by hash table).

- */

-typedef struct pj_hash_entry pj_hash_entry;

-

-/**

- * Data type for hash search iterator.

- * This structure should be opaque, however applications need to declare

- * concrete variable of this type, that's why the declaration is visible here.

- */

-typedef struct pj_hash_iterator_t

-{

-    pj_uint32_t	     index;     /**< Internal index.     */

-    pj_hash_entry   *entry;     /**< Internal entry.     */

-} pj_hash_iterator_t;

-

-

-/**

- * Forward declaration for memory pool factory.

- */

-typedef struct pj_pool_factory pj_pool_factory;

-

-/**

- * Opaque data type for memory pool.

- */

-typedef struct pj_pool_t pj_pool_t;

-

-/**

- * Forward declaration for caching pool, a pool factory implementation.

- */

-typedef struct pj_caching_pool pj_caching_pool;

-

-/**

- * This type is used as replacement to legacy C string, and used throughout

- * the library.

- */

-typedef struct pj_str_t pj_str_t;

-

-/**

- * Opaque data type for I/O Queue structure.

- */

-typedef struct pj_ioqueue_t pj_ioqueue_t;

-

-/**

- * Opaque data type for key that identifies a handle registered to the

- * I/O queue framework.

- */

-typedef struct pj_ioqueue_key_t pj_ioqueue_key_t;

-

-/**

- * Opaque data to identify timer heap.

- */

-typedef struct pj_timer_heap_t pj_timer_heap_t;

-

-/**

- * Forward declaration for timer entry.

- */

-typedef struct pj_timer_entry pj_timer_entry;

-

-/** 

- * Opaque data type for atomic operations.

- */

-typedef struct pj_atomic_t pj_atomic_t;

-

-/**

- * Value type of an atomic variable.

- */

-typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t;

- 

-///////////////////////////////////////////////////////////////////////////////

-

-/** Thread handle. */

-typedef struct pj_thread_t pj_thread_t;

-

-/** Lock object. */

-typedef struct pj_lock_t pj_lock_t;

-

-/** Mutex handle. */

-typedef struct pj_mutex_t pj_mutex_t;

-

-/** Semaphore handle. */

-typedef struct pj_sem_t pj_sem_t;

-

-/** Event object. */

-typedef struct pj_event_t pj_event_t;

-

-/** Unidirectional stream pipe object. */

-typedef struct pj_pipe_t pj_pipe_t;

-

-/** Operating system handle. */

-typedef void *pj_oshandle_t;

-

-/** Socket handle. */

-typedef long pj_sock_t;

-

-/** Generic socket address. */

-typedef void pj_sockaddr_t;

-

-/** Color type. */

-typedef unsigned int pj_color_t;

-

-/** Exception id. */

-typedef int pj_exception_id_t;

-

-///////////////////////////////////////////////////////////////////////////////

-

-/** Utility macro to compute the number of elements in static array. */

-#define PJ_ARRAY_SIZE(a)    (sizeof(a)/sizeof(a[0]))

-

-/** Maximum value for signed 32-bit integer. */

-#define PJ_MAXINT32  0x7FFFFFFFL

-

-/**

- * Length of object names.

- */

-#define PJ_MAX_OBJ_NAME	16

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * General.

- */

-/**

- * Initialize the PJ Library.

- * This function must be called before using the library. The purpose of this

- * function is to initialize static library data, such as character table used

- * in random string generation, and to initialize operating system dependent

- * functionality (such as WSAStartup() in Windows).

- */

-PJ_DECL(pj_status_t) pj_init(void);

-

-

-/**

- * @}

- */

-/**

- * @addtogroup PJ_TIME Time Data Type and Manipulation.

- * @ingroup PJ_MISC

- * @{

- */

-

-/**

- * Representation of time value in this library.

- * This type can be used to represent either an interval or a specific time

- * or date. 

- */

-typedef struct pj_time_val

-{

-    /** The seconds part of the time. */

-    long    sec;

-

-    /** The miliseconds fraction of the time. */

-    long    msec;

-

-} pj_time_val;

-

-/**

- * Normalize the value in time value.

- * @param t     Time value to be normalized.

- */

-PJ_DECL(void) pj_time_val_normalize(pj_time_val *t);

-

-/**

- * Get the total time value in miliseconds. This is the same as

- * multiplying the second part with 1000 and then add the miliseconds

- * part to the result.

- *

- * @param t     The time value.

- * @return      Total time in miliseconds.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_MSEC(t)	((t).sec * 1000 + (t).msec)

-

-/**

- * This macro will check if \a t1 is equal to \a t2.

- *

- * @param t1    The first time value to compare.

- * @param t2    The second time value to compare.

- * @return      Non-zero if both time values are equal.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_EQ(t1, t2)	((t1).sec==(t2).sec && (t1).msec==(t2).msec)

-

-/**

- * This macro will check if \a t1 is greater than \a t2

- *

- * @param t1    The first time value to compare.

- * @param t2    The second time value to compare.

- * @return      Non-zero if t1 is greater than t2.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_GT(t1, t2)	((t1).sec>(t2).sec || \

-                                ((t1).sec==(t2).sec && (t1).msec>(t2).msec))

-

-/**

- * This macro will check if \a t1 is greater than or equal to \a t2

- *

- * @param t1    The first time value to compare.

- * @param t2    The second time value to compare.

- * @return      Non-zero if t1 is greater than or equal to t2.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_GTE(t1, t2)	(PJ_TIME_VAL_GT(t1,t2) || \

-                                 PJ_TIME_VAL_EQ(t1,t2))

-

-/**

- * This macro will check if \a t1 is less than \a t2

- *

- * @param t1    The first time value to compare.

- * @param t2    The second time value to compare.

- * @return      Non-zero if t1 is less than t2.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_LT(t1, t2)	(!(PJ_TIME_VAL_GTE(t1,t2)))

-

-/**

- * This macro will check if \a t1 is less than or equal to \a t2.

- *

- * @param t1    The first time value to compare.

- * @param t2    The second time value to compare.

- * @return      Non-zero if t1 is less than or equal to t2.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_LTE(t1, t2)	(!PJ_TIME_VAL_GT(t1, t2))

-

-/**

- * Add \a t2 to \a t1 and store the result in \a t1. Effectively

- *

- * this macro will expand as: (\a t1 += \a t2).

- * @param t1    The time value to add.

- * @param t2    The time value to be added to \a t1.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_ADD(t1, t2)	    do {			    \

-					(t1).sec += (t2).sec;	    \

-					(t1).msec += (t2).msec;	    \

-					pj_time_val_normalize(&(t1)); \

-				    } while (0)

-

-

-/**

- * Substract \a t2 from \a t1 and store the result in \a t1. Effectively

- * this macro will expand as (\a t1 -= \a t2).

- *

- * @param t1    The time value to subsctract.

- * @param t2    The time value to be substracted from \a t1.

- * @hideinitializer

- */

-#define PJ_TIME_VAL_SUB(t1, t2)	    do {			    \

-					(t1).sec -= (t2).sec;	    \

-					(t1).msec -= (t2).msec;	    \

-					pj_time_val_normalize(&(t1)); \

-				    } while (0)

-

-

-/**

- * This structure represent the parsed representation of time.

- * It is acquired by calling #pj_time_decode().

- */

-typedef struct pj_parsed_time

-{

-    /** This represents day of week where value zero means Sunday */

-    int wday;

-

-    /** This represents day of the year, 0-365, where zero means

-     *  1st of January.

-     */

-    int yday;

-

-    /** This represents day of month: 1-31 */

-    int day;

-

-    /** This represents month, with the value is 0 - 11 (zero is January) */

-    int mon;

-

-    /** This represent the actual year (unlike in ANSI libc where

-     *  the value must be added by 1900).

-     */

-    int year;

-

-    /** This represents the second part, with the value is 0-59 */

-    int sec;

-

-    /** This represents the minute part, with the value is: 0-59 */

-    int min;

-

-    /** This represents the hour part, with the value is 0-23 */

-    int hour;

-

-    /** This represents the milisecond part, with the value is 0-999 */

-    int msec;

-

-} pj_parsed_time;

-

-

-/**

- * @}	// Time Management

- */

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * Terminal.

- */

-/**

- * Color code combination.

- */

-enum {

-    PJ_TERM_COLOR_R	= 2,    /**< Red            */

-    PJ_TERM_COLOR_G	= 4,    /**< Green          */

-    PJ_TERM_COLOR_B	= 1,    /**< Blue.          */

-    PJ_TERM_COLOR_BRIGHT = 8    /**< Bright mask.   */

-};

-

-

-

-

-PJ_END_DECL

-

-

-#endif /* __PJ_TYPES_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_TYPES_H__
+#define __PJ_TYPES_H__
+
+
+/**
+ * @defgroup PJ PJ Library
+ */
+/**
+ * @file types.h
+ * @brief Declaration of basic types and utility.
+ */
+/**
+ * @defgroup PJ_BASIC Basic Data Types and Library Functionality.
+ * @ingroup PJ_DS
+ * @{
+ */
+#include <pj/config.h>
+
+PJ_BEGIN_DECL
+
+///////////////////////////////////////////////////////////////////////////////
+
+/** Unsigned 32bit integer. */
+typedef int		pj_int32_t;
+
+/** Signed 32bit integer. */
+typedef unsigned int	pj_uint32_t;
+
+/** Unsigned 16bit integer. */
+typedef short		pj_int16_t;
+
+/** Signed 16bit integer. */
+typedef unsigned short	pj_uint16_t;
+
+/** Unsigned 8bit integer. */
+typedef signed char	pj_int8_t;
+
+/** Signed 16bit integer. */
+typedef unsigned char	pj_uint8_t;
+
+/** Large unsigned integer. */
+typedef size_t		pj_size_t;
+
+/** Large signed integer. */
+typedef long		pj_ssize_t;
+
+/** Status code. */
+typedef int		pj_status_t;
+
+/** Boolean. */
+typedef int		pj_bool_t;
+
+/** Status is OK. */
+#define PJ_SUCCESS  0
+
+/** True value. */
+#define PJ_TRUE	    1
+
+/** False value. */
+#define PJ_FALSE    0
+
+/**
+ * File offset type.
+ */
+#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0
+typedef pj_int64_t pj_off_t;
+#else
+typedef pj_ssize_t pj_off_t;
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Data structure types.
+ */
+/**
+ * This type is used as replacement to legacy C string, and used throughout
+ * the library. By convention, the string is NOT null terminated.
+ */
+struct pj_str_t
+{
+    /** Buffer pointer, which is by convention NOT null terminated. */
+    char       *ptr;
+
+    /** The length of the string. */
+    pj_ssize_t  slen;
+};
+
+
+/**
+ * The opaque data type for linked list, which is used as arguments throughout
+ * the linked list operations.
+ */
+typedef void pj_list_type;
+
+/** 
+ * List.
+ */
+typedef struct pj_list pj_list;
+
+/**
+ * Opaque data type for hash tables.
+ */
+typedef struct pj_hash_table_t pj_hash_table_t;
+
+/**
+ * Opaque data type for hash entry (only used internally by hash table).
+ */
+typedef struct pj_hash_entry pj_hash_entry;
+
+/**
+ * Data type for hash search iterator.
+ * This structure should be opaque, however applications need to declare
+ * concrete variable of this type, that's why the declaration is visible here.
+ */
+typedef struct pj_hash_iterator_t
+{
+    pj_uint32_t	     index;     /**< Internal index.     */
+    pj_hash_entry   *entry;     /**< Internal entry.     */
+} pj_hash_iterator_t;
+
+
+/**
+ * Forward declaration for memory pool factory.
+ */
+typedef struct pj_pool_factory pj_pool_factory;
+
+/**
+ * Opaque data type for memory pool.
+ */
+typedef struct pj_pool_t pj_pool_t;
+
+/**
+ * Forward declaration for caching pool, a pool factory implementation.
+ */
+typedef struct pj_caching_pool pj_caching_pool;
+
+/**
+ * This type is used as replacement to legacy C string, and used throughout
+ * the library.
+ */
+typedef struct pj_str_t pj_str_t;
+
+/**
+ * Opaque data type for I/O Queue structure.
+ */
+typedef struct pj_ioqueue_t pj_ioqueue_t;
+
+/**
+ * Opaque data type for key that identifies a handle registered to the
+ * I/O queue framework.
+ */
+typedef struct pj_ioqueue_key_t pj_ioqueue_key_t;
+
+/**
+ * Opaque data to identify timer heap.
+ */
+typedef struct pj_timer_heap_t pj_timer_heap_t;
+
+/**
+ * Forward declaration for timer entry.
+ */
+typedef struct pj_timer_entry pj_timer_entry;
+
+/** 
+ * Opaque data type for atomic operations.
+ */
+typedef struct pj_atomic_t pj_atomic_t;
+
+/**
+ * Value type of an atomic variable.
+ */
+typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t;
+ 
+///////////////////////////////////////////////////////////////////////////////
+
+/** Thread handle. */
+typedef struct pj_thread_t pj_thread_t;
+
+/** Lock object. */
+typedef struct pj_lock_t pj_lock_t;
+
+/** Mutex handle. */
+typedef struct pj_mutex_t pj_mutex_t;
+
+/** Semaphore handle. */
+typedef struct pj_sem_t pj_sem_t;
+
+/** Event object. */
+typedef struct pj_event_t pj_event_t;
+
+/** Unidirectional stream pipe object. */
+typedef struct pj_pipe_t pj_pipe_t;
+
+/** Operating system handle. */
+typedef void *pj_oshandle_t;
+
+/** Socket handle. */
+typedef long pj_sock_t;
+
+/** Generic socket address. */
+typedef void pj_sockaddr_t;
+
+/** Color type. */
+typedef unsigned int pj_color_t;
+
+/** Exception id. */
+typedef int pj_exception_id_t;
+
+///////////////////////////////////////////////////////////////////////////////
+
+/** Utility macro to compute the number of elements in static array. */
+#define PJ_ARRAY_SIZE(a)    (sizeof(a)/sizeof(a[0]))
+
+/** Maximum value for signed 32-bit integer. */
+#define PJ_MAXINT32  0x7FFFFFFFL
+
+/**
+ * Length of object names.
+ */
+#define PJ_MAX_OBJ_NAME	16
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * General.
+ */
+/**
+ * Initialize the PJ Library.
+ * This function must be called before using the library. The purpose of this
+ * function is to initialize static library data, such as character table used
+ * in random string generation, and to initialize operating system dependent
+ * functionality (such as WSAStartup() in Windows).
+ */
+PJ_DECL(pj_status_t) pj_init(void);
+
+
+/**
+ * @}
+ */
+/**
+ * @addtogroup PJ_TIME Time Data Type and Manipulation.
+ * @ingroup PJ_MISC
+ * @{
+ */
+
+/**
+ * Representation of time value in this library.
+ * This type can be used to represent either an interval or a specific time
+ * or date. 
+ */
+typedef struct pj_time_val
+{
+    /** The seconds part of the time. */
+    long    sec;
+
+    /** The miliseconds fraction of the time. */
+    long    msec;
+
+} pj_time_val;
+
+/**
+ * Normalize the value in time value.
+ * @param t     Time value to be normalized.
+ */
+PJ_DECL(void) pj_time_val_normalize(pj_time_val *t);
+
+/**
+ * Get the total time value in miliseconds. This is the same as
+ * multiplying the second part with 1000 and then add the miliseconds
+ * part to the result.
+ *
+ * @param t     The time value.
+ * @return      Total time in miliseconds.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_MSEC(t)	((t).sec * 1000 + (t).msec)
+
+/**
+ * This macro will check if \a t1 is equal to \a t2.
+ *
+ * @param t1    The first time value to compare.
+ * @param t2    The second time value to compare.
+ * @return      Non-zero if both time values are equal.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_EQ(t1, t2)	((t1).sec==(t2).sec && (t1).msec==(t2).msec)
+
+/**
+ * This macro will check if \a t1 is greater than \a t2
+ *
+ * @param t1    The first time value to compare.
+ * @param t2    The second time value to compare.
+ * @return      Non-zero if t1 is greater than t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_GT(t1, t2)	((t1).sec>(t2).sec || \
+                                ((t1).sec==(t2).sec && (t1).msec>(t2).msec))
+
+/**
+ * This macro will check if \a t1 is greater than or equal to \a t2
+ *
+ * @param t1    The first time value to compare.
+ * @param t2    The second time value to compare.
+ * @return      Non-zero if t1 is greater than or equal to t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_GTE(t1, t2)	(PJ_TIME_VAL_GT(t1,t2) || \
+                                 PJ_TIME_VAL_EQ(t1,t2))
+
+/**
+ * This macro will check if \a t1 is less than \a t2
+ *
+ * @param t1    The first time value to compare.
+ * @param t2    The second time value to compare.
+ * @return      Non-zero if t1 is less than t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_LT(t1, t2)	(!(PJ_TIME_VAL_GTE(t1,t2)))
+
+/**
+ * This macro will check if \a t1 is less than or equal to \a t2.
+ *
+ * @param t1    The first time value to compare.
+ * @param t2    The second time value to compare.
+ * @return      Non-zero if t1 is less than or equal to t2.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_LTE(t1, t2)	(!PJ_TIME_VAL_GT(t1, t2))
+
+/**
+ * Add \a t2 to \a t1 and store the result in \a t1. Effectively
+ *
+ * this macro will expand as: (\a t1 += \a t2).
+ * @param t1    The time value to add.
+ * @param t2    The time value to be added to \a t1.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_ADD(t1, t2)	    do {			    \
+					(t1).sec += (t2).sec;	    \
+					(t1).msec += (t2).msec;	    \
+					pj_time_val_normalize(&(t1)); \
+				    } while (0)
+
+
+/**
+ * Substract \a t2 from \a t1 and store the result in \a t1. Effectively
+ * this macro will expand as (\a t1 -= \a t2).
+ *
+ * @param t1    The time value to subsctract.
+ * @param t2    The time value to be substracted from \a t1.
+ * @hideinitializer
+ */
+#define PJ_TIME_VAL_SUB(t1, t2)	    do {			    \
+					(t1).sec -= (t2).sec;	    \
+					(t1).msec -= (t2).msec;	    \
+					pj_time_val_normalize(&(t1)); \
+				    } while (0)
+
+
+/**
+ * This structure represent the parsed representation of time.
+ * It is acquired by calling #pj_time_decode().
+ */
+typedef struct pj_parsed_time
+{
+    /** This represents day of week where value zero means Sunday */
+    int wday;
+
+    /** This represents day of the year, 0-365, where zero means
+     *  1st of January.
+     */
+    int yday;
+
+    /** This represents day of month: 1-31 */
+    int day;
+
+    /** This represents month, with the value is 0 - 11 (zero is January) */
+    int mon;
+
+    /** This represent the actual year (unlike in ANSI libc where
+     *  the value must be added by 1900).
+     */
+    int year;
+
+    /** This represents the second part, with the value is 0-59 */
+    int sec;
+
+    /** This represents the minute part, with the value is: 0-59 */
+    int min;
+
+    /** This represents the hour part, with the value is 0-23 */
+    int hour;
+
+    /** This represents the milisecond part, with the value is 0-999 */
+    int msec;
+
+} pj_parsed_time;
+
+
+/**
+ * @}	// Time Management
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Terminal.
+ */
+/**
+ * Color code combination.
+ */
+enum {
+    PJ_TERM_COLOR_R	= 2,    /**< Red            */
+    PJ_TERM_COLOR_G	= 4,    /**< Green          */
+    PJ_TERM_COLOR_B	= 1,    /**< Blue.          */
+    PJ_TERM_COLOR_BRIGHT = 8    /**< Bright mask.   */
+};
+
+
+
+
+PJ_END_DECL
+
+
+#endif /* __PJ_TYPES_H__ */
+
diff --git a/pjlib/include/pjlib++.hpp b/pjlib/include/pjlib++.hpp
index 833f9a0..59a3d61 100644
--- a/pjlib/include/pjlib++.hpp
+++ b/pjlib/include/pjlib++.hpp
@@ -1,33 +1,33 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 __PJLIBPP_H__

-#define __PJLIBPP_H__

-

-#include <pj++/pool.hpp>

-#include <pj++/hash.hpp>

-#include <pj++/list.hpp>

-#include <pj++/os.hpp>

-#include <pj++/proactor.hpp>

-#include <pj++/scanner.hpp>

-#include <pj++/sock.hpp>

-#include <pj++/string.hpp>

-#include <pj++/timer.hpp>

-#include <pj++/tree.hpp>

-

-#endif	/* __PJLIBPP_H__ */

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 __PJLIBPP_H__
+#define __PJLIBPP_H__
+
+#include <pj++/pool.hpp>
+#include <pj++/hash.hpp>
+#include <pj++/list.hpp>
+#include <pj++/os.hpp>
+#include <pj++/proactor.hpp>
+#include <pj++/scanner.hpp>
+#include <pj++/sock.hpp>
+#include <pj++/string.hpp>
+#include <pj++/timer.hpp>
+#include <pj++/tree.hpp>
+
+#endif	/* __PJLIBPP_H__ */
diff --git a/pjlib/include/pjlib.h b/pjlib/include/pjlib.h
index a63f57e..45a9e49 100644
--- a/pjlib/include/pjlib.h
+++ b/pjlib/include/pjlib.h
@@ -1,55 +1,55 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 __PJLIB_H__

-#define __PJLIB_H__

-

-/**

- * @file pjlib.h

- * @brief Include all PJLIB header files.

- */

-

-#include <pj/addr_resolv.h>

-#include <pj/array.h>

-#include <pj/assert.h>

-#include <pj/ctype.h>

-#include <pj/errno.h>

-#include <pj/except.h>

-#include <pj/fifobuf.h>

-#include <pj/file_access.h>

-#include <pj/file_io.h>

-#include <pj/guid.h>

-#include <pj/hash.h>

-#include <pj/ioqueue.h>

-#include <pj/list.h>

-#include <pj/lock.h>

-#include <pj/log.h>

-#include <pj/os.h>

-#include <pj/pool.h>

-#include <pj/rand.h>

-#include <pj/rbtree.h>

-#include <pj/sock.h>

-#include <pj/sock_select.h>

-#include <pj/string.h>

-#include <pj/timer.h>

-

-#include <pj/compat/high_precision.h>

-

-#endif  /* __PJLIB_H__ */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 __PJLIB_H__
+#define __PJLIB_H__
+
+/**
+ * @file pjlib.h
+ * @brief Include all PJLIB header files.
+ */
+
+#include <pj/addr_resolv.h>
+#include <pj/array.h>
+#include <pj/assert.h>
+#include <pj/ctype.h>
+#include <pj/errno.h>
+#include <pj/except.h>
+#include <pj/fifobuf.h>
+#include <pj/file_access.h>
+#include <pj/file_io.h>
+#include <pj/guid.h>
+#include <pj/hash.h>
+#include <pj/ioqueue.h>
+#include <pj/list.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/rand.h>
+#include <pj/rbtree.h>
+#include <pj/sock.h>
+#include <pj/sock_select.h>
+#include <pj/string.h>
+#include <pj/timer.h>
+
+#include <pj/compat/high_precision.h>
+
+#endif  /* __PJLIB_H__ */
+
diff --git a/pjlib/src/pj/config.c b/pjlib/src/pj/config.c
index d6e55b3..8c7ed52 100644
--- a/pjlib/src/pj/config.c
+++ b/pjlib/src/pj/config.c
@@ -1,48 +1,48 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/config.h>

-#include <pj/log.h>

-#include <pj/ioqueue.h>

-

-static const char *id = "config.c";

-const char *PJ_VERSION = "0.3.0-pre4";

-

-PJ_DEF(void) pj_dump_config(void)

-{

-    PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono"));

-    PJ_LOG(3, (id, "Dumping configurations:"));

-    PJ_LOG(3, (id, " PJ_VERSION               : %s", PJ_VERSION));

-    PJ_LOG(3, (id, " PJ_DEBUG                 : %d", PJ_DEBUG));

-    PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED));

-    PJ_LOG(3, (id, " PJ_POOL_DEBUG            : %d", PJ_POOL_DEBUG));

-    PJ_LOG(3, (id, " PJ_HAS_THREADS           : %d", PJ_HAS_THREADS));

-    PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL         : %d", PJ_LOG_MAX_LEVEL));

-    PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE          : %d", PJ_LOG_MAX_SIZE));

-    PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER  : %d", PJ_LOG_USE_STACK_BUFFER));

-    PJ_LOG(3, (id, " PJ_HAS_TCP               : %d", PJ_HAS_TCP));

-    PJ_LOG(3, (id, " PJ_MAX_HOSTNAME          : %d", PJ_MAX_HOSTNAME));

-    PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE         : %d", PJ_HAS_SEMAPHORE));

-    PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ         : %d", PJ_HAS_EVENT_OBJ));

-    PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER    : %d", PJ_HAS_HIGH_RES_TIMER));

-    PJ_LOG(3, (id, " PJ_(endianness)          : %s", 

-	       (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian")));

-    PJ_LOG(3, (id, " ioqueue type             : %s", pj_ioqueue_name()));

-    PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES   : %d", PJ_IOQUEUE_MAX_HANDLES));

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/config.h>
+#include <pj/log.h>
+#include <pj/ioqueue.h>
+
+static const char *id = "config.c";
+const char *PJ_VERSION = "0.3.0-pre4";
+
+PJ_DEF(void) pj_dump_config(void)
+{
+    PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono"));
+    PJ_LOG(3, (id, "Dumping configurations:"));
+    PJ_LOG(3, (id, " PJ_VERSION               : %s", PJ_VERSION));
+    PJ_LOG(3, (id, " PJ_DEBUG                 : %d", PJ_DEBUG));
+    PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED));
+    PJ_LOG(3, (id, " PJ_POOL_DEBUG            : %d", PJ_POOL_DEBUG));
+    PJ_LOG(3, (id, " PJ_HAS_THREADS           : %d", PJ_HAS_THREADS));
+    PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL         : %d", PJ_LOG_MAX_LEVEL));
+    PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE          : %d", PJ_LOG_MAX_SIZE));
+    PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER  : %d", PJ_LOG_USE_STACK_BUFFER));
+    PJ_LOG(3, (id, " PJ_HAS_TCP               : %d", PJ_HAS_TCP));
+    PJ_LOG(3, (id, " PJ_MAX_HOSTNAME          : %d", PJ_MAX_HOSTNAME));
+    PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE         : %d", PJ_HAS_SEMAPHORE));
+    PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ         : %d", PJ_HAS_EVENT_OBJ));
+    PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER    : %d", PJ_HAS_HIGH_RES_TIMER));
+    PJ_LOG(3, (id, " PJ_(endianness)          : %s", 
+	       (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian")));
+    PJ_LOG(3, (id, " ioqueue type             : %s", pj_ioqueue_name()));
+    PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES   : %d", PJ_IOQUEUE_MAX_HANDLES));
+}
+
diff --git a/pjlib/src/pj/ctype.c b/pjlib/src/pj/ctype.c
index b274cca..a5b83b4 100644
--- a/pjlib/src/pj/ctype.c
+++ b/pjlib/src/pj/ctype.c
@@ -1,24 +1,24 @@
-/* $Id: $ */

-/* 

- * Copyright (C)2003-2006 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/ctype.h>

-

-

-char pj_hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',

-			'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

-

+/* $Id: $ */
+/* 
+ * Copyright (C)2003-2006 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/ctype.h>
+
+
+char pj_hex_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+			'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
diff --git a/pjlib/src/pj/equeue_winnt.c b/pjlib/src/pj/equeue_winnt.c
index c395b2f..e7a20c4 100644
--- a/pjlib/src/pj/equeue_winnt.c
+++ b/pjlib/src/pj/equeue_winnt.c
@@ -1,19 +1,19 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/equeue.h>

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/equeue.h>
diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c
index 0b47121..d214d68 100644
--- a/pjlib/src/pj/errno.c
+++ b/pjlib/src/pj/errno.c
@@ -1,115 +1,115 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/errno.h>

-#include <pj/string.h>

-#include <pj/compat/sprintf.h>

-

-/* Prototype for platform specific error message, which will be defined 

- * in separate file.

- */

-extern int platform_strerror( pj_os_err_type code, 

-                              char *buf, pj_size_t bufsize );

-

-/* PJLIB's own error codes/messages */

-static const struct 

-{

-    int code;

-    const char *msg;

-} err_str[] = 

-{

-    { PJ_EUNKNOWN,      "Unknown Error" },

-    { PJ_EPENDING,      "Pending operation" },

-    { PJ_ETOOMANYCONN,  "Too many connecting sockets" },

-    { PJ_EINVAL,        "Invalid value or argument" },

-    { PJ_ENAMETOOLONG,  "Name too long" },

-    { PJ_ENOTFOUND,     "Not found" },

-    { PJ_ENOMEM,        "Not enough memory" },

-    { PJ_EBUG,          "BUG DETECTED!" },

-    { PJ_ETIMEDOUT,     "Operation timed out" },

-    { PJ_ETOOMANY,      "Too many objects of the specified type"},

-    { PJ_EBUSY,         "Object is busy"},

-    { PJ_ENOTSUP,	"Option/operation is not supported"},

-    { PJ_EINVALIDOP,	"Invalid operation"},

-    { PJ_ECANCELLED,    "Operation cancelled"},

-    { PJ_EEXISTS,       "Object already exists" }

-};

-

-/*

- * pjlib_error()

- *

- * Retrieve message string for PJLIB's own error code.

- */

-static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)

-{

-    unsigned i;

-

-    for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {

-        if (err_str[i].code == code) {

-            pj_size_t len = strlen(err_str[i].msg);

-            if (len >= size) len = size-1;

-            pj_memcpy(buf, err_str[i].msg, len);

-            buf[len] = '\0';

-            return len;

-        }

-    }

-

-    *buf++ = '?';

-    *buf++ = '?';

-    *buf++ = '?';

-    *buf++ = '\0';

-    return 3;

-}

-

-/*

- * pj_strerror()

- */

-PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, 

-			      char *buf, pj_size_t bufsize )

-{

-    int len = -1;

-    pj_str_t errstr;

-

-    if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {

-        len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode);

-

-    } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {

-        len = pjlib_error(statcode, buf, bufsize);

-

-    } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {

-        len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);

-

-    } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) {

-        len = pj_snprintf( buf, bufsize, "User error %d", statcode);

-

-    } else {

-        len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode);

-

-    }

-

-    if (len < 1) {

-        *buf = '\0';

-        len = 0;

-    }

-

-    errstr.ptr = buf;

-    errstr.slen = len;

-

-    return errstr;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/errno.h>
+#include <pj/string.h>
+#include <pj/compat/sprintf.h>
+
+/* Prototype for platform specific error message, which will be defined 
+ * in separate file.
+ */
+extern int platform_strerror( pj_os_err_type code, 
+                              char *buf, pj_size_t bufsize );
+
+/* PJLIB's own error codes/messages */
+static const struct 
+{
+    int code;
+    const char *msg;
+} err_str[] = 
+{
+    { PJ_EUNKNOWN,      "Unknown Error" },
+    { PJ_EPENDING,      "Pending operation" },
+    { PJ_ETOOMANYCONN,  "Too many connecting sockets" },
+    { PJ_EINVAL,        "Invalid value or argument" },
+    { PJ_ENAMETOOLONG,  "Name too long" },
+    { PJ_ENOTFOUND,     "Not found" },
+    { PJ_ENOMEM,        "Not enough memory" },
+    { PJ_EBUG,          "BUG DETECTED!" },
+    { PJ_ETIMEDOUT,     "Operation timed out" },
+    { PJ_ETOOMANY,      "Too many objects of the specified type"},
+    { PJ_EBUSY,         "Object is busy"},
+    { PJ_ENOTSUP,	"Option/operation is not supported"},
+    { PJ_EINVALIDOP,	"Invalid operation"},
+    { PJ_ECANCELLED,    "Operation cancelled"},
+    { PJ_EEXISTS,       "Object already exists" }
+};
+
+/*
+ * pjlib_error()
+ *
+ * Retrieve message string for PJLIB's own error code.
+ */
+static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
+{
+    unsigned i;
+
+    for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
+        if (err_str[i].code == code) {
+            pj_size_t len = strlen(err_str[i].msg);
+            if (len >= size) len = size-1;
+            pj_memcpy(buf, err_str[i].msg, len);
+            buf[len] = '\0';
+            return len;
+        }
+    }
+
+    *buf++ = '?';
+    *buf++ = '?';
+    *buf++ = '?';
+    *buf++ = '\0';
+    return 3;
+}
+
+/*
+ * pj_strerror()
+ */
+PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, 
+			      char *buf, pj_size_t bufsize )
+{
+    int len = -1;
+    pj_str_t errstr;
+
+    if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
+        len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode);
+
+    } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
+        len = pjlib_error(statcode, buf, bufsize);
+
+    } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
+        len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
+
+    } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) {
+        len = pj_snprintf( buf, bufsize, "User error %d", statcode);
+
+    } else {
+        len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode);
+
+    }
+
+    if (len < 1) {
+        *buf = '\0';
+        len = 0;
+    }
+
+    errstr.ptr = buf;
+    errstr.slen = len;
+
+    return errstr;
+}
+
diff --git a/pjlib/src/pj/except.c b/pjlib/src/pj/except.c
index b58c8f7..ceaaad1 100644
--- a/pjlib/src/pj/except.c
+++ b/pjlib/src/pj/except.c
@@ -1,151 +1,151 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/except.h>

-#include <pj/os.h>

-#include <pj/assert.h>

-#include <pj/log.h>

-#include <pj/errno.h>

-

-static long thread_local_id = -1;

-

-#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0

-    static const char *exception_id_names[PJ_MAX_EXCEPTION_ID];

-#else

-    /*

-     * Start from 1 (not 0)!!!

-     * Exception 0 is reserved for normal path of setjmp()!!!

-     */

-    static int last_exception_id = 1;

-#endif  /* PJ_HAS_EXCEPTION_NAMES */

-

-

-PJ_DEF(void) pj_throw_exception_(int exception_id)

-{

-    struct pj_exception_state_t *handler;

-

-    handler = pj_thread_local_get(thread_local_id);

-    if (handler == NULL) {

-        PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id));

-        pj_assert(handler != NULL);

-        /* This will crash the system! */

-    }

-    pj_longjmp(handler->state, exception_id);

-}

-

-PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)

-{

-    struct pj_exception_state_t *parent_handler = NULL;

-

-    if (thread_local_id == -1) {

-	pj_thread_local_alloc(&thread_local_id);

-	pj_assert(thread_local_id != -1);

-    }

-    parent_handler = pj_thread_local_get(thread_local_id);

-    rec->prev = parent_handler;

-    pj_thread_local_set(thread_local_id, rec);

-}

-

-PJ_DEF(void) pj_pop_exception_handler_(void)

-{

-    struct pj_exception_state_t *handler;

-

-    handler = pj_thread_local_get(thread_local_id);

-    pj_assert(handler != NULL);

-    pj_thread_local_set(thread_local_id, handler->prev);

-}

-

-#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0

-PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,

-                                           pj_exception_id_t *id)

-{

-    unsigned i;

-

-    pj_enter_critical_section();

-

-    /*

-     * Start from 1 (not 0)!!!

-     * Exception 0 is reserved for normal path of setjmp()!!!

-     */

-    for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) {

-        if (exception_id_names[i] == NULL) {

-            exception_id_names[i] = name;

-            *id = i;

-            pj_leave_critical_section();

-            return PJ_SUCCESS;

-        }

-    }

-

-    pj_leave_critical_section();

-    return PJ_ETOOMANY;

-}

-

-PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )

-{

-    /*

-     * Start from 1 (not 0)!!!

-     * Exception 0 is reserved for normal path of setjmp()!!!

-     */

-    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL);

-    

-    pj_enter_critical_section();

-    exception_id_names[id] = NULL;

-    pj_leave_critical_section();

-

-    return PJ_SUCCESS;

-

-}

-

-PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)

-{

-    /*

-     * Start from 1 (not 0)!!!

-     * Exception 0 is reserved for normal path of setjmp()!!!

-     */

-    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>");

-

-    if (exception_id_names[id] == NULL)

-        return "<Unallocated ID>";

-

-    return exception_id_names[id];

-}

-

-#else   /* PJ_HAS_EXCEPTION_NAMES */

-PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,

-                                           pj_exception_id_t *id)

-{

-    PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY);

-

-    *id = last_exception_id++

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )

-{

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)

-{

-    return "";

-}

-

-#endif  /* PJ_HAS_EXCEPTION_NAMES */

-

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/except.h>
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/errno.h>
+
+static long thread_local_id = -1;
+
+#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
+    static const char *exception_id_names[PJ_MAX_EXCEPTION_ID];
+#else
+    /*
+     * Start from 1 (not 0)!!!
+     * Exception 0 is reserved for normal path of setjmp()!!!
+     */
+    static int last_exception_id = 1;
+#endif  /* PJ_HAS_EXCEPTION_NAMES */
+
+
+PJ_DEF(void) pj_throw_exception_(int exception_id)
+{
+    struct pj_exception_state_t *handler;
+
+    handler = pj_thread_local_get(thread_local_id);
+    if (handler == NULL) {
+        PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id));
+        pj_assert(handler != NULL);
+        /* This will crash the system! */
+    }
+    pj_longjmp(handler->state, exception_id);
+}
+
+PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)
+{
+    struct pj_exception_state_t *parent_handler = NULL;
+
+    if (thread_local_id == -1) {
+	pj_thread_local_alloc(&thread_local_id);
+	pj_assert(thread_local_id != -1);
+    }
+    parent_handler = pj_thread_local_get(thread_local_id);
+    rec->prev = parent_handler;
+    pj_thread_local_set(thread_local_id, rec);
+}
+
+PJ_DEF(void) pj_pop_exception_handler_(void)
+{
+    struct pj_exception_state_t *handler;
+
+    handler = pj_thread_local_get(thread_local_id);
+    pj_assert(handler != NULL);
+    pj_thread_local_set(thread_local_id, handler->prev);
+}
+
+#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
+PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
+                                           pj_exception_id_t *id)
+{
+    unsigned i;
+
+    pj_enter_critical_section();
+
+    /*
+     * Start from 1 (not 0)!!!
+     * Exception 0 is reserved for normal path of setjmp()!!!
+     */
+    for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) {
+        if (exception_id_names[i] == NULL) {
+            exception_id_names[i] = name;
+            *id = i;
+            pj_leave_critical_section();
+            return PJ_SUCCESS;
+        }
+    }
+
+    pj_leave_critical_section();
+    return PJ_ETOOMANY;
+}
+
+PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
+{
+    /*
+     * Start from 1 (not 0)!!!
+     * Exception 0 is reserved for normal path of setjmp()!!!
+     */
+    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL);
+    
+    pj_enter_critical_section();
+    exception_id_names[id] = NULL;
+    pj_leave_critical_section();
+
+    return PJ_SUCCESS;
+
+}
+
+PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
+{
+    /*
+     * Start from 1 (not 0)!!!
+     * Exception 0 is reserved for normal path of setjmp()!!!
+     */
+    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>");
+
+    if (exception_id_names[id] == NULL)
+        return "<Unallocated ID>";
+
+    return exception_id_names[id];
+}
+
+#else   /* PJ_HAS_EXCEPTION_NAMES */
+PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
+                                           pj_exception_id_t *id)
+{
+    PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY);
+
+    *id = last_exception_id++
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
+{
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
+{
+    return "";
+}
+
+#endif  /* PJ_HAS_EXCEPTION_NAMES */
+
+
+
diff --git a/pjlib/src/pj/extra-exports.c b/pjlib/src/pj/extra-exports.c
index f86ed31..05f7a3f 100644
--- a/pjlib/src/pj/extra-exports.c
+++ b/pjlib/src/pj/extra-exports.c
@@ -1,40 +1,40 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 <linux/module.h>

-#include <linux/syscalls.h>

-

-EXPORT_SYMBOL(sys_select);

-

-EXPORT_SYMBOL(sys_epoll_create);

-EXPORT_SYMBOL(sys_epoll_ctl);

-EXPORT_SYMBOL(sys_epoll_wait);

-

-EXPORT_SYMBOL(sys_socket);

-EXPORT_SYMBOL(sys_bind);

-EXPORT_SYMBOL(sys_getpeername);

-EXPORT_SYMBOL(sys_getsockname);

-EXPORT_SYMBOL(sys_sendto);

-EXPORT_SYMBOL(sys_recvfrom);

-EXPORT_SYMBOL(sys_getsockopt);

-EXPORT_SYMBOL(sys_setsockopt);

-EXPORT_SYMBOL(sys_listen);

-EXPORT_SYMBOL(sys_shutdown);

-EXPORT_SYMBOL(sys_connect);

-EXPORT_SYMBOL(sys_accept);

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 <linux/module.h>
+#include <linux/syscalls.h>
+
+EXPORT_SYMBOL(sys_select);
+
+EXPORT_SYMBOL(sys_epoll_create);
+EXPORT_SYMBOL(sys_epoll_ctl);
+EXPORT_SYMBOL(sys_epoll_wait);
+
+EXPORT_SYMBOL(sys_socket);
+EXPORT_SYMBOL(sys_bind);
+EXPORT_SYMBOL(sys_getpeername);
+EXPORT_SYMBOL(sys_getsockname);
+EXPORT_SYMBOL(sys_sendto);
+EXPORT_SYMBOL(sys_recvfrom);
+EXPORT_SYMBOL(sys_getsockopt);
+EXPORT_SYMBOL(sys_setsockopt);
+EXPORT_SYMBOL(sys_listen);
+EXPORT_SYMBOL(sys_shutdown);
+EXPORT_SYMBOL(sys_connect);
+EXPORT_SYMBOL(sys_accept);
+
diff --git a/pjlib/src/pj/fifobuf.c b/pjlib/src/pj/fifobuf.c
index 99b082e..00b48b6 100644
--- a/pjlib/src/pj/fifobuf.c
+++ b/pjlib/src/pj/fifobuf.c
@@ -1,193 +1,193 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/fifobuf.h>

-#include <pj/log.h>

-#include <pj/assert.h>

-#include <pj/os.h>

-

-#define THIS_FILE   "fifobuf"

-

-#define SZ  sizeof(unsigned)

-

-PJ_DEF(void)

-pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)

-{

-    PJ_CHECK_STACK();

-

-    PJ_LOG(6, (THIS_FILE, 

-	       "fifobuf_init fifobuf=%p buffer=%p, size=%d", 

-	       fifobuf, buffer, size));

-

-    fifobuf->first = buffer;

-    fifobuf->last = fifobuf->first + size;

-    fifobuf->ubegin = fifobuf->uend = fifobuf->first;

-    fifobuf->full = 0;

-}

-

-PJ_DEF(unsigned)

-pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)

-{

-    unsigned s1, s2;

-

-    PJ_CHECK_STACK();

-

-    if (fifobuf->uend >= fifobuf->ubegin) {

-	s1 = fifobuf->last - fifobuf->uend;

-	s2 = fifobuf->ubegin - fifobuf->first;

-    } else {

-	s1 = s2 = fifobuf->ubegin - fifobuf->uend;

-    }

-    

-    return s1<s2 ? s2 : s1;

-}

-

-PJ_DEF(void*)

-pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)

-{

-    unsigned available;

-    char *start;

-

-    PJ_CHECK_STACK();

-

-    if (fifobuf->full) {

-	PJ_LOG(6, (THIS_FILE, 

-		   "fifobuf_alloc fifobuf=%p, size=%d: full!", 

-		   fifobuf, size));

-	return NULL;

-    }

-

-    /* try to allocate from the end part of the fifo */

-    if (fifobuf->uend >= fifobuf->ubegin) {

-	available = fifobuf->last - fifobuf->uend;

-	if (available >= size+SZ) {

-	    char *ptr = fifobuf->uend;

-	    fifobuf->uend += (size+SZ);

-	    if (fifobuf->uend == fifobuf->last)

-		fifobuf->uend = fifobuf->first;

-	    if (fifobuf->uend == fifobuf->ubegin)

-		fifobuf->full = 1;

-	    *(unsigned*)ptr = size+SZ;

-	    ptr += SZ;

-

-	    PJ_LOG(6, (THIS_FILE, 

-		       "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 

-		       fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));

-	    return ptr;

-	}

-    }

-

-    /* try to allocate from the start part of the fifo */

-    start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;

-    available = fifobuf->ubegin - start;

-    if (available >= size+SZ) {

-	char *ptr = start;

-	fifobuf->uend = start + size + SZ;

-	if (fifobuf->uend == fifobuf->ubegin)

-	    fifobuf->full = 1;

-	*(unsigned*)ptr = size+SZ;

-	ptr += SZ;

-

-	PJ_LOG(6, (THIS_FILE, 

-		   "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 

-		   fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));

-	return ptr;

-    }

-

-    PJ_LOG(6, (THIS_FILE, 

-	       "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p", 

-	       fifobuf, size, fifobuf->ubegin, fifobuf->uend));

-    return NULL;

-}

-

-PJ_DEF(pj_status_t)

-pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)

-{

-    char *ptr = buf;

-    char *endptr;

-    unsigned sz;

-

-    PJ_CHECK_STACK();

-

-    ptr -= SZ;

-    sz = *(unsigned*)ptr;

-

-    endptr = fifobuf->uend;

-    if (endptr == fifobuf->first)

-	endptr = fifobuf->last;

-

-    if (ptr+sz != endptr) {

-	pj_assert(!"Invalid pointer to undo alloc");

-	return -1;

-    }

-

-    fifobuf->uend = ptr;

-    fifobuf->full = 0;

-

-    PJ_LOG(6, (THIS_FILE, 

-	       "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 

-	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));

-

-    return 0;

-}

-

-PJ_DEF(pj_status_t)

-pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)

-{

-    char *ptr = buf;

-    char *end;

-    unsigned sz;

-

-    PJ_CHECK_STACK();

-

-    ptr -= SZ;

-    if (ptr < fifobuf->first || ptr >= fifobuf->last) {

-	pj_assert(!"Invalid pointer to free");

-	return -1;

-    }

-

-    if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {

-	pj_assert(!"Invalid free() sequence!");

-	return -1;

-    }

-

-    end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;

-    sz = *(unsigned*)ptr;

-    if (ptr+sz > end) {

-	pj_assert(!"Invalid size!");

-	return -1;

-    }

-

-    fifobuf->ubegin = ptr + sz;

-

-    /* Rollover */

-    if (fifobuf->ubegin == fifobuf->last)

-	fifobuf->ubegin = fifobuf->first;

-

-    /* Reset if fifobuf is empty */

-    if (fifobuf->ubegin == fifobuf->uend)

-	fifobuf->ubegin = fifobuf->uend = fifobuf->first;

-

-    fifobuf->full = 0;

-

-    PJ_LOG(6, (THIS_FILE, 

-	       "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 

-	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));

-

-    return 0;

-}

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/fifobuf.h>
+#include <pj/log.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+
+#define THIS_FILE   "fifobuf"
+
+#define SZ  sizeof(unsigned)
+
+PJ_DEF(void)
+pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)
+{
+    PJ_CHECK_STACK();
+
+    PJ_LOG(6, (THIS_FILE, 
+	       "fifobuf_init fifobuf=%p buffer=%p, size=%d", 
+	       fifobuf, buffer, size));
+
+    fifobuf->first = buffer;
+    fifobuf->last = fifobuf->first + size;
+    fifobuf->ubegin = fifobuf->uend = fifobuf->first;
+    fifobuf->full = 0;
+}
+
+PJ_DEF(unsigned)
+pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)
+{
+    unsigned s1, s2;
+
+    PJ_CHECK_STACK();
+
+    if (fifobuf->uend >= fifobuf->ubegin) {
+	s1 = fifobuf->last - fifobuf->uend;
+	s2 = fifobuf->ubegin - fifobuf->first;
+    } else {
+	s1 = s2 = fifobuf->ubegin - fifobuf->uend;
+    }
+    
+    return s1<s2 ? s2 : s1;
+}
+
+PJ_DEF(void*)
+pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)
+{
+    unsigned available;
+    char *start;
+
+    PJ_CHECK_STACK();
+
+    if (fifobuf->full) {
+	PJ_LOG(6, (THIS_FILE, 
+		   "fifobuf_alloc fifobuf=%p, size=%d: full!", 
+		   fifobuf, size));
+	return NULL;
+    }
+
+    /* try to allocate from the end part of the fifo */
+    if (fifobuf->uend >= fifobuf->ubegin) {
+	available = fifobuf->last - fifobuf->uend;
+	if (available >= size+SZ) {
+	    char *ptr = fifobuf->uend;
+	    fifobuf->uend += (size+SZ);
+	    if (fifobuf->uend == fifobuf->last)
+		fifobuf->uend = fifobuf->first;
+	    if (fifobuf->uend == fifobuf->ubegin)
+		fifobuf->full = 1;
+	    *(unsigned*)ptr = size+SZ;
+	    ptr += SZ;
+
+	    PJ_LOG(6, (THIS_FILE, 
+		       "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 
+		       fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
+	    return ptr;
+	}
+    }
+
+    /* try to allocate from the start part of the fifo */
+    start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;
+    available = fifobuf->ubegin - start;
+    if (available >= size+SZ) {
+	char *ptr = start;
+	fifobuf->uend = start + size + SZ;
+	if (fifobuf->uend == fifobuf->ubegin)
+	    fifobuf->full = 1;
+	*(unsigned*)ptr = size+SZ;
+	ptr += SZ;
+
+	PJ_LOG(6, (THIS_FILE, 
+		   "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 
+		   fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
+	return ptr;
+    }
+
+    PJ_LOG(6, (THIS_FILE, 
+	       "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p", 
+	       fifobuf, size, fifobuf->ubegin, fifobuf->uend));
+    return NULL;
+}
+
+PJ_DEF(pj_status_t)
+pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)
+{
+    char *ptr = buf;
+    char *endptr;
+    unsigned sz;
+
+    PJ_CHECK_STACK();
+
+    ptr -= SZ;
+    sz = *(unsigned*)ptr;
+
+    endptr = fifobuf->uend;
+    if (endptr == fifobuf->first)
+	endptr = fifobuf->last;
+
+    if (ptr+sz != endptr) {
+	pj_assert(!"Invalid pointer to undo alloc");
+	return -1;
+    }
+
+    fifobuf->uend = ptr;
+    fifobuf->full = 0;
+
+    PJ_LOG(6, (THIS_FILE, 
+	       "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 
+	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
+
+    return 0;
+}
+
+PJ_DEF(pj_status_t)
+pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)
+{
+    char *ptr = buf;
+    char *end;
+    unsigned sz;
+
+    PJ_CHECK_STACK();
+
+    ptr -= SZ;
+    if (ptr < fifobuf->first || ptr >= fifobuf->last) {
+	pj_assert(!"Invalid pointer to free");
+	return -1;
+    }
+
+    if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {
+	pj_assert(!"Invalid free() sequence!");
+	return -1;
+    }
+
+    end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;
+    sz = *(unsigned*)ptr;
+    if (ptr+sz > end) {
+	pj_assert(!"Invalid size!");
+	return -1;
+    }
+
+    fifobuf->ubegin = ptr + sz;
+
+    /* Rollover */
+    if (fifobuf->ubegin == fifobuf->last)
+	fifobuf->ubegin = fifobuf->first;
+
+    /* Reset if fifobuf is empty */
+    if (fifobuf->ubegin == fifobuf->uend)
+	fifobuf->ubegin = fifobuf->uend = fifobuf->first;
+
+    fifobuf->full = 0;
+
+    PJ_LOG(6, (THIS_FILE, 
+	       "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 
+	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
+
+    return 0;
+}
diff --git a/pjlib/src/pj/file_access_unistd.c b/pjlib/src/pj/file_access_unistd.c
index ba5fa85..f456f19 100644
--- a/pjlib/src/pj/file_access_unistd.c
+++ b/pjlib/src/pj/file_access_unistd.c
@@ -1,113 +1,113 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/file_access.h>

-#include <pj/assert.h>

-#include <pj/errno.h>

-

-#include <sys/types.h>

-#include <sys/stat.h>

-#include <unistd.h>

-#include <stdio.h>	/* rename() */

-#include <errno.h>

-

-/*

- * pj_file_exists()

- */

-PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)

-{

-    struct stat buf;

-

-    PJ_ASSERT_RETURN(filename, 0);

-

-    if (stat(filename, &buf) != 0)

-	return 0;

-

-    return PJ_TRUE;

-}

-

-

-/*

- * pj_file_size()

- */

-PJ_DEF(pj_off_t) pj_file_size(const char *filename)

-{

-    struct stat buf;

-

-    PJ_ASSERT_RETURN(filename, -1);

-

-    if (stat(filename, &buf) != 0)

-	return -1;

-

-    return buf.st_size;

-}

-

-

-/*

- * pj_file_delete()

- */

-PJ_DEF(pj_status_t) pj_file_delete(const char *filename)

-{

-    PJ_ASSERT_RETURN(filename, PJ_EINVAL);

-

-    if (unlink(filename)!=0) {

-	return PJ_RETURN_OS_ERROR(errno);

-    }

-    return PJ_SUCCESS;

-}

-

-

-/*

- * pj_file_move()

- */

-PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)

-{

-    PJ_ASSERT_RETURN(oldname && newname, PJ_EINVAL);

-

-    if (rename(oldname, newname) != 0) {

-	return PJ_RETURN_OS_ERROR(errno);

-    }

-    return PJ_SUCCESS;

-}

-

-

-/*

- * pj_file_getstat()

- */

-PJ_DEF(pj_status_t) pj_file_getstat(const char *filename, 

-				    pj_file_stat *statbuf)

-{

-    struct stat buf;

-

-    PJ_ASSERT_RETURN(filename && statbuf, PJ_EINVAL);

-

-    if (stat(filename, &buf) != 0) {

-	return PJ_RETURN_OS_ERROR(errno);

-    }

-

-    statbuf->size = buf.st_size;

-    statbuf->ctime.sec = buf.st_ctime;

-    statbuf->ctime.msec = 0;

-    statbuf->mtime.sec = buf.st_mtime;

-    statbuf->mtime.msec = 0;

-    statbuf->atime.sec = buf.st_atime;

-    statbuf->atime.msec = 0;

-

-    return PJ_SUCCESS;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/file_access.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>	/* rename() */
+#include <errno.h>
+
+/*
+ * pj_file_exists()
+ */
+PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)
+{
+    struct stat buf;
+
+    PJ_ASSERT_RETURN(filename, 0);
+
+    if (stat(filename, &buf) != 0)
+	return 0;
+
+    return PJ_TRUE;
+}
+
+
+/*
+ * pj_file_size()
+ */
+PJ_DEF(pj_off_t) pj_file_size(const char *filename)
+{
+    struct stat buf;
+
+    PJ_ASSERT_RETURN(filename, -1);
+
+    if (stat(filename, &buf) != 0)
+	return -1;
+
+    return buf.st_size;
+}
+
+
+/*
+ * pj_file_delete()
+ */
+PJ_DEF(pj_status_t) pj_file_delete(const char *filename)
+{
+    PJ_ASSERT_RETURN(filename, PJ_EINVAL);
+
+    if (unlink(filename)!=0) {
+	return PJ_RETURN_OS_ERROR(errno);
+    }
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * pj_file_move()
+ */
+PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)
+{
+    PJ_ASSERT_RETURN(oldname && newname, PJ_EINVAL);
+
+    if (rename(oldname, newname) != 0) {
+	return PJ_RETURN_OS_ERROR(errno);
+    }
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * pj_file_getstat()
+ */
+PJ_DEF(pj_status_t) pj_file_getstat(const char *filename, 
+				    pj_file_stat *statbuf)
+{
+    struct stat buf;
+
+    PJ_ASSERT_RETURN(filename && statbuf, PJ_EINVAL);
+
+    if (stat(filename, &buf) != 0) {
+	return PJ_RETURN_OS_ERROR(errno);
+    }
+
+    statbuf->size = buf.st_size;
+    statbuf->ctime.sec = buf.st_ctime;
+    statbuf->ctime.msec = 0;
+    statbuf->mtime.sec = buf.st_mtime;
+    statbuf->mtime.msec = 0;
+    statbuf->atime.sec = buf.st_atime;
+    statbuf->atime.msec = 0;
+
+    return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/file_access_win32.c b/pjlib/src/pj/file_access_win32.c
index e8378bd..79eb1f8 100644
--- a/pjlib/src/pj/file_access_win32.c
+++ b/pjlib/src/pj/file_access_win32.c
@@ -1,189 +1,189 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/file_access.h>

-#include <pj/assert.h>

-#include <pj/errno.h>

-#include <windows.h>

-#include <time.h>

-

-/*

- * pj_file_exists()

- */

-PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)

-{

-    HANDLE hFile;

-

-    PJ_ASSERT_RETURN(filename != NULL, 0);

-

-    hFile = CreateFile(filename, READ_CONTROL, FILE_SHARE_READ, NULL,

-                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

-    if (hFile == INVALID_HANDLE_VALUE)

-        return 0;

-

-    CloseHandle(hFile);

-    return PJ_TRUE;

-}

-

-

-/*

- * pj_file_size()

- */

-PJ_DEF(pj_off_t) pj_file_size(const char *filename)

-{

-    HANDLE hFile;

-    DWORD sizeLo, sizeHi;

-    pj_off_t size;

-

-    PJ_ASSERT_RETURN(filename != NULL, -1);

-

-    hFile = CreateFile(filename, READ_CONTROL, 

-                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,

-                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

-    if (hFile == INVALID_HANDLE_VALUE)

-        return -1;

-

-    sizeLo = GetFileSize(hFile, &sizeHi);

-    if (sizeLo == INVALID_FILE_SIZE) {

-        DWORD dwStatus = GetLastError();

-        if (dwStatus != NO_ERROR) {

-            CloseHandle(hFile);

-            return -1;

-        }

-    }

-

-    size = sizeHi;

-    size = (size << 32) + sizeLo;

-

-    CloseHandle(hFile);

-    return size;

-}

-

-

-/*

- * pj_file_delete()

- */

-PJ_DEF(pj_status_t) pj_file_delete(const char *filename)

-{

-    PJ_ASSERT_RETURN(filename != NULL, PJ_EINVAL);

-

-    if (DeleteFile(filename) == FALSE)

-        return PJ_RETURN_OS_ERROR(GetLastError());

-

-    return PJ_SUCCESS;

-}

-

-

-/*

- * pj_file_move()

- */

-PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)

-{

-    BOOL rc;

-

-    PJ_ASSERT_RETURN(oldname!=NULL && newname!=NULL, PJ_EINVAL);

-

-#if PJ_WIN32_WINNT >= 0x0400

-    rc = MoveFileEx(oldname, newname, 

-                    MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING);

-#else

-    rc = MoveFile(oldname, newname);

-#endif

-

-    if (!rc)

-        return PJ_RETURN_OS_ERROR(GetLastError());

-

-    return PJ_SUCCESS;

-}

-

-

-static pj_status_t file_time_to_time_val(const FILETIME *file_time,

-                                         pj_time_val *time_val)

-{

-    SYSTEMTIME systemTime, localTime;

-    struct tm tm;

-

-    if (!FileTimeToSystemTime(file_time, &systemTime))

-        return -1;

-

-    if (!SystemTimeToTzSpecificLocalTime(NULL, &systemTime, &localTime))

-        return -1;

-

-    memset(&tm, 0, sizeof(struct tm));

-    tm.tm_year = localTime.wYear - 1900;

-    tm.tm_mon = localTime.wMonth - 1;

-    tm.tm_mday = localTime.wDay;

-    tm.tm_hour = localTime.wHour;

-    tm.tm_min = localTime.wMinute;

-    tm.tm_sec = localTime.wSecond;

-    tm.tm_isdst = 0;

-

-    time_val->sec = mktime(&tm);

-    if (time_val->sec == (time_t)-1)

-        return -1;

-

-    time_val->msec = localTime.wMilliseconds;

-

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_file_getstat()

- */

-PJ_DEF(pj_status_t) pj_file_getstat(const char *filename, pj_file_stat *stat)

-{

-    HANDLE hFile;

-    DWORD sizeLo, sizeHi;

-    FILETIME creationTime, accessTime, writeTime;

-

-    PJ_ASSERT_RETURN(filename!=NULL && stat!=NULL, PJ_EINVAL);

-

-    hFile = CreateFile(filename, READ_CONTROL, FILE_SHARE_READ, NULL,

-                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

-    if (hFile == INVALID_HANDLE_VALUE)

-        return PJ_RETURN_OS_ERROR(GetLastError());

-

-    sizeLo = GetFileSize(hFile, &sizeHi);

-    if (sizeLo == INVALID_FILE_SIZE) {

-        DWORD dwStatus = GetLastError();

-        if (dwStatus != NO_ERROR) {

-            CloseHandle(hFile);

-            return PJ_RETURN_OS_ERROR(dwStatus);

-        }

-    }

-

-    stat->size = sizeHi;

-    stat->size = (stat->size << 32) + sizeLo;

-

-    if (GetFileTime(hFile, &creationTime, &accessTime, &writeTime)==FALSE) {

-        DWORD dwStatus = GetLastError();

-        CloseHandle(hFile);

-        return PJ_RETURN_OS_ERROR(dwStatus);

-    }

-

-    CloseHandle(hFile);

-

-    if (file_time_to_time_val(&creationTime, &stat->ctime) != PJ_SUCCESS)

-        return PJ_RETURN_OS_ERROR(GetLastError());

-

-    file_time_to_time_val(&accessTime, &stat->atime);

-    file_time_to_time_val(&writeTime, &stat->mtime);

-

-    return PJ_SUCCESS;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/file_access.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <windows.h>
+#include <time.h>
+
+/*
+ * pj_file_exists()
+ */
+PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)
+{
+    HANDLE hFile;
+
+    PJ_ASSERT_RETURN(filename != NULL, 0);
+
+    hFile = CreateFile(filename, READ_CONTROL, FILE_SHARE_READ, NULL,
+                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+        return 0;
+
+    CloseHandle(hFile);
+    return PJ_TRUE;
+}
+
+
+/*
+ * pj_file_size()
+ */
+PJ_DEF(pj_off_t) pj_file_size(const char *filename)
+{
+    HANDLE hFile;
+    DWORD sizeLo, sizeHi;
+    pj_off_t size;
+
+    PJ_ASSERT_RETURN(filename != NULL, -1);
+
+    hFile = CreateFile(filename, READ_CONTROL, 
+                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+        return -1;
+
+    sizeLo = GetFileSize(hFile, &sizeHi);
+    if (sizeLo == INVALID_FILE_SIZE) {
+        DWORD dwStatus = GetLastError();
+        if (dwStatus != NO_ERROR) {
+            CloseHandle(hFile);
+            return -1;
+        }
+    }
+
+    size = sizeHi;
+    size = (size << 32) + sizeLo;
+
+    CloseHandle(hFile);
+    return size;
+}
+
+
+/*
+ * pj_file_delete()
+ */
+PJ_DEF(pj_status_t) pj_file_delete(const char *filename)
+{
+    PJ_ASSERT_RETURN(filename != NULL, PJ_EINVAL);
+
+    if (DeleteFile(filename) == FALSE)
+        return PJ_RETURN_OS_ERROR(GetLastError());
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * pj_file_move()
+ */
+PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)
+{
+    BOOL rc;
+
+    PJ_ASSERT_RETURN(oldname!=NULL && newname!=NULL, PJ_EINVAL);
+
+#if PJ_WIN32_WINNT >= 0x0400
+    rc = MoveFileEx(oldname, newname, 
+                    MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING);
+#else
+    rc = MoveFile(oldname, newname);
+#endif
+
+    if (!rc)
+        return PJ_RETURN_OS_ERROR(GetLastError());
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t file_time_to_time_val(const FILETIME *file_time,
+                                         pj_time_val *time_val)
+{
+    SYSTEMTIME systemTime, localTime;
+    struct tm tm;
+
+    if (!FileTimeToSystemTime(file_time, &systemTime))
+        return -1;
+
+    if (!SystemTimeToTzSpecificLocalTime(NULL, &systemTime, &localTime))
+        return -1;
+
+    memset(&tm, 0, sizeof(struct tm));
+    tm.tm_year = localTime.wYear - 1900;
+    tm.tm_mon = localTime.wMonth - 1;
+    tm.tm_mday = localTime.wDay;
+    tm.tm_hour = localTime.wHour;
+    tm.tm_min = localTime.wMinute;
+    tm.tm_sec = localTime.wSecond;
+    tm.tm_isdst = 0;
+
+    time_val->sec = mktime(&tm);
+    if (time_val->sec == (time_t)-1)
+        return -1;
+
+    time_val->msec = localTime.wMilliseconds;
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_file_getstat()
+ */
+PJ_DEF(pj_status_t) pj_file_getstat(const char *filename, pj_file_stat *stat)
+{
+    HANDLE hFile;
+    DWORD sizeLo, sizeHi;
+    FILETIME creationTime, accessTime, writeTime;
+
+    PJ_ASSERT_RETURN(filename!=NULL && stat!=NULL, PJ_EINVAL);
+
+    hFile = CreateFile(filename, READ_CONTROL, FILE_SHARE_READ, NULL,
+                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+        return PJ_RETURN_OS_ERROR(GetLastError());
+
+    sizeLo = GetFileSize(hFile, &sizeHi);
+    if (sizeLo == INVALID_FILE_SIZE) {
+        DWORD dwStatus = GetLastError();
+        if (dwStatus != NO_ERROR) {
+            CloseHandle(hFile);
+            return PJ_RETURN_OS_ERROR(dwStatus);
+        }
+    }
+
+    stat->size = sizeHi;
+    stat->size = (stat->size << 32) + sizeLo;
+
+    if (GetFileTime(hFile, &creationTime, &accessTime, &writeTime)==FALSE) {
+        DWORD dwStatus = GetLastError();
+        CloseHandle(hFile);
+        return PJ_RETURN_OS_ERROR(dwStatus);
+    }
+
+    CloseHandle(hFile);
+
+    if (file_time_to_time_val(&creationTime, &stat->ctime) != PJ_SUCCESS)
+        return PJ_RETURN_OS_ERROR(GetLastError());
+
+    file_time_to_time_val(&accessTime, &stat->atime);
+    file_time_to_time_val(&writeTime, &stat->mtime);
+
+    return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/file_io_ansi.c b/pjlib/src/pj/file_io_ansi.c
index 057af04..dafa329 100644
--- a/pjlib/src/pj/file_io_ansi.c
+++ b/pjlib/src/pj/file_io_ansi.c
@@ -1,157 +1,157 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/file_io.h>

-#include <pj/assert.h>

-#include <pj/errno.h>

-#include <stdio.h>

-#include <errno.h>

-

-PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,

-                                  const char *pathname, 

-                                  unsigned flags,

-                                  pj_oshandle_t *fd)

-{

-    char mode[8];

-    char *p = mode;

-

-    PJ_ASSERT_RETURN(pathname && fd, PJ_EINVAL);

-    PJ_UNUSED_ARG(pool);

-

-    if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {

-        if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {

-            *p++ = 'a';

-            if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY)

-                *p++ = '+';

-        } else {

-            /* This is invalid.

-             * Can not specify PJ_O_RDONLY with PJ_O_APPEND! 

-             */

-        }

-    } else {

-        if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {

-            *p++ = 'r';

-            if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY)

-                *p++ = '+';

-        } else {

-            *p++ = 'w';

-        }

-    }

-

-    if (p==mode)

-        return PJ_EINVAL;

-

-    *p++ = 'b';

-    *p++ = '\0';

-

-    *fd = fopen(pathname, mode);

-    if (*fd == NULL)

-        return PJ_RETURN_OS_ERROR(errno);

-    

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)

-{

-    PJ_ASSERT_RETURN(fd, PJ_EINVAL);

-    if (fclose((FILE*)fd) != 0)

-        return PJ_RETURN_OS_ERROR(errno);

-

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,

-                                   const void *data,

-                                   pj_ssize_t *size)

-{

-    size_t written;

-

-    clearerr((FILE*)fd);

-    written = fwrite(data, 1, *size, (FILE*)fd);

-    if (ferror((FILE*)fd)) {

-        *size = -1;

-        return PJ_RETURN_OS_ERROR(errno);

-    }

-

-    *size = written;

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,

-                                  void *data,

-                                  pj_ssize_t *size)

-{

-    size_t bytes;

-

-    clearerr((FILE*)fd);

-    bytes = fread(data, 1, *size, (FILE*)fd);

-    if (ferror((FILE*)fd)) {

-        *size = -1;

-        return PJ_RETURN_OS_ERROR(errno);

-    }

-

-    *size = bytes;

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)

-{

-    PJ_UNUSED_ARG(access);

-    return feof((FILE*)fd) ? PJ_TRUE : 0;

-}

-

-PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,

-                                    pj_off_t offset,

-                                    enum pj_file_seek_type whence)

-{

-    int mode;

-

-    switch (whence) {

-    case PJ_SEEK_SET:

-        mode = SEEK_SET; break;

-    case PJ_SEEK_CUR:

-        mode = SEEK_CUR; break;

-    case PJ_SEEK_END:

-        mode = SEEK_END; break;

-    default:

-        pj_assert(!"Invalid whence in file_setpos");

-        return PJ_EINVAL;

-    }

-

-    if (fseek((FILE*)fd, (long)offset, mode) != 0)

-        return PJ_RETURN_OS_ERROR(errno);

-

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,

-                                    pj_off_t *pos)

-{

-    long offset;

-

-    offset = ftell((FILE*)fd);

-    if (offset == -1) {

-        *pos = -1;

-        return PJ_RETURN_OS_ERROR(errno);

-    }

-

-    *pos = offset;

-    return PJ_SUCCESS;

-}

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/file_io.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <stdio.h>
+#include <errno.h>
+
+PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
+                                  const char *pathname, 
+                                  unsigned flags,
+                                  pj_oshandle_t *fd)
+{
+    char mode[8];
+    char *p = mode;
+
+    PJ_ASSERT_RETURN(pathname && fd, PJ_EINVAL);
+    PJ_UNUSED_ARG(pool);
+
+    if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
+        if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
+            *p++ = 'a';
+            if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY)
+                *p++ = '+';
+        } else {
+            /* This is invalid.
+             * Can not specify PJ_O_RDONLY with PJ_O_APPEND! 
+             */
+        }
+    } else {
+        if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {
+            *p++ = 'r';
+            if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY)
+                *p++ = '+';
+        } else {
+            *p++ = 'w';
+        }
+    }
+
+    if (p==mode)
+        return PJ_EINVAL;
+
+    *p++ = 'b';
+    *p++ = '\0';
+
+    *fd = fopen(pathname, mode);
+    if (*fd == NULL)
+        return PJ_RETURN_OS_ERROR(errno);
+    
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
+{
+    PJ_ASSERT_RETURN(fd, PJ_EINVAL);
+    if (fclose((FILE*)fd) != 0)
+        return PJ_RETURN_OS_ERROR(errno);
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
+                                   const void *data,
+                                   pj_ssize_t *size)
+{
+    size_t written;
+
+    clearerr((FILE*)fd);
+    written = fwrite(data, 1, *size, (FILE*)fd);
+    if (ferror((FILE*)fd)) {
+        *size = -1;
+        return PJ_RETURN_OS_ERROR(errno);
+    }
+
+    *size = written;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
+                                  void *data,
+                                  pj_ssize_t *size)
+{
+    size_t bytes;
+
+    clearerr((FILE*)fd);
+    bytes = fread(data, 1, *size, (FILE*)fd);
+    if (ferror((FILE*)fd)) {
+        *size = -1;
+        return PJ_RETURN_OS_ERROR(errno);
+    }
+
+    *size = bytes;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)
+{
+    PJ_UNUSED_ARG(access);
+    return feof((FILE*)fd) ? PJ_TRUE : 0;
+}
+
+PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
+                                    pj_off_t offset,
+                                    enum pj_file_seek_type whence)
+{
+    int mode;
+
+    switch (whence) {
+    case PJ_SEEK_SET:
+        mode = SEEK_SET; break;
+    case PJ_SEEK_CUR:
+        mode = SEEK_CUR; break;
+    case PJ_SEEK_END:
+        mode = SEEK_END; break;
+    default:
+        pj_assert(!"Invalid whence in file_setpos");
+        return PJ_EINVAL;
+    }
+
+    if (fseek((FILE*)fd, (long)offset, mode) != 0)
+        return PJ_RETURN_OS_ERROR(errno);
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
+                                    pj_off_t *pos)
+{
+    long offset;
+
+    offset = ftell((FILE*)fd);
+    if (offset == -1) {
+        *pos = -1;
+        return PJ_RETURN_OS_ERROR(errno);
+    }
+
+    *pos = offset;
+    return PJ_SUCCESS;
+}
+
+
diff --git a/pjlib/src/pj/file_io_win32.c b/pjlib/src/pj/file_io_win32.c
index 2f6e3cb..f7a4f16 100644
--- a/pjlib/src/pj/file_io_win32.c
+++ b/pjlib/src/pj/file_io_win32.c
@@ -1,203 +1,203 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/file_io.h>

-#include <pj/errno.h>

-#include <pj/assert.h>

-

-#include <windows.h>

-

-#ifndef INVALID_SET_FILE_POINTER

-#   define INVALID_SET_FILE_POINTER     ((DWORD)-1)

-#endif

-

-/**

- * Check for end-of-file condition on the specified descriptor.

- *

- * @param fd            The file descriptor.

- * @param access        The desired access.

- *

- * @return              Non-zero if file is EOF.

- */

-PJ_DECL(pj_bool_t) pj_file_eof(pj_oshandle_t fd, 

-                               enum pj_file_access access);

-

-

-PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,

-                                  const char *pathname, 

-                                  unsigned flags,

-                                  pj_oshandle_t *fd)

-{

-    HANDLE hFile;

-    DWORD dwDesiredAccess = 0;

-    DWORD dwShareMode = 0;

-    DWORD dwCreationDisposition = 0;

-    DWORD dwFlagsAndAttributes = 0;

-

-    PJ_UNUSED_ARG(pool);

-

-    PJ_ASSERT_RETURN(pathname!=NULL, PJ_EINVAL);

-

-    if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {

-        dwDesiredAccess |= GENERIC_WRITE;

-        if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {

-            dwDesiredAccess |= FILE_APPEND_DATA;

-        } else {

-            dwDesiredAccess &= ~(FILE_APPEND_DATA);

-            dwCreationDisposition |= CREATE_ALWAYS;

-        }

-    }

-    if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {

-        dwDesiredAccess |= GENERIC_READ;

-        if (flags == PJ_O_RDONLY)

-            dwCreationDisposition |= OPEN_EXISTING;

-    }

-

-    if (dwDesiredAccess == 0) {

-        pj_assert(!"Invalid file open flags");

-        return PJ_EINVAL;

-    }

-

-    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;

-    dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;

-

-    hFile = CreateFile(pathname, dwDesiredAccess, dwShareMode, NULL,

-                       dwCreationDisposition, dwFlagsAndAttributes, NULL);

-    if (hFile == INVALID_HANDLE_VALUE) {

-        *fd = 0;

-        return PJ_RETURN_OS_ERROR(GetLastError());

-    }

-

-    *fd = hFile;

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)

-{

-    if (CloseHandle(fd)==0)

-        return PJ_RETURN_OS_ERROR(GetLastError());

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,

-                                   const void *data,

-                                   pj_ssize_t *size)

-{

-    BOOL rc;

-    DWORD bytesWritten;

-

-    rc = WriteFile(fd, data, *size, &bytesWritten, NULL);

-    if (!rc) {

-        *size = -1;

-        return PJ_RETURN_OS_ERROR(GetLastError());

-    }

-

-    *size = bytesWritten;

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,

-                                  void *data,

-                                  pj_ssize_t *size)

-{

-    BOOL rc;

-    DWORD bytesRead;

-

-    rc = ReadFile(fd, data, *size, &bytesRead, NULL);

-    if (!rc) {

-        *size = -1;

-        return PJ_RETURN_OS_ERROR(GetLastError());

-    }

-

-    *size = bytesRead;

-    return PJ_SUCCESS;

-}

-

-/*

-PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)

-{

-    BOOL rc;

-    DWORD dummy = 0, bytes;

-    DWORD dwStatus;

-

-    if ((access & PJ_O_RDONLY) == PJ_O_RDONLY) {

-        rc = ReadFile(fd, &dummy, 0, &bytes, NULL);

-    } else if ((access & PJ_O_WRONLY) == PJ_O_WRONLY) {

-        rc = WriteFile(fd, &dummy, 0, &bytes, NULL);

-    } else {

-        pj_assert(!"Invalid access");

-        return PJ_TRUE;

-    }

-

-    dwStatus = GetLastError();

-    if (dwStatus==ERROR_HANDLE_EOF)

-        return PJ_TRUE;

-

-    return 0;

-}

-*/

-

-PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,

-                                    pj_off_t offset,

-                                    enum pj_file_seek_type whence)

-{

-    DWORD dwMoveMethod;

-    DWORD dwNewPos;

-    LONG  hi32;

-

-    if (whence == PJ_SEEK_SET)

-        dwMoveMethod = FILE_BEGIN;

-    else if (whence == PJ_SEEK_CUR)

-        dwMoveMethod = FILE_CURRENT;

-    else if (whence == PJ_SEEK_END)

-        dwMoveMethod = FILE_END;

-    else {

-        pj_assert(!"Invalid whence in file_setpos");

-        return PJ_EINVAL;

-    }

-

-    hi32 = (LONG)(offset >> 32);

-    dwNewPos = SetFilePointer(fd, (long)offset, &hi32, dwMoveMethod);

-    if (dwNewPos == (DWORD)INVALID_SET_FILE_POINTER) {

-        DWORD dwStatus = GetLastError();

-        if (dwStatus != 0)

-            return PJ_RETURN_OS_ERROR(dwStatus);

-        /* dwNewPos actually is not an error. */

-    }

-

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,

-                                    pj_off_t *pos)

-{

-    LONG hi32 = 0;

-    DWORD lo32;

-

-    lo32 = SetFilePointer(fd, 0, &hi32, FILE_CURRENT);

-    if (lo32 == (DWORD)INVALID_SET_FILE_POINTER) {

-        DWORD dwStatus = GetLastError();

-        if (dwStatus != 0)

-            return PJ_RETURN_OS_ERROR(dwStatus);

-    }

-

-    *pos = hi32;

-    *pos = (*pos << 32) + lo32;

-    return PJ_SUCCESS;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/file_io.h>
+#include <pj/errno.h>
+#include <pj/assert.h>
+
+#include <windows.h>
+
+#ifndef INVALID_SET_FILE_POINTER
+#   define INVALID_SET_FILE_POINTER     ((DWORD)-1)
+#endif
+
+/**
+ * Check for end-of-file condition on the specified descriptor.
+ *
+ * @param fd            The file descriptor.
+ * @param access        The desired access.
+ *
+ * @return              Non-zero if file is EOF.
+ */
+PJ_DECL(pj_bool_t) pj_file_eof(pj_oshandle_t fd, 
+                               enum pj_file_access access);
+
+
+PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
+                                  const char *pathname, 
+                                  unsigned flags,
+                                  pj_oshandle_t *fd)
+{
+    HANDLE hFile;
+    DWORD dwDesiredAccess = 0;
+    DWORD dwShareMode = 0;
+    DWORD dwCreationDisposition = 0;
+    DWORD dwFlagsAndAttributes = 0;
+
+    PJ_UNUSED_ARG(pool);
+
+    PJ_ASSERT_RETURN(pathname!=NULL, PJ_EINVAL);
+
+    if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
+        dwDesiredAccess |= GENERIC_WRITE;
+        if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
+            dwDesiredAccess |= FILE_APPEND_DATA;
+        } else {
+            dwDesiredAccess &= ~(FILE_APPEND_DATA);
+            dwCreationDisposition |= CREATE_ALWAYS;
+        }
+    }
+    if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {
+        dwDesiredAccess |= GENERIC_READ;
+        if (flags == PJ_O_RDONLY)
+            dwCreationDisposition |= OPEN_EXISTING;
+    }
+
+    if (dwDesiredAccess == 0) {
+        pj_assert(!"Invalid file open flags");
+        return PJ_EINVAL;
+    }
+
+    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+    dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+
+    hFile = CreateFile(pathname, dwDesiredAccess, dwShareMode, NULL,
+                       dwCreationDisposition, dwFlagsAndAttributes, NULL);
+    if (hFile == INVALID_HANDLE_VALUE) {
+        *fd = 0;
+        return PJ_RETURN_OS_ERROR(GetLastError());
+    }
+
+    *fd = hFile;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
+{
+    if (CloseHandle(fd)==0)
+        return PJ_RETURN_OS_ERROR(GetLastError());
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
+                                   const void *data,
+                                   pj_ssize_t *size)
+{
+    BOOL rc;
+    DWORD bytesWritten;
+
+    rc = WriteFile(fd, data, *size, &bytesWritten, NULL);
+    if (!rc) {
+        *size = -1;
+        return PJ_RETURN_OS_ERROR(GetLastError());
+    }
+
+    *size = bytesWritten;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
+                                  void *data,
+                                  pj_ssize_t *size)
+{
+    BOOL rc;
+    DWORD bytesRead;
+
+    rc = ReadFile(fd, data, *size, &bytesRead, NULL);
+    if (!rc) {
+        *size = -1;
+        return PJ_RETURN_OS_ERROR(GetLastError());
+    }
+
+    *size = bytesRead;
+    return PJ_SUCCESS;
+}
+
+/*
+PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)
+{
+    BOOL rc;
+    DWORD dummy = 0, bytes;
+    DWORD dwStatus;
+
+    if ((access & PJ_O_RDONLY) == PJ_O_RDONLY) {
+        rc = ReadFile(fd, &dummy, 0, &bytes, NULL);
+    } else if ((access & PJ_O_WRONLY) == PJ_O_WRONLY) {
+        rc = WriteFile(fd, &dummy, 0, &bytes, NULL);
+    } else {
+        pj_assert(!"Invalid access");
+        return PJ_TRUE;
+    }
+
+    dwStatus = GetLastError();
+    if (dwStatus==ERROR_HANDLE_EOF)
+        return PJ_TRUE;
+
+    return 0;
+}
+*/
+
+PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
+                                    pj_off_t offset,
+                                    enum pj_file_seek_type whence)
+{
+    DWORD dwMoveMethod;
+    DWORD dwNewPos;
+    LONG  hi32;
+
+    if (whence == PJ_SEEK_SET)
+        dwMoveMethod = FILE_BEGIN;
+    else if (whence == PJ_SEEK_CUR)
+        dwMoveMethod = FILE_CURRENT;
+    else if (whence == PJ_SEEK_END)
+        dwMoveMethod = FILE_END;
+    else {
+        pj_assert(!"Invalid whence in file_setpos");
+        return PJ_EINVAL;
+    }
+
+    hi32 = (LONG)(offset >> 32);
+    dwNewPos = SetFilePointer(fd, (long)offset, &hi32, dwMoveMethod);
+    if (dwNewPos == (DWORD)INVALID_SET_FILE_POINTER) {
+        DWORD dwStatus = GetLastError();
+        if (dwStatus != 0)
+            return PJ_RETURN_OS_ERROR(dwStatus);
+        /* dwNewPos actually is not an error. */
+    }
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
+                                    pj_off_t *pos)
+{
+    LONG hi32 = 0;
+    DWORD lo32;
+
+    lo32 = SetFilePointer(fd, 0, &hi32, FILE_CURRENT);
+    if (lo32 == (DWORD)INVALID_SET_FILE_POINTER) {
+        DWORD dwStatus = GetLastError();
+        if (dwStatus != 0)
+            return PJ_RETURN_OS_ERROR(dwStatus);
+    }
+
+    *pos = hi32;
+    *pos = (*pos << 32) + lo32;
+    return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/guid.c b/pjlib/src/pj/guid.c
index bd9343e..c804879 100644
--- a/pjlib/src/pj/guid.c
+++ b/pjlib/src/pj/guid.c
@@ -1,26 +1,26 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/guid.h>

-#include <pj/pool.h>

-

-PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str)

-{

-    str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);

-    pj_generate_unique_string(str);

-}

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/guid.h>
+#include <pj/pool.h>
+
+PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str)
+{
+    str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);
+    pj_generate_unique_string(str);
+}
diff --git a/pjlib/src/pj/guid_simple.c b/pjlib/src/pj/guid_simple.c
index d2b2556..300abac 100644
--- a/pjlib/src/pj/guid_simple.c
+++ b/pjlib/src/pj/guid_simple.c
@@ -1,67 +1,67 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/guid.h>

-#include <pj/os.h>

-#include <pj/rand.h>

-#include <pj/string.h>

-#include <pj/compat/sprintf.h>

-

-const unsigned PJ_GUID_STRING_LENGTH=20;

-

-static void init_mac_address(unsigned char mac_addr[16])

-{

-    unsigned long *ulval1 = (unsigned long*) &mac_addr[0];

-    unsigned short *usval1 = (unsigned short*) &mac_addr[4];

-

-    *ulval1 = pj_rand();

-    *usval1 = (unsigned short) pj_rand();

-}

-

-PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)

-{

-    static int guid_initialized;

-    static unsigned pid;

-    static char str_pid[5];

-    static unsigned char mac_addr[6];

-    static char str_mac_addr[16];

-    static unsigned clock_seq;

-

-    PJ_CHECK_STACK();

-

-    if (guid_initialized == 0) {

-	pid = pj_getpid();

-	init_mac_address(mac_addr);

-	clock_seq = 0;

-

-	sprintf(str_pid, "%04x", pid);

-	sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x",

-	    mac_addr[0], mac_addr[1], mac_addr[2],

-	    mac_addr[3], mac_addr[4], mac_addr[5]);

-

-	guid_initialized = 1;

-    }

-

-    strcpy(str->ptr, str_pid);

-    sprintf(str->ptr+4, "%04x", clock_seq++);

-    pj_memcpy(str->ptr+8, str_mac_addr, 12);

-    str->slen = 20;

-

-    return str;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/guid.h>
+#include <pj/os.h>
+#include <pj/rand.h>
+#include <pj/string.h>
+#include <pj/compat/sprintf.h>
+
+const unsigned PJ_GUID_STRING_LENGTH=20;
+
+static void init_mac_address(unsigned char mac_addr[16])
+{
+    unsigned long *ulval1 = (unsigned long*) &mac_addr[0];
+    unsigned short *usval1 = (unsigned short*) &mac_addr[4];
+
+    *ulval1 = pj_rand();
+    *usval1 = (unsigned short) pj_rand();
+}
+
+PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
+{
+    static int guid_initialized;
+    static unsigned pid;
+    static char str_pid[5];
+    static unsigned char mac_addr[6];
+    static char str_mac_addr[16];
+    static unsigned clock_seq;
+
+    PJ_CHECK_STACK();
+
+    if (guid_initialized == 0) {
+	pid = pj_getpid();
+	init_mac_address(mac_addr);
+	clock_seq = 0;
+
+	sprintf(str_pid, "%04x", pid);
+	sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x",
+	    mac_addr[0], mac_addr[1], mac_addr[2],
+	    mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	guid_initialized = 1;
+    }
+
+    strcpy(str->ptr, str_pid);
+    sprintf(str->ptr+4, "%04x", clock_seq++);
+    pj_memcpy(str->ptr+8, str_mac_addr, 12);
+    str->slen = 20;
+
+    return str;
+}
+
diff --git a/pjlib/src/pj/guid_win32.c b/pjlib/src/pj/guid_win32.c
index d35fbc7..0ffb355 100644
--- a/pjlib/src/pj/guid_win32.c
+++ b/pjlib/src/pj/guid_win32.c
@@ -1,68 +1,68 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/guid.h>

-#include <pj/string.h>

-#include <pj/sock.h>

-#include <windows.h>

-#include <objbase.h>

-#include <pj/os.h>

-

-

-const unsigned PJ_GUID_STRING_LENGTH=32;

-

-PJ_INLINE(void) hex2digit(unsigned value, char *p)

-{

-    static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',

-			 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

-    *p++ = hex[ (value & 0xF0) >> 4 ];

-    *p++ = hex[ (value & 0x0F) ];

-}

-

-static void guid_to_str( const GUID *guid, pj_str_t *str )

-{

-    unsigned i;

-    GUID guid_copy;

-    const unsigned char *src = (const unsigned char*)&guid_copy;

-    char *dst = str->ptr;

-

-    pj_memcpy(&guid_copy, guid, sizeof(*guid));

-    guid_copy.Data1 = pj_ntohl(guid_copy.Data1);

-    guid_copy.Data2 = pj_ntohs(guid_copy.Data2);

-    guid_copy.Data3 = pj_ntohs(guid_copy.Data3);

-

-    for (i=0; i<16; ++i) {

-	hex2digit( *src, dst );

-	dst += 2;

-	++src;

-    }

-    str->slen = 32;

-}

-

-

-PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)

-{

-    GUID guid;

-

-    PJ_CHECK_STACK();

-

-    CoCreateGuid(&guid);

-    guid_to_str( &guid, str );

-    return str;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/guid.h>
+#include <pj/string.h>
+#include <pj/sock.h>
+#include <windows.h>
+#include <objbase.h>
+#include <pj/os.h>
+
+
+const unsigned PJ_GUID_STRING_LENGTH=32;
+
+PJ_INLINE(void) hex2digit(unsigned value, char *p)
+{
+    static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+			 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+    *p++ = hex[ (value & 0xF0) >> 4 ];
+    *p++ = hex[ (value & 0x0F) ];
+}
+
+static void guid_to_str( const GUID *guid, pj_str_t *str )
+{
+    unsigned i;
+    GUID guid_copy;
+    const unsigned char *src = (const unsigned char*)&guid_copy;
+    char *dst = str->ptr;
+
+    pj_memcpy(&guid_copy, guid, sizeof(*guid));
+    guid_copy.Data1 = pj_ntohl(guid_copy.Data1);
+    guid_copy.Data2 = pj_ntohs(guid_copy.Data2);
+    guid_copy.Data3 = pj_ntohs(guid_copy.Data3);
+
+    for (i=0; i<16; ++i) {
+	hex2digit( *src, dst );
+	dst += 2;
+	++src;
+    }
+    str->slen = 32;
+}
+
+
+PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
+{
+    GUID guid;
+
+    PJ_CHECK_STACK();
+
+    CoCreateGuid(&guid);
+    guid_to_str( &guid, str );
+    return str;
+}
+
diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c
index 61b3cd8..28d6d0f 100644
--- a/pjlib/src/pj/hash.c
+++ b/pjlib/src/pj/hash.c
@@ -1,274 +1,274 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/hash.h>

-#include <pj/log.h>

-#include <pj/string.h>

-#include <pj/pool.h>

-#include <pj/os.h>

-#include <pj/ctype.h>

-

-/**

- * The hash multiplier used to calculate hash value.

- */

-#define PJ_HASH_MULTIPLIER	33

-

-

-struct pj_hash_entry

-{

-    struct pj_hash_entry *next;

-    const void *key;

-    pj_uint32_t hash;

-    pj_uint32_t keylen;

-    void *value;

-};

-

-

-struct pj_hash_table_t

-{

-    pj_hash_entry     **table;

-    unsigned		count, rows;

-    pj_hash_iterator_t	iterator;

-};

-

-

-

-PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen)

-{

-    PJ_CHECK_STACK();

-

-    if (keylen==PJ_HASH_KEY_STRING) {

-	const unsigned char *p = key;

-	for ( ; *p; ++p ) {

-	    hash = hash * PJ_HASH_MULTIPLIER + *p;

-	}

-	keylen = p - (const unsigned char*)key;

-    } else {

-	const unsigned char *p = key,

-			    *end = p + keylen;

-	for ( ; p!=end; ++p) {

-	    hash = hash * PJ_HASH_MULTIPLIER + *p;

-	}

-    }

-    return hash;

-}

-

-PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,

-                                          char *result,

-                                          const pj_str_t *key)

-{

-    long i;

-

-    for (i=0; i<key->slen; ++i) {

-	result[i] = (char)pj_tolower(key->ptr[i]);

-	hval = hval * PJ_HASH_MULTIPLIER + result[i];

-    }

-

-    return hval;

-}

-

-

-PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)

-{

-    pj_hash_table_t *h;

-    unsigned table_size;

-    

-    h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));

-    h->count = 0;

-

-    PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool)));

-

-    /* size must be 2^n - 1.

-       round-up the size to this rule, except when size is 2^n, then size

-       will be round-down to 2^n-1.

-     */

-    table_size = 8;

-    do {

-	table_size <<= 1;    

-    } while (table_size <= size);

-    table_size -= 1;

-    

-    h->rows = table_size;

-    h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));

-    return h;

-}

-

-static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, 

-				   const void *key, unsigned keylen,

-				   void *val)

-{

-    pj_uint32_t hash;

-    pj_hash_entry **p_entry, *entry;

-

-    hash=0;

-    if (keylen==PJ_HASH_KEY_STRING) {

-	const unsigned char *p = key;

-	for ( ; *p; ++p ) {

-	    hash = hash * PJ_HASH_MULTIPLIER + *p;

-	}

-	keylen = p - (const unsigned char*)key;

-    } else {

-	const unsigned char *p = key,

-			    *end = p + keylen;

-	for ( ; p!=end; ++p) {

-	    hash = hash * PJ_HASH_MULTIPLIER + *p;

-	}

-    }

-

-    /* scan the linked list */

-    for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry; 

-	 entry; 

-	 p_entry = &entry->next, entry = *p_entry)

-    {

-	if (entry->hash==hash && entry->keylen==keylen &&

-	    memcmp(entry->key, key, keylen)==0) 

-	{

-	    break;	

-	}

-    }

-

-    if (entry || val==NULL)

-	return p_entry;

-

-    /* create a new entry */

-    entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));

-    PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry, 

-			  pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));

-    entry->next = NULL;

-    entry->hash = hash;

-    entry->key = key;

-    entry->keylen = keylen;

-    entry->value = val;

-    *p_entry = entry;

-    

-    ++ht->count;

-    

-    return p_entry;

-}

-

-PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,

-			    const void *key, unsigned keylen )

-{

-    pj_hash_entry *entry;

-    entry = *find_entry( NULL, ht, key, keylen, NULL);

-    return entry ? entry->value : NULL;

-}

-

-PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,

-			  const void *key, unsigned keylen,

-			  void *value )

-{

-    pj_hash_entry **p_entry;

-

-    p_entry = find_entry( pool, ht, key, keylen, value );

-    if (*p_entry) {

-	if (value == NULL) {

-	    /* delete entry */

-	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));

-	    *p_entry = (*p_entry)->next;

-	    --ht->count;

-	    

-	} else {

-	    /* overwrite */

-	    (*p_entry)->value = value;

-	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));

-	}

-    }

-}

-

-PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht )

-{

-    return ht->count;

-}

-

-PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,

-					   pj_hash_iterator_t *it )

-{

-    it->index = 0;

-    it->entry = NULL;

-

-    for (; it->index < ht->rows; ++it->index) {

-	it->entry = ht->table[it->index];

-	if (it->entry) {

-	    break;

-	}

-    }

-

-    return it->entry ? it : NULL;

-}

-

-PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 

-					  pj_hash_iterator_t *it )

-{

-    it->entry = it->entry->next;

-    if (it->entry) {

-	return it;

-    }

-

-    for (++it->index; it->index < ht->rows; ++it->index) {

-	it->entry = ht->table[it->index];

-	if (it->entry) {

-	    break;

-	}

-    }

-

-    return it->entry ? it : NULL;

-}

-

-PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it )

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(ht);

-    return it->entry->value;

-}

-

-#if 0

-void pj_hash_dump_collision( pj_hash_table_t *ht )

-{

-    unsigned min=0xFFFFFFFF, max=0;

-    unsigned i;

-    char line[120];

-    int len, totlen = 0;

-

-    for (i=0; i<ht->rows; ++i) {

-	unsigned count = 0;    

-	pj_hash_entry *entry = ht->table[i];

-	while (entry) {

-	    ++count;

-	    entry = entry->next;

-	}

-	if (count < min)

-	    min = count;

-	if (count > max)

-	    max = count;

-	len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count);

-	if (len < 1)

-	    break;

-	totlen += len;

-

-	if ((i+1) % 10 == 0) {

-	    line[totlen] = '\0';

-	    PJ_LOG(4,(__FILE__, line));

-	}

-    }

-

-    PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max));

-}

-#endif

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/hash.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/pool.h>
+#include <pj/os.h>
+#include <pj/ctype.h>
+
+/**
+ * The hash multiplier used to calculate hash value.
+ */
+#define PJ_HASH_MULTIPLIER	33
+
+
+struct pj_hash_entry
+{
+    struct pj_hash_entry *next;
+    const void *key;
+    pj_uint32_t hash;
+    pj_uint32_t keylen;
+    void *value;
+};
+
+
+struct pj_hash_table_t
+{
+    pj_hash_entry     **table;
+    unsigned		count, rows;
+    pj_hash_iterator_t	iterator;
+};
+
+
+
+PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen)
+{
+    PJ_CHECK_STACK();
+
+    if (keylen==PJ_HASH_KEY_STRING) {
+	const unsigned char *p = key;
+	for ( ; *p; ++p ) {
+	    hash = hash * PJ_HASH_MULTIPLIER + *p;
+	}
+	keylen = p - (const unsigned char*)key;
+    } else {
+	const unsigned char *p = key,
+			    *end = p + keylen;
+	for ( ; p!=end; ++p) {
+	    hash = hash * PJ_HASH_MULTIPLIER + *p;
+	}
+    }
+    return hash;
+}
+
+PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,
+                                          char *result,
+                                          const pj_str_t *key)
+{
+    long i;
+
+    for (i=0; i<key->slen; ++i) {
+	result[i] = (char)pj_tolower(key->ptr[i]);
+	hval = hval * PJ_HASH_MULTIPLIER + result[i];
+    }
+
+    return hval;
+}
+
+
+PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)
+{
+    pj_hash_table_t *h;
+    unsigned table_size;
+    
+    h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));
+    h->count = 0;
+
+    PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool)));
+
+    /* size must be 2^n - 1.
+       round-up the size to this rule, except when size is 2^n, then size
+       will be round-down to 2^n-1.
+     */
+    table_size = 8;
+    do {
+	table_size <<= 1;    
+    } while (table_size <= size);
+    table_size -= 1;
+    
+    h->rows = table_size;
+    h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));
+    return h;
+}
+
+static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, 
+				   const void *key, unsigned keylen,
+				   void *val)
+{
+    pj_uint32_t hash;
+    pj_hash_entry **p_entry, *entry;
+
+    hash=0;
+    if (keylen==PJ_HASH_KEY_STRING) {
+	const unsigned char *p = key;
+	for ( ; *p; ++p ) {
+	    hash = hash * PJ_HASH_MULTIPLIER + *p;
+	}
+	keylen = p - (const unsigned char*)key;
+    } else {
+	const unsigned char *p = key,
+			    *end = p + keylen;
+	for ( ; p!=end; ++p) {
+	    hash = hash * PJ_HASH_MULTIPLIER + *p;
+	}
+    }
+
+    /* scan the linked list */
+    for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry; 
+	 entry; 
+	 p_entry = &entry->next, entry = *p_entry)
+    {
+	if (entry->hash==hash && entry->keylen==keylen &&
+	    memcmp(entry->key, key, keylen)==0) 
+	{
+	    break;	
+	}
+    }
+
+    if (entry || val==NULL)
+	return p_entry;
+
+    /* create a new entry */
+    entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
+    PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry, 
+			  pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));
+    entry->next = NULL;
+    entry->hash = hash;
+    entry->key = key;
+    entry->keylen = keylen;
+    entry->value = val;
+    *p_entry = entry;
+    
+    ++ht->count;
+    
+    return p_entry;
+}
+
+PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,
+			    const void *key, unsigned keylen )
+{
+    pj_hash_entry *entry;
+    entry = *find_entry( NULL, ht, key, keylen, NULL);
+    return entry ? entry->value : NULL;
+}
+
+PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
+			  const void *key, unsigned keylen,
+			  void *value )
+{
+    pj_hash_entry **p_entry;
+
+    p_entry = find_entry( pool, ht, key, keylen, value );
+    if (*p_entry) {
+	if (value == NULL) {
+	    /* delete entry */
+	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));
+	    *p_entry = (*p_entry)->next;
+	    --ht->count;
+	    
+	} else {
+	    /* overwrite */
+	    (*p_entry)->value = value;
+	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));
+	}
+    }
+}
+
+PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht )
+{
+    return ht->count;
+}
+
+PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,
+					   pj_hash_iterator_t *it )
+{
+    it->index = 0;
+    it->entry = NULL;
+
+    for (; it->index < ht->rows; ++it->index) {
+	it->entry = ht->table[it->index];
+	if (it->entry) {
+	    break;
+	}
+    }
+
+    return it->entry ? it : NULL;
+}
+
+PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 
+					  pj_hash_iterator_t *it )
+{
+    it->entry = it->entry->next;
+    if (it->entry) {
+	return it;
+    }
+
+    for (++it->index; it->index < ht->rows; ++it->index) {
+	it->entry = ht->table[it->index];
+	if (it->entry) {
+	    break;
+	}
+    }
+
+    return it->entry ? it : NULL;
+}
+
+PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it )
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(ht);
+    return it->entry->value;
+}
+
+#if 0
+void pj_hash_dump_collision( pj_hash_table_t *ht )
+{
+    unsigned min=0xFFFFFFFF, max=0;
+    unsigned i;
+    char line[120];
+    int len, totlen = 0;
+
+    for (i=0; i<ht->rows; ++i) {
+	unsigned count = 0;    
+	pj_hash_entry *entry = ht->table[i];
+	while (entry) {
+	    ++count;
+	    entry = entry->next;
+	}
+	if (count < min)
+	    min = count;
+	if (count > max)
+	    max = count;
+	len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count);
+	if (len < 1)
+	    break;
+	totlen += len;
+
+	if ((i+1) % 10 == 0) {
+	    line[totlen] = '\0';
+	    PJ_LOG(4,(__FILE__, line));
+	}
+    }
+
+    PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max));
+}
+#endif
+
+
diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c
index b383a31..285aefc 100644
--- a/pjlib/src/pj/ioqueue_common_abs.c
+++ b/pjlib/src/pj/ioqueue_common_abs.c
@@ -1,955 +1,955 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 

- */

-

-/*

- * ioqueue_common_abs.c

- *

- * This contains common functionalities to emulate proactor pattern with

- * various event dispatching mechanisms (e.g. select, epoll).

- *

- * This file will be included by the appropriate ioqueue implementation.

- * This file is NOT supposed to be compiled as stand-alone source.

- */

-

-static void ioqueue_init( pj_ioqueue_t *ioqueue )

-{

-    ioqueue->lock = NULL;

-    ioqueue->auto_delete_lock = 0;

-}

-

-static pj_status_t ioqueue_destroy(pj_ioqueue_t *ioqueue)

-{

-    if (ioqueue->auto_delete_lock && ioqueue->lock ) {

-	pj_lock_release(ioqueue->lock);

-        return pj_lock_destroy(ioqueue->lock);

-    } else

-        return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_set_lock()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 

-					 pj_lock_t *lock,

-					 pj_bool_t auto_delete )

-{

-    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);

-

-    if (ioqueue->auto_delete_lock && ioqueue->lock) {

-        pj_lock_destroy(ioqueue->lock);

-    }

-

-    ioqueue->lock = lock;

-    ioqueue->auto_delete_lock = auto_delete;

-

-    return PJ_SUCCESS;

-}

-

-static pj_status_t ioqueue_init_key( pj_pool_t *pool,

-                                     pj_ioqueue_t *ioqueue,

-                                     pj_ioqueue_key_t *key,

-                                     pj_sock_t sock,

-                                     void *user_data,

-                                     const pj_ioqueue_callback *cb)

-{

-    pj_status_t rc;

-    int optlen;

-

-    key->ioqueue = ioqueue;

-    key->fd = sock;

-    key->user_data = user_data;

-    pj_list_init(&key->read_list);

-    pj_list_init(&key->write_list);

-#if PJ_HAS_TCP

-    pj_list_init(&key->accept_list);

-#endif

-

-    /* Save callback. */

-    pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));

-

-    /* Get socket type. When socket type is datagram, some optimization

-     * will be performed during send to allow parallel send operations.

-     */

-    optlen = sizeof(key->fd_type);

-    rc = pj_sock_getsockopt(sock, PJ_SOL_SOCKET, PJ_SO_TYPE,

-                            &key->fd_type, &optlen);

-    if (rc != PJ_SUCCESS)

-        key->fd_type = PJ_SOCK_STREAM;

-

-    /* Create mutex for the key. */

-    rc = pj_mutex_create_simple(pool, NULL, &key->mutex);

-    

-    return rc;

-}

-

-static void ioqueue_destroy_key( pj_ioqueue_key_t *key )

-{

-    pj_mutex_destroy(key->mutex);

-}

-

-/*

- * pj_ioqueue_get_user_data()

- *

- * Obtain value associated with a key.

- */

-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )

-{

-    PJ_ASSERT_RETURN(key != NULL, NULL);

-    return key->user_data;

-}

-

-/*

- * pj_ioqueue_set_user_data()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,

-                                              void *user_data,

-                                              void **old_data)

-{

-    PJ_ASSERT_RETURN(key, PJ_EINVAL);

-

-    if (old_data)

-        *old_data = key->user_data;

-    key->user_data = user_data;

-

-    return PJ_SUCCESS;

-}

-

-PJ_INLINE(int) key_has_pending_write(pj_ioqueue_key_t *key)

-{

-    return !pj_list_empty(&key->write_list);

-}

-

-PJ_INLINE(int) key_has_pending_read(pj_ioqueue_key_t *key)

-{

-    return !pj_list_empty(&key->read_list);

-}

-

-PJ_INLINE(int) key_has_pending_accept(pj_ioqueue_key_t *key)

-{

-#if PJ_HAS_TCP

-    return !pj_list_empty(&key->accept_list);

-#else

-    return 0;

-#endif

-}

-

-PJ_INLINE(int) key_has_pending_connect(pj_ioqueue_key_t *key)

-{

-    return key->connecting;

-}

-

-

-/*

- * ioqueue_dispatch_event()

- *

- * Report occurence of an event in the key to be processed by the

- * framework.

- */

-void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)

-{

-    /* Lock the key. */

-    pj_mutex_lock(h->mutex);

-

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0

-    if (h->connecting) {

-	/* Completion of connect() operation */

-	pj_ssize_t bytes_transfered;

-

-	/* Clear operation. */

-	h->connecting = 0;

-

-        ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

-        ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);

-

-        /* Unlock; from this point we don't need to hold key's mutex. */

-        pj_mutex_unlock(h->mutex);

-

-#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)

-	/* from connect(2): 

-	 * On Linux, use getsockopt to read the SO_ERROR option at

-	 * level SOL_SOCKET to determine whether connect() completed

-	 * successfully (if SO_ERROR is zero).

-	 */

-	{

-	  int value;

-	  socklen_t vallen = sizeof(value);

-	  int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, 

-                               &value, &vallen);

-	  if (gs_rc != 0) {

-	    /* Argh!! What to do now??? 

-	     * Just indicate that the socket is connected. The

-	     * application will get error as soon as it tries to use

-	     * the socket to send/receive.

-	     */

-	    bytes_transfered = 0;

-	  } else {

-            bytes_transfered = value;

-	  }

- 	}

-#elif defined(PJ_WIN32) && PJ_WIN32!=0

-	bytes_transfered = 0; /* success */

-#else

-	/* Excellent information in D.J. Bernstein page:

-	 * http://cr.yp.to/docs/connect.html

-	 *

-	 * Seems like the most portable way of detecting connect()

-	 * failure is to call getpeername(). If socket is connected,

-	 * getpeername() will return 0. If the socket is not connected,

-	 * it will return ENOTCONN, and read(fd, &ch, 1) will produce

-	 * the right errno through error slippage. This is a combination

-	 * of suggestions from Douglas C. Schmidt and Ken Keys.

-	 */

-	int gp_rc;

-	struct sockaddr_in addr;

-	socklen_t addrlen = sizeof(addr);

-

-	gp_rc = getpeername(h->fd, (struct sockaddr*)&addr, &addrlen);

-	bytes_transfered = gp_rc;

-#endif

-

-	/* Call callback. */

-        if (h->cb.on_connect_complete)

-	    (*h->cb.on_connect_complete)(h, bytes_transfered);

-

-        /* Done. */

-

-    } else 

-#endif /* PJ_HAS_TCP */

-    if (key_has_pending_write(h)) {

-	/* Socket is writable. */

-        struct write_operation *write_op;

-        pj_ssize_t sent;

-        pj_status_t send_rc;

-

-        /* Get the first in the queue. */

-        write_op = h->write_list.next;

-

-        /* For datagrams, we can remove the write_op from the list

-         * so that send() can work in parallel.

-         */

-        if (h->fd_type == PJ_SOCK_DGRAM) {

-            pj_list_erase(write_op);

-            write_op->op = 0;

-

-            if (pj_list_empty(&h->write_list))

-                ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

-

-            pj_mutex_unlock(h->mutex);

-        }

-

-        /* Send the data. 

-         * Unfortunately we must do this while holding key's mutex, thus

-         * preventing parallel write on a single key.. :-((

-         */

-        sent = write_op->size - write_op->written;

-        if (write_op->op == PJ_IOQUEUE_OP_SEND) {

-            send_rc = pj_sock_send(h->fd, write_op->buf+write_op->written,

-                                   &sent, write_op->flags);

-        } else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {

-            send_rc = pj_sock_sendto(h->fd, 

-                                     write_op->buf+write_op->written,

-                                     &sent, write_op->flags,

-                                     &write_op->rmt_addr, 

-                                     write_op->rmt_addrlen);

-        } else {

-            pj_assert(!"Invalid operation type!");

-            send_rc = PJ_EBUG;

-        }

-

-        if (send_rc == PJ_SUCCESS) {

-            write_op->written += sent;

-        } else {

-            pj_assert(send_rc > 0);

-            write_op->written = -send_rc;

-        }

-

-        /* Are we finished with this buffer? */

-        if (send_rc!=PJ_SUCCESS || 

-            write_op->written == (pj_ssize_t)write_op->size ||

-            h->fd_type == PJ_SOCK_DGRAM) 

-        {

-            if (h->fd_type != PJ_SOCK_DGRAM) {

-                /* Write completion of the whole stream. */

-                pj_list_erase(write_op);

-                write_op->op = 0;

-

-                /* Clear operation if there's no more data to send. */

-                if (pj_list_empty(&h->write_list))

-                    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

-

-                /* No need to hold mutex anymore */

-                pj_mutex_unlock(h->mutex);

-            }

-

-	    /* Call callback. */

-            if (h->cb.on_write_complete) {

-	        (*h->cb.on_write_complete)(h, 

-                                           (pj_ioqueue_op_key_t*)write_op,

-                                           write_op->written);

-            }

-

-        } else {

-            pj_mutex_unlock(h->mutex);

-        }

-

-        /* Done. */

-    } else {

-        /*

-         * This is normal; execution may fall here when multiple threads

-         * are signalled for the same event, but only one thread eventually

-         * able to process the event.

-         */

-        pj_mutex_unlock(h->mutex);

-    }

-}

-

-void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )

-{

-    pj_status_t rc;

-

-    /* Lock the key. */

-    pj_mutex_lock(h->mutex);

-

-#   if PJ_HAS_TCP

-    if (!pj_list_empty(&h->accept_list)) {

-

-        struct accept_operation *accept_op;

-	

-        /* Get one accept operation from the list. */

-	accept_op = h->accept_list.next;

-        pj_list_erase(accept_op);

-        accept_op->op = 0;

-

-	/* Clear bit in fdset if there is no more pending accept */

-        if (pj_list_empty(&h->accept_list))

-            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);

-

-        /* Unlock; from this point we don't need to hold key's mutex. */

-        pj_mutex_unlock(h->mutex);

-

-	rc=pj_sock_accept(h->fd, accept_op->accept_fd, 

-                          accept_op->rmt_addr, accept_op->addrlen);

-	if (rc==PJ_SUCCESS && accept_op->local_addr) {

-	    rc = pj_sock_getsockname(*accept_op->accept_fd, 

-                                     accept_op->local_addr,

-				     accept_op->addrlen);

-	}

-

-	/* Call callback. */

-        if (h->cb.on_accept_complete) {

-	    (*h->cb.on_accept_complete)(h, 

-                                        (pj_ioqueue_op_key_t*)accept_op,

-                                        *accept_op->accept_fd, rc);

-	}

-

-    }

-    else

-#   endif

-    if (key_has_pending_read(h)) {

-        struct read_operation *read_op;

-        pj_ssize_t bytes_read;

-

-        /* Get one pending read operation from the list. */

-        read_op = h->read_list.next;

-        pj_list_erase(read_op);

-        read_op->op = 0;

-

-        /* Clear fdset if there is no pending read. */

-        if (pj_list_empty(&h->read_list))

-            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);

-

-        /* Unlock; from this point we don't need to hold key's mutex. */

-        pj_mutex_unlock(h->mutex);

-

-        bytes_read = read_op->size;

-

-	if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {

-	    rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read, 0,

-				  read_op->rmt_addr, 

-                                  read_op->rmt_addrlen);

-	} else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {

-	    rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);

-        } else {

-            pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);

-            /*

-             * User has specified pj_ioqueue_read().

-             * On Win32, we should do ReadFile(). But because we got

-             * here because of select() anyway, user must have put a

-             * socket descriptor on h->fd, which in this case we can

-             * just call pj_sock_recv() instead of ReadFile().

-             * On Unix, user may put a file in h->fd, so we'll have

-             * to call read() here.

-             * This may not compile on systems which doesn't have 

-             * read(). That's why we only specify PJ_LINUX here so

-             * that error is easier to catch.

-             */

-#	    if defined(PJ_WIN32) && PJ_WIN32 != 0

-                rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);

-                //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,

-                //              &bytes_read, NULL);

-#           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

-        }

-	

-	if (rc != PJ_SUCCESS) {

-#	    if defined(PJ_WIN32) && PJ_WIN32 != 0

-	    /* On Win32, for UDP, WSAECONNRESET on the receive side 

-	     * indicates that previous sending has triggered ICMP Port 

-	     * Unreachable message.

-	     * But we wouldn't know at this point which one of previous 

-	     * key that has triggered the error, since UDP socket can

-	     * be shared!

-	     * So we'll just ignore it!

-	     */

-

-	    if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {

-		//PJ_LOG(4,(THIS_FILE, 

-                //          "Ignored ICMP port unreach. on key=%p", h));

-	    }

-#	    endif

-

-            /* In any case we would report this to caller. */

-            bytes_read = -rc;

-	}

-

-	/* Call callback. */

-        if (h->cb.on_read_complete) {

-	    (*h->cb.on_read_complete)(h, 

-                                      (pj_ioqueue_op_key_t*)read_op,

-                                      bytes_read);

-        }

-

-    } else {

-        /*

-         * This is normal; execution may fall here when multiple threads

-         * are signalled for the same event, but only one thread eventually

-         * able to process the event.

-         */

-        pj_mutex_unlock(h->mutex);

-    }

-}

-

-

-void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue, 

-                                       pj_ioqueue_key_t *h )

-{

-    pj_mutex_lock(h->mutex);

-

-    if (!h->connecting) {

-        /* It is possible that more than one thread was woken up, thus

-         * the remaining thread will see h->connecting as zero because

-         * it has been processed by other thread.

-         */

-        pj_mutex_unlock(h->mutex);

-        return;

-    }

-

-    /* Clear operation. */

-    h->connecting = 0;

-

-    pj_mutex_unlock(h->mutex);

-

-    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

-    ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);

-

-    /* Call callback. */

-    if (h->cb.on_connect_complete)

-	(*h->cb.on_connect_complete)(h, -1);

-}

-

-/*

- * pj_ioqueue_recv()

- *

- * Start asynchronous recv() from the socket.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,

-                                      pj_ioqueue_op_key_t *op_key,

-				      void *buffer,

-				      pj_ssize_t *length,

-				      unsigned flags )

-{

-    struct read_operation *read_op;

-

-    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);

-    PJ_CHECK_STACK();

-

-    read_op = (struct read_operation*)op_key;

-    read_op->op = 0;

-

-    /* Try to see if there's data immediately available. 

-     */

-    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {

-	pj_status_t status;

-	pj_ssize_t size;

-

-	size = *length;

-	status = pj_sock_recv(key->fd, buffer, &size, flags);

-	if (status == PJ_SUCCESS) {

-	    /* Yes! Data is available! */

-	    *length = size;

-	    return PJ_SUCCESS;

-	} else {

-	    /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

-	     * the error to caller.

-	     */

-	    if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))

-		return status;

-	}

-    }

-

-    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

-

-    /*

-     * No data is immediately available.

-     * Must schedule asynchronous operation to the ioqueue.

-     */

-    read_op->op = PJ_IOQUEUE_OP_RECV;

-    read_op->buf = buffer;

-    read_op->size = *length;

-    read_op->flags = flags;

-

-    pj_mutex_lock(key->mutex);

-    pj_list_insert_before(&key->read_list, read_op);

-    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);

-    pj_mutex_unlock(key->mutex);

-

-    return PJ_EPENDING;

-}

-

-/*

- * pj_ioqueue_recvfrom()

- *

- * Start asynchronous recvfrom() from the socket.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,

-                                         pj_ioqueue_op_key_t *op_key,

-				         void *buffer,

-				         pj_ssize_t *length,

-                                         unsigned flags,

-				         pj_sockaddr_t *addr,

-				         int *addrlen)

-{

-    struct read_operation *read_op;

-

-    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);

-    PJ_CHECK_STACK();

-

-    read_op = (struct read_operation*)op_key;

-    read_op->op = 0;

-

-    /* Try to see if there's data immediately available. 

-     */

-    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {

-	pj_status_t status;

-	pj_ssize_t size;

-

-	size = *length;

-	status = pj_sock_recvfrom(key->fd, buffer, &size, flags,

-				  addr, addrlen);

-	if (status == PJ_SUCCESS) {

-	    /* Yes! Data is available! */

-	    *length = size;

-	    return PJ_SUCCESS;

-	} else {

-	    /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

-	     * the error to caller.

-	     */

-	    if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))

-		return status;

-	}

-    }

-

-    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

-

-    /*

-     * No data is immediately available.

-     * Must schedule asynchronous operation to the ioqueue.

-     */

-    read_op->op = PJ_IOQUEUE_OP_RECV_FROM;

-    read_op->buf = buffer;

-    read_op->size = *length;

-    read_op->flags = flags;

-    read_op->rmt_addr = addr;

-    read_op->rmt_addrlen = addrlen;

-

-    pj_mutex_lock(key->mutex);

-    pj_list_insert_before(&key->read_list, read_op);

-    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);

-    pj_mutex_unlock(key->mutex);

-

-    return PJ_EPENDING;

-}

-

-/*

- * pj_ioqueue_send()

- *

- * Start asynchronous send() to the descriptor.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,

-                                     pj_ioqueue_op_key_t *op_key,

-			             const void *data,

-			             pj_ssize_t *length,

-                                     unsigned flags)

-{

-    struct write_operation *write_op;

-    pj_status_t status;

-    pj_ssize_t sent;

-

-    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);

-    PJ_CHECK_STACK();

-

-    write_op = (struct write_operation*)op_key;

-    write_op->op = 0;

-

-    /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write. */

-    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

-

-    /* Fast track:

-     *   Try to send data immediately, only if there's no pending write!

-     * Note:

-     *  We are speculating that the list is empty here without properly

-     *  acquiring ioqueue's mutex first. This is intentional, to maximize

-     *  performance via parallelism.

-     *

-     *  This should be safe, because:

-     *      - by convention, we require caller to make sure that the

-     *        key is not unregistered while other threads are invoking

-     *        an operation on the same key.

-     *      - pj_list_empty() is safe to be invoked by multiple threads,

-     *        even when other threads are modifying the list.

-     */

-    if (pj_list_empty(&key->write_list)) {

-        /*

-         * See if data can be sent immediately.

-         */

-        sent = *length;

-        status = pj_sock_send(key->fd, data, &sent, flags);

-        if (status == PJ_SUCCESS) {

-            /* Success! */

-            *length = sent;

-            return PJ_SUCCESS;

-        } else {

-            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

-             * the error to caller.

-             */

-            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {

-                return status;

-            }

-        }

-    }

-

-    /*

-     * Schedule asynchronous send.

-     */

-    write_op->op = PJ_IOQUEUE_OP_SEND;

-    write_op->buf = (void*)data;

-    write_op->size = *length;

-    write_op->written = 0;

-    write_op->flags = flags;

-    

-    pj_mutex_lock(key->mutex);

-    pj_list_insert_before(&key->write_list, write_op);

-    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);

-    pj_mutex_unlock(key->mutex);

-

-    return PJ_EPENDING;

-}

-

-

-/*

- * pj_ioqueue_sendto()

- *

- * Start asynchronous write() to the descriptor.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,

-                                       pj_ioqueue_op_key_t *op_key,

-			               const void *data,

-			               pj_ssize_t *length,

-                                       pj_uint32_t flags,

-			               const pj_sockaddr_t *addr,

-			               int addrlen)

-{

-    struct write_operation *write_op;

-    pj_status_t status;

-    pj_ssize_t sent;

-

-    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);

-    PJ_CHECK_STACK();

-

-    write_op = (struct write_operation*)op_key;

-    write_op->op = 0;

-

-    /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write */

-    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

-

-    /* Fast track:

-     *   Try to send data immediately, only if there's no pending write!

-     * Note:

-     *  We are speculating that the list is empty here without properly

-     *  acquiring ioqueue's mutex first. This is intentional, to maximize

-     *  performance via parallelism.

-     *

-     *  This should be safe, because:

-     *      - by convention, we require caller to make sure that the

-     *        key is not unregistered while other threads are invoking

-     *        an operation on the same key.

-     *      - pj_list_empty() is safe to be invoked by multiple threads,

-     *        even when other threads are modifying the list.

-     */

-    if (pj_list_empty(&key->write_list)) {

-        /*

-         * See if data can be sent immediately.

-         */

-        sent = *length;

-        status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);

-        if (status == PJ_SUCCESS) {

-            /* Success! */

-            *length = sent;

-            return PJ_SUCCESS;

-        } else {

-            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

-             * the error to caller.

-             */

-            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {

-                return status;

-            }

-        }

-    }

-

-    /*

-     * Check that address storage can hold the address parameter.

-     */

-    PJ_ASSERT_RETURN(addrlen <= sizeof(pj_sockaddr_in), PJ_EBUG);

-

-    /*

-     * Schedule asynchronous send.

-     */

-    write_op->op = PJ_IOQUEUE_OP_SEND_TO;

-    write_op->buf = (void*)data;

-    write_op->size = *length;

-    write_op->written = 0;

-    write_op->flags = flags;

-    pj_memcpy(&write_op->rmt_addr, addr, addrlen);

-    write_op->rmt_addrlen = addrlen;

-    

-    pj_mutex_lock(key->mutex);

-    pj_list_insert_before(&key->write_list, write_op);

-    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);

-    pj_mutex_unlock(key->mutex);

-

-    return PJ_EPENDING;

-}

-

-#if PJ_HAS_TCP

-/*

- * Initiate overlapped accept() operation.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,

-                                       pj_ioqueue_op_key_t *op_key,

-			               pj_sock_t *new_sock,

-			               pj_sockaddr_t *local,

-			               pj_sockaddr_t *remote,

-			               int *addrlen)

-{

-    struct accept_operation *accept_op;

-    pj_status_t status;

-

-    /* check parameters. All must be specified! */

-    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);

-

-    accept_op = (struct accept_operation*)op_key;

-    accept_op->op = 0;

-

-    /* Fast track:

-     *  See if there's new connection available immediately.

-     */

-    if (pj_list_empty(&key->accept_list)) {

-        status = pj_sock_accept(key->fd, new_sock, remote, addrlen);

-        if (status == PJ_SUCCESS) {

-            /* Yes! New connection is available! */

-            if (local && addrlen) {

-                status = pj_sock_getsockname(*new_sock, local, addrlen);

-                if (status != PJ_SUCCESS) {

-                    pj_sock_close(*new_sock);

-                    *new_sock = PJ_INVALID_SOCKET;

-                    return status;

-                }

-            }

-            return PJ_SUCCESS;

-        } else {

-            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

-             * the error to caller.

-             */

-            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {

-                return status;

-            }

-        }

-    }

-

-    /*

-     * No connection is available immediately.

-     * Schedule accept() operation to be completed when there is incoming

-     * connection available.

-     */

-    accept_op->op = PJ_IOQUEUE_OP_ACCEPT;

-    accept_op->accept_fd = new_sock;

-    accept_op->rmt_addr = remote;

-    accept_op->addrlen= addrlen;

-    accept_op->local_addr = local;

-

-    pj_mutex_lock(key->mutex);

-    pj_list_insert_before(&key->accept_list, accept_op);

-    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);

-    pj_mutex_unlock(key->mutex);

-

-    return PJ_EPENDING;

-}

-

-/*

- * 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_key_t *key,

-					const pj_sockaddr_t *addr,

-					int addrlen )

-{

-    pj_status_t status;

-    

-    /* check parameters. All must be specified! */

-    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);

-

-    /* Check if socket has not been marked for connecting */

-    if (key->connecting != 0)

-        return PJ_EPENDING;

-    

-    status = pj_sock_connect(key->fd, addr, addrlen);

-    if (status == PJ_SUCCESS) {

-	/* Connected! */

-	return PJ_SUCCESS;

-    } else {

-	if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {

-	    /* Pending! */

-            pj_mutex_lock(key->mutex);

-	    key->connecting = PJ_TRUE;

-            ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);

-            ioqueue_add_to_set(key->ioqueue, key->fd, EXCEPTION_EVENT);

-            pj_mutex_unlock(key->mutex);

-	    return PJ_EPENDING;

-	} else {

-	    /* Error! */

-	    return status;

-	}

-    }

-}

-#endif	/* PJ_HAS_TCP */

-

-

-PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,

-				     pj_size_t size )

-{

-    pj_memset(op_key, 0, size);

-}

-

-

-/*

- * pj_ioqueue_is_pending()

- */

-PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,

-                                         pj_ioqueue_op_key_t *op_key )

-{

-    struct generic_operation *op_rec;

-

-    PJ_UNUSED_ARG(key);

-

-    op_rec = (struct generic_operation*)op_key;

-    return op_rec->op != 0;

-}

-

-

-/*

- * pj_ioqueue_post_completion()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,

-                                                pj_ioqueue_op_key_t *op_key,

-                                                pj_ssize_t bytes_status )

-{

-    struct generic_operation *op_rec;

-

-    /*

-     * Find the operation key in all pending operation list to

-     * really make sure that it's still there; then call the callback.

-     */

-    pj_mutex_lock(key->mutex);

-

-    /* Find the operation in the pending read list. */

-    op_rec = (struct generic_operation*)key->read_list.next;

-    while (op_rec != (void*)&key->read_list) {

-        if (op_rec == (void*)op_key) {

-            pj_list_erase(op_rec);

-            op_rec->op = 0;

-            pj_mutex_unlock(key->mutex);

-

-            (*key->cb.on_read_complete)(key, op_key, bytes_status);

-            return PJ_SUCCESS;

-        }

-        op_rec = op_rec->next;

-    }

-

-    /* Find the operation in the pending write list. */

-    op_rec = (struct generic_operation*)key->write_list.next;

-    while (op_rec != (void*)&key->write_list) {

-        if (op_rec == (void*)op_key) {

-            pj_list_erase(op_rec);

-            op_rec->op = 0;

-            pj_mutex_unlock(key->mutex);

-

-            (*key->cb.on_write_complete)(key, op_key, bytes_status);

-            return PJ_SUCCESS;

-        }

-        op_rec = op_rec->next;

-    }

-

-    /* Find the operation in the pending accept list. */

-    op_rec = (struct generic_operation*)key->accept_list.next;

-    while (op_rec != (void*)&key->accept_list) {

-        if (op_rec == (void*)op_key) {

-            pj_list_erase(op_rec);

-            op_rec->op = 0;

-            pj_mutex_unlock(key->mutex);

-

-            (*key->cb.on_accept_complete)(key, op_key, 

-                                          PJ_INVALID_SOCKET,

-                                          bytes_status);

-            return PJ_SUCCESS;

-        }

-        op_rec = op_rec->next;

-    }

-

-    pj_mutex_unlock(key->mutex);

-    

-    return PJ_EINVALIDOP;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 
+ */
+
+/*
+ * ioqueue_common_abs.c
+ *
+ * This contains common functionalities to emulate proactor pattern with
+ * various event dispatching mechanisms (e.g. select, epoll).
+ *
+ * This file will be included by the appropriate ioqueue implementation.
+ * This file is NOT supposed to be compiled as stand-alone source.
+ */
+
+static void ioqueue_init( pj_ioqueue_t *ioqueue )
+{
+    ioqueue->lock = NULL;
+    ioqueue->auto_delete_lock = 0;
+}
+
+static pj_status_t ioqueue_destroy(pj_ioqueue_t *ioqueue)
+{
+    if (ioqueue->auto_delete_lock && ioqueue->lock ) {
+	pj_lock_release(ioqueue->lock);
+        return pj_lock_destroy(ioqueue->lock);
+    } else
+        return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_set_lock()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 
+					 pj_lock_t *lock,
+					 pj_bool_t auto_delete )
+{
+    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
+
+    if (ioqueue->auto_delete_lock && ioqueue->lock) {
+        pj_lock_destroy(ioqueue->lock);
+    }
+
+    ioqueue->lock = lock;
+    ioqueue->auto_delete_lock = auto_delete;
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t ioqueue_init_key( pj_pool_t *pool,
+                                     pj_ioqueue_t *ioqueue,
+                                     pj_ioqueue_key_t *key,
+                                     pj_sock_t sock,
+                                     void *user_data,
+                                     const pj_ioqueue_callback *cb)
+{
+    pj_status_t rc;
+    int optlen;
+
+    key->ioqueue = ioqueue;
+    key->fd = sock;
+    key->user_data = user_data;
+    pj_list_init(&key->read_list);
+    pj_list_init(&key->write_list);
+#if PJ_HAS_TCP
+    pj_list_init(&key->accept_list);
+#endif
+
+    /* Save callback. */
+    pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));
+
+    /* Get socket type. When socket type is datagram, some optimization
+     * will be performed during send to allow parallel send operations.
+     */
+    optlen = sizeof(key->fd_type);
+    rc = pj_sock_getsockopt(sock, PJ_SOL_SOCKET, PJ_SO_TYPE,
+                            &key->fd_type, &optlen);
+    if (rc != PJ_SUCCESS)
+        key->fd_type = PJ_SOCK_STREAM;
+
+    /* Create mutex for the key. */
+    rc = pj_mutex_create_simple(pool, NULL, &key->mutex);
+    
+    return rc;
+}
+
+static void ioqueue_destroy_key( pj_ioqueue_key_t *key )
+{
+    pj_mutex_destroy(key->mutex);
+}
+
+/*
+ * pj_ioqueue_get_user_data()
+ *
+ * Obtain value associated with a key.
+ */
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+    PJ_ASSERT_RETURN(key != NULL, NULL);
+    return key->user_data;
+}
+
+/*
+ * pj_ioqueue_set_user_data()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+                                              void *user_data,
+                                              void **old_data)
+{
+    PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+    if (old_data)
+        *old_data = key->user_data;
+    key->user_data = user_data;
+
+    return PJ_SUCCESS;
+}
+
+PJ_INLINE(int) key_has_pending_write(pj_ioqueue_key_t *key)
+{
+    return !pj_list_empty(&key->write_list);
+}
+
+PJ_INLINE(int) key_has_pending_read(pj_ioqueue_key_t *key)
+{
+    return !pj_list_empty(&key->read_list);
+}
+
+PJ_INLINE(int) key_has_pending_accept(pj_ioqueue_key_t *key)
+{
+#if PJ_HAS_TCP
+    return !pj_list_empty(&key->accept_list);
+#else
+    return 0;
+#endif
+}
+
+PJ_INLINE(int) key_has_pending_connect(pj_ioqueue_key_t *key)
+{
+    return key->connecting;
+}
+
+
+/*
+ * ioqueue_dispatch_event()
+ *
+ * Report occurence of an event in the key to be processed by the
+ * framework.
+ */
+void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
+{
+    /* Lock the key. */
+    pj_mutex_lock(h->mutex);
+
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
+    if (h->connecting) {
+	/* Completion of connect() operation */
+	pj_ssize_t bytes_transfered;
+
+	/* Clear operation. */
+	h->connecting = 0;
+
+        ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+        ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
+
+        /* Unlock; from this point we don't need to hold key's mutex. */
+        pj_mutex_unlock(h->mutex);
+
+#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)
+	/* from connect(2): 
+	 * On Linux, use getsockopt to read the SO_ERROR option at
+	 * level SOL_SOCKET to determine whether connect() completed
+	 * successfully (if SO_ERROR is zero).
+	 */
+	{
+	  int value;
+	  socklen_t vallen = sizeof(value);
+	  int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, 
+                               &value, &vallen);
+	  if (gs_rc != 0) {
+	    /* Argh!! What to do now??? 
+	     * Just indicate that the socket is connected. The
+	     * application will get error as soon as it tries to use
+	     * the socket to send/receive.
+	     */
+	    bytes_transfered = 0;
+	  } else {
+            bytes_transfered = value;
+	  }
+ 	}
+#elif defined(PJ_WIN32) && PJ_WIN32!=0
+	bytes_transfered = 0; /* success */
+#else
+	/* Excellent information in D.J. Bernstein page:
+	 * http://cr.yp.to/docs/connect.html
+	 *
+	 * Seems like the most portable way of detecting connect()
+	 * failure is to call getpeername(). If socket is connected,
+	 * getpeername() will return 0. If the socket is not connected,
+	 * it will return ENOTCONN, and read(fd, &ch, 1) will produce
+	 * the right errno through error slippage. This is a combination
+	 * of suggestions from Douglas C. Schmidt and Ken Keys.
+	 */
+	int gp_rc;
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(addr);
+
+	gp_rc = getpeername(h->fd, (struct sockaddr*)&addr, &addrlen);
+	bytes_transfered = gp_rc;
+#endif
+
+	/* Call callback. */
+        if (h->cb.on_connect_complete)
+	    (*h->cb.on_connect_complete)(h, bytes_transfered);
+
+        /* Done. */
+
+    } else 
+#endif /* PJ_HAS_TCP */
+    if (key_has_pending_write(h)) {
+	/* Socket is writable. */
+        struct write_operation *write_op;
+        pj_ssize_t sent;
+        pj_status_t send_rc;
+
+        /* Get the first in the queue. */
+        write_op = h->write_list.next;
+
+        /* For datagrams, we can remove the write_op from the list
+         * so that send() can work in parallel.
+         */
+        if (h->fd_type == PJ_SOCK_DGRAM) {
+            pj_list_erase(write_op);
+            write_op->op = 0;
+
+            if (pj_list_empty(&h->write_list))
+                ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+
+            pj_mutex_unlock(h->mutex);
+        }
+
+        /* Send the data. 
+         * Unfortunately we must do this while holding key's mutex, thus
+         * preventing parallel write on a single key.. :-((
+         */
+        sent = write_op->size - write_op->written;
+        if (write_op->op == PJ_IOQUEUE_OP_SEND) {
+            send_rc = pj_sock_send(h->fd, write_op->buf+write_op->written,
+                                   &sent, write_op->flags);
+        } else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {
+            send_rc = pj_sock_sendto(h->fd, 
+                                     write_op->buf+write_op->written,
+                                     &sent, write_op->flags,
+                                     &write_op->rmt_addr, 
+                                     write_op->rmt_addrlen);
+        } else {
+            pj_assert(!"Invalid operation type!");
+            send_rc = PJ_EBUG;
+        }
+
+        if (send_rc == PJ_SUCCESS) {
+            write_op->written += sent;
+        } else {
+            pj_assert(send_rc > 0);
+            write_op->written = -send_rc;
+        }
+
+        /* Are we finished with this buffer? */
+        if (send_rc!=PJ_SUCCESS || 
+            write_op->written == (pj_ssize_t)write_op->size ||
+            h->fd_type == PJ_SOCK_DGRAM) 
+        {
+            if (h->fd_type != PJ_SOCK_DGRAM) {
+                /* Write completion of the whole stream. */
+                pj_list_erase(write_op);
+                write_op->op = 0;
+
+                /* Clear operation if there's no more data to send. */
+                if (pj_list_empty(&h->write_list))
+                    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+
+                /* No need to hold mutex anymore */
+                pj_mutex_unlock(h->mutex);
+            }
+
+	    /* Call callback. */
+            if (h->cb.on_write_complete) {
+	        (*h->cb.on_write_complete)(h, 
+                                           (pj_ioqueue_op_key_t*)write_op,
+                                           write_op->written);
+            }
+
+        } else {
+            pj_mutex_unlock(h->mutex);
+        }
+
+        /* Done. */
+    } else {
+        /*
+         * This is normal; execution may fall here when multiple threads
+         * are signalled for the same event, but only one thread eventually
+         * able to process the event.
+         */
+        pj_mutex_unlock(h->mutex);
+    }
+}
+
+void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
+{
+    pj_status_t rc;
+
+    /* Lock the key. */
+    pj_mutex_lock(h->mutex);
+
+#   if PJ_HAS_TCP
+    if (!pj_list_empty(&h->accept_list)) {
+
+        struct accept_operation *accept_op;
+	
+        /* Get one accept operation from the list. */
+	accept_op = h->accept_list.next;
+        pj_list_erase(accept_op);
+        accept_op->op = 0;
+
+	/* Clear bit in fdset if there is no more pending accept */
+        if (pj_list_empty(&h->accept_list))
+            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
+
+        /* Unlock; from this point we don't need to hold key's mutex. */
+        pj_mutex_unlock(h->mutex);
+
+	rc=pj_sock_accept(h->fd, accept_op->accept_fd, 
+                          accept_op->rmt_addr, accept_op->addrlen);
+	if (rc==PJ_SUCCESS && accept_op->local_addr) {
+	    rc = pj_sock_getsockname(*accept_op->accept_fd, 
+                                     accept_op->local_addr,
+				     accept_op->addrlen);
+	}
+
+	/* Call callback. */
+        if (h->cb.on_accept_complete) {
+	    (*h->cb.on_accept_complete)(h, 
+                                        (pj_ioqueue_op_key_t*)accept_op,
+                                        *accept_op->accept_fd, rc);
+	}
+
+    }
+    else
+#   endif
+    if (key_has_pending_read(h)) {
+        struct read_operation *read_op;
+        pj_ssize_t bytes_read;
+
+        /* Get one pending read operation from the list. */
+        read_op = h->read_list.next;
+        pj_list_erase(read_op);
+        read_op->op = 0;
+
+        /* Clear fdset if there is no pending read. */
+        if (pj_list_empty(&h->read_list))
+            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
+
+        /* Unlock; from this point we don't need to hold key's mutex. */
+        pj_mutex_unlock(h->mutex);
+
+        bytes_read = read_op->size;
+
+	if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {
+	    rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read, 0,
+				  read_op->rmt_addr, 
+                                  read_op->rmt_addrlen);
+	} else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {
+	    rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
+        } else {
+            pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);
+            /*
+             * User has specified pj_ioqueue_read().
+             * On Win32, we should do ReadFile(). But because we got
+             * here because of select() anyway, user must have put a
+             * socket descriptor on h->fd, which in this case we can
+             * just call pj_sock_recv() instead of ReadFile().
+             * On Unix, user may put a file in h->fd, so we'll have
+             * to call read() here.
+             * This may not compile on systems which doesn't have 
+             * read(). That's why we only specify PJ_LINUX here so
+             * that error is easier to catch.
+             */
+#	    if defined(PJ_WIN32) && PJ_WIN32 != 0
+                rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
+                //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,
+                //              &bytes_read, NULL);
+#           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
+        }
+	
+	if (rc != PJ_SUCCESS) {
+#	    if defined(PJ_WIN32) && PJ_WIN32 != 0
+	    /* On Win32, for UDP, WSAECONNRESET on the receive side 
+	     * indicates that previous sending has triggered ICMP Port 
+	     * Unreachable message.
+	     * But we wouldn't know at this point which one of previous 
+	     * key that has triggered the error, since UDP socket can
+	     * be shared!
+	     * So we'll just ignore it!
+	     */
+
+	    if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {
+		//PJ_LOG(4,(THIS_FILE, 
+                //          "Ignored ICMP port unreach. on key=%p", h));
+	    }
+#	    endif
+
+            /* In any case we would report this to caller. */
+            bytes_read = -rc;
+	}
+
+	/* Call callback. */
+        if (h->cb.on_read_complete) {
+	    (*h->cb.on_read_complete)(h, 
+                                      (pj_ioqueue_op_key_t*)read_op,
+                                      bytes_read);
+        }
+
+    } else {
+        /*
+         * This is normal; execution may fall here when multiple threads
+         * are signalled for the same event, but only one thread eventually
+         * able to process the event.
+         */
+        pj_mutex_unlock(h->mutex);
+    }
+}
+
+
+void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue, 
+                                       pj_ioqueue_key_t *h )
+{
+    pj_mutex_lock(h->mutex);
+
+    if (!h->connecting) {
+        /* It is possible that more than one thread was woken up, thus
+         * the remaining thread will see h->connecting as zero because
+         * it has been processed by other thread.
+         */
+        pj_mutex_unlock(h->mutex);
+        return;
+    }
+
+    /* Clear operation. */
+    h->connecting = 0;
+
+    pj_mutex_unlock(h->mutex);
+
+    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
+    ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
+
+    /* Call callback. */
+    if (h->cb.on_connect_complete)
+	(*h->cb.on_connect_complete)(h, -1);
+}
+
+/*
+ * pj_ioqueue_recv()
+ *
+ * Start asynchronous recv() from the socket.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,
+                                      pj_ioqueue_op_key_t *op_key,
+				      void *buffer,
+				      pj_ssize_t *length,
+				      unsigned flags )
+{
+    struct read_operation *read_op;
+
+    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+    PJ_CHECK_STACK();
+
+    read_op = (struct read_operation*)op_key;
+    read_op->op = 0;
+
+    /* Try to see if there's data immediately available. 
+     */
+    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
+	pj_status_t status;
+	pj_ssize_t size;
+
+	size = *length;
+	status = pj_sock_recv(key->fd, buffer, &size, flags);
+	if (status == PJ_SUCCESS) {
+	    /* Yes! Data is available! */
+	    *length = size;
+	    return PJ_SUCCESS;
+	} else {
+	    /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+	     * the error to caller.
+	     */
+	    if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
+		return status;
+	}
+    }
+
+    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+    /*
+     * No data is immediately available.
+     * Must schedule asynchronous operation to the ioqueue.
+     */
+    read_op->op = PJ_IOQUEUE_OP_RECV;
+    read_op->buf = buffer;
+    read_op->size = *length;
+    read_op->flags = flags;
+
+    pj_mutex_lock(key->mutex);
+    pj_list_insert_before(&key->read_list, read_op);
+    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
+    pj_mutex_unlock(key->mutex);
+
+    return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_recvfrom()
+ *
+ * Start asynchronous recvfrom() from the socket.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
+                                         pj_ioqueue_op_key_t *op_key,
+				         void *buffer,
+				         pj_ssize_t *length,
+                                         unsigned flags,
+				         pj_sockaddr_t *addr,
+				         int *addrlen)
+{
+    struct read_operation *read_op;
+
+    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+    PJ_CHECK_STACK();
+
+    read_op = (struct read_operation*)op_key;
+    read_op->op = 0;
+
+    /* Try to see if there's data immediately available. 
+     */
+    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
+	pj_status_t status;
+	pj_ssize_t size;
+
+	size = *length;
+	status = pj_sock_recvfrom(key->fd, buffer, &size, flags,
+				  addr, addrlen);
+	if (status == PJ_SUCCESS) {
+	    /* Yes! Data is available! */
+	    *length = size;
+	    return PJ_SUCCESS;
+	} else {
+	    /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+	     * the error to caller.
+	     */
+	    if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
+		return status;
+	}
+    }
+
+    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+    /*
+     * No data is immediately available.
+     * Must schedule asynchronous operation to the ioqueue.
+     */
+    read_op->op = PJ_IOQUEUE_OP_RECV_FROM;
+    read_op->buf = buffer;
+    read_op->size = *length;
+    read_op->flags = flags;
+    read_op->rmt_addr = addr;
+    read_op->rmt_addrlen = addrlen;
+
+    pj_mutex_lock(key->mutex);
+    pj_list_insert_before(&key->read_list, read_op);
+    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
+    pj_mutex_unlock(key->mutex);
+
+    return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_send()
+ *
+ * Start asynchronous send() to the descriptor.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
+                                     pj_ioqueue_op_key_t *op_key,
+			             const void *data,
+			             pj_ssize_t *length,
+                                     unsigned flags)
+{
+    struct write_operation *write_op;
+    pj_status_t status;
+    pj_ssize_t sent;
+
+    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
+    PJ_CHECK_STACK();
+
+    write_op = (struct write_operation*)op_key;
+    write_op->op = 0;
+
+    /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write. */
+    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+    /* Fast track:
+     *   Try to send data immediately, only if there's no pending write!
+     * Note:
+     *  We are speculating that the list is empty here without properly
+     *  acquiring ioqueue's mutex first. This is intentional, to maximize
+     *  performance via parallelism.
+     *
+     *  This should be safe, because:
+     *      - by convention, we require caller to make sure that the
+     *        key is not unregistered while other threads are invoking
+     *        an operation on the same key.
+     *      - pj_list_empty() is safe to be invoked by multiple threads,
+     *        even when other threads are modifying the list.
+     */
+    if (pj_list_empty(&key->write_list)) {
+        /*
+         * See if data can be sent immediately.
+         */
+        sent = *length;
+        status = pj_sock_send(key->fd, data, &sent, flags);
+        if (status == PJ_SUCCESS) {
+            /* Success! */
+            *length = sent;
+            return PJ_SUCCESS;
+        } else {
+            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+             * the error to caller.
+             */
+            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+                return status;
+            }
+        }
+    }
+
+    /*
+     * Schedule asynchronous send.
+     */
+    write_op->op = PJ_IOQUEUE_OP_SEND;
+    write_op->buf = (void*)data;
+    write_op->size = *length;
+    write_op->written = 0;
+    write_op->flags = flags;
+    
+    pj_mutex_lock(key->mutex);
+    pj_list_insert_before(&key->write_list, write_op);
+    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
+    pj_mutex_unlock(key->mutex);
+
+    return PJ_EPENDING;
+}
+
+
+/*
+ * pj_ioqueue_sendto()
+ *
+ * Start asynchronous write() to the descriptor.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
+                                       pj_ioqueue_op_key_t *op_key,
+			               const void *data,
+			               pj_ssize_t *length,
+                                       pj_uint32_t flags,
+			               const pj_sockaddr_t *addr,
+			               int addrlen)
+{
+    struct write_operation *write_op;
+    pj_status_t status;
+    pj_ssize_t sent;
+
+    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
+    PJ_CHECK_STACK();
+
+    write_op = (struct write_operation*)op_key;
+    write_op->op = 0;
+
+    /* We can not use PJ_IOQUEUE_ALWAYS_ASYNC for socket write */
+    flags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+    /* Fast track:
+     *   Try to send data immediately, only if there's no pending write!
+     * Note:
+     *  We are speculating that the list is empty here without properly
+     *  acquiring ioqueue's mutex first. This is intentional, to maximize
+     *  performance via parallelism.
+     *
+     *  This should be safe, because:
+     *      - by convention, we require caller to make sure that the
+     *        key is not unregistered while other threads are invoking
+     *        an operation on the same key.
+     *      - pj_list_empty() is safe to be invoked by multiple threads,
+     *        even when other threads are modifying the list.
+     */
+    if (pj_list_empty(&key->write_list)) {
+        /*
+         * See if data can be sent immediately.
+         */
+        sent = *length;
+        status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);
+        if (status == PJ_SUCCESS) {
+            /* Success! */
+            *length = sent;
+            return PJ_SUCCESS;
+        } else {
+            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+             * the error to caller.
+             */
+            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+                return status;
+            }
+        }
+    }
+
+    /*
+     * Check that address storage can hold the address parameter.
+     */
+    PJ_ASSERT_RETURN(addrlen <= sizeof(pj_sockaddr_in), PJ_EBUG);
+
+    /*
+     * Schedule asynchronous send.
+     */
+    write_op->op = PJ_IOQUEUE_OP_SEND_TO;
+    write_op->buf = (void*)data;
+    write_op->size = *length;
+    write_op->written = 0;
+    write_op->flags = flags;
+    pj_memcpy(&write_op->rmt_addr, addr, addrlen);
+    write_op->rmt_addrlen = addrlen;
+    
+    pj_mutex_lock(key->mutex);
+    pj_list_insert_before(&key->write_list, write_op);
+    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
+    pj_mutex_unlock(key->mutex);
+
+    return PJ_EPENDING;
+}
+
+#if PJ_HAS_TCP
+/*
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
+                                       pj_ioqueue_op_key_t *op_key,
+			               pj_sock_t *new_sock,
+			               pj_sockaddr_t *local,
+			               pj_sockaddr_t *remote,
+			               int *addrlen)
+{
+    struct accept_operation *accept_op;
+    pj_status_t status;
+
+    /* check parameters. All must be specified! */
+    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
+
+    accept_op = (struct accept_operation*)op_key;
+    accept_op->op = 0;
+
+    /* Fast track:
+     *  See if there's new connection available immediately.
+     */
+    if (pj_list_empty(&key->accept_list)) {
+        status = pj_sock_accept(key->fd, new_sock, remote, addrlen);
+        if (status == PJ_SUCCESS) {
+            /* Yes! New connection is available! */
+            if (local && addrlen) {
+                status = pj_sock_getsockname(*new_sock, local, addrlen);
+                if (status != PJ_SUCCESS) {
+                    pj_sock_close(*new_sock);
+                    *new_sock = PJ_INVALID_SOCKET;
+                    return status;
+                }
+            }
+            return PJ_SUCCESS;
+        } else {
+            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
+             * the error to caller.
+             */
+            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
+                return status;
+            }
+        }
+    }
+
+    /*
+     * No connection is available immediately.
+     * Schedule accept() operation to be completed when there is incoming
+     * connection available.
+     */
+    accept_op->op = PJ_IOQUEUE_OP_ACCEPT;
+    accept_op->accept_fd = new_sock;
+    accept_op->rmt_addr = remote;
+    accept_op->addrlen= addrlen;
+    accept_op->local_addr = local;
+
+    pj_mutex_lock(key->mutex);
+    pj_list_insert_before(&key->accept_list, accept_op);
+    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
+    pj_mutex_unlock(key->mutex);
+
+    return PJ_EPENDING;
+}
+
+/*
+ * 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_key_t *key,
+					const pj_sockaddr_t *addr,
+					int addrlen )
+{
+    pj_status_t status;
+    
+    /* check parameters. All must be specified! */
+    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
+
+    /* Check if socket has not been marked for connecting */
+    if (key->connecting != 0)
+        return PJ_EPENDING;
+    
+    status = pj_sock_connect(key->fd, addr, addrlen);
+    if (status == PJ_SUCCESS) {
+	/* Connected! */
+	return PJ_SUCCESS;
+    } else {
+	if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {
+	    /* Pending! */
+            pj_mutex_lock(key->mutex);
+	    key->connecting = PJ_TRUE;
+            ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
+            ioqueue_add_to_set(key->ioqueue, key->fd, EXCEPTION_EVENT);
+            pj_mutex_unlock(key->mutex);
+	    return PJ_EPENDING;
+	} else {
+	    /* Error! */
+	    return status;
+	}
+    }
+}
+#endif	/* PJ_HAS_TCP */
+
+
+PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
+				     pj_size_t size )
+{
+    pj_memset(op_key, 0, size);
+}
+
+
+/*
+ * pj_ioqueue_is_pending()
+ */
+PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
+                                         pj_ioqueue_op_key_t *op_key )
+{
+    struct generic_operation *op_rec;
+
+    PJ_UNUSED_ARG(key);
+
+    op_rec = (struct generic_operation*)op_key;
+    return op_rec->op != 0;
+}
+
+
+/*
+ * pj_ioqueue_post_completion()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
+                                                pj_ioqueue_op_key_t *op_key,
+                                                pj_ssize_t bytes_status )
+{
+    struct generic_operation *op_rec;
+
+    /*
+     * Find the operation key in all pending operation list to
+     * really make sure that it's still there; then call the callback.
+     */
+    pj_mutex_lock(key->mutex);
+
+    /* Find the operation in the pending read list. */
+    op_rec = (struct generic_operation*)key->read_list.next;
+    while (op_rec != (void*)&key->read_list) {
+        if (op_rec == (void*)op_key) {
+            pj_list_erase(op_rec);
+            op_rec->op = 0;
+            pj_mutex_unlock(key->mutex);
+
+            (*key->cb.on_read_complete)(key, op_key, bytes_status);
+            return PJ_SUCCESS;
+        }
+        op_rec = op_rec->next;
+    }
+
+    /* Find the operation in the pending write list. */
+    op_rec = (struct generic_operation*)key->write_list.next;
+    while (op_rec != (void*)&key->write_list) {
+        if (op_rec == (void*)op_key) {
+            pj_list_erase(op_rec);
+            op_rec->op = 0;
+            pj_mutex_unlock(key->mutex);
+
+            (*key->cb.on_write_complete)(key, op_key, bytes_status);
+            return PJ_SUCCESS;
+        }
+        op_rec = op_rec->next;
+    }
+
+    /* Find the operation in the pending accept list. */
+    op_rec = (struct generic_operation*)key->accept_list.next;
+    while (op_rec != (void*)&key->accept_list) {
+        if (op_rec == (void*)op_key) {
+            pj_list_erase(op_rec);
+            op_rec->op = 0;
+            pj_mutex_unlock(key->mutex);
+
+            (*key->cb.on_accept_complete)(key, op_key, 
+                                          PJ_INVALID_SOCKET,
+                                          bytes_status);
+            return PJ_SUCCESS;
+        }
+        op_rec = op_rec->next;
+    }
+
+    pj_mutex_unlock(key->mutex);
+    
+    return PJ_EINVALIDOP;
+}
+
diff --git a/pjlib/src/pj/ioqueue_common_abs.h b/pjlib/src/pj/ioqueue_common_abs.h
index 9cb4ee2..8c3a1ff 100644
--- a/pjlib/src/pj/ioqueue_common_abs.h
+++ b/pjlib/src/pj/ioqueue_common_abs.h
@@ -1,125 +1,125 @@
-/* $Id */

-/* 

- * Copyright (C)2003-2006 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 

- */

-

-/* ioqueue_common_abs.h

- *

- * This file contains private declarations for abstracting various 

- * event polling/dispatching mechanisms (e.g. select, poll, epoll) 

- * to the ioqueue. 

- */

-

-#include <pj/list.h>

-

-/*

- * The select ioqueue relies on socket functions (pj_sock_xxx()) to return

- * the correct error code.

- */

-#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)

-#   error "Proper error reporting must be enabled for ioqueue to work!"

-#endif

-

-

-struct generic_operation

-{

-    PJ_DECL_LIST_MEMBER(struct generic_operation);

-    pj_ioqueue_operation_e  op;

-};

-

-struct read_operation

-{

-    PJ_DECL_LIST_MEMBER(struct read_operation);

-    pj_ioqueue_operation_e  op;

-

-    void		   *buf;

-    pj_size_t		    size;

-    unsigned                flags;

-    pj_sockaddr_t	   *rmt_addr;

-    int			   *rmt_addrlen;

-};

-

-struct write_operation

-{

-    PJ_DECL_LIST_MEMBER(struct write_operation);

-    pj_ioqueue_operation_e  op;

-

-    char		   *buf;

-    pj_size_t		    size;

-    pj_ssize_t              written;

-    unsigned                flags;

-    pj_sockaddr_in	    rmt_addr;

-    int			    rmt_addrlen;

-};

-

-#if PJ_HAS_TCP

-struct accept_operation

-{

-    PJ_DECL_LIST_MEMBER(struct accept_operation);

-    pj_ioqueue_operation_e  op;

-

-    pj_sock_t              *accept_fd;

-    pj_sockaddr_t	   *local_addr;

-    pj_sockaddr_t	   *rmt_addr;

-    int			   *addrlen;

-};

-#endif

-

-union operation_key

-{

-    struct generic_operation generic;

-    struct read_operation    read;

-    struct write_operation   write;

-#if PJ_HAS_TCP

-    struct accept_operation  accept;

-#endif

-};

-

-#define DECLARE_COMMON_KEY                          \

-    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t);   \

-    pj_ioqueue_t           *ioqueue;                \

-    pj_mutex_t             *mutex;                  \

-    pj_sock_t		    fd;                     \

-    int                     fd_type;                \

-    void		   *user_data;              \

-    pj_ioqueue_callback	    cb;                     \

-    int                     connecting;             \

-    struct read_operation   read_list;              \

-    struct write_operation  write_list;             \

-    struct accept_operation accept_list;

-

-

-#define DECLARE_COMMON_IOQUEUE                      \

-    pj_lock_t          *lock;                       \

-    pj_bool_t           auto_delete_lock;

-

-

-enum ioqueue_event_type

-{

-    NO_EVENT,

-    READABLE_EVENT,

-    WRITEABLE_EVENT,

-    EXCEPTION_EVENT,

-};

-

-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,

-                                pj_sock_t fd,

-                                enum ioqueue_event_type event_type );

-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,

-                                     pj_sock_t fd, 

-                                     enum ioqueue_event_type event_type);

-

+/* $Id */
+/* 
+ * Copyright (C)2003-2006 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 
+ */
+
+/* ioqueue_common_abs.h
+ *
+ * This file contains private declarations for abstracting various 
+ * event polling/dispatching mechanisms (e.g. select, poll, epoll) 
+ * to the ioqueue. 
+ */
+
+#include <pj/list.h>
+
+/*
+ * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
+ * the correct error code.
+ */
+#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
+#   error "Proper error reporting must be enabled for ioqueue to work!"
+#endif
+
+
+struct generic_operation
+{
+    PJ_DECL_LIST_MEMBER(struct generic_operation);
+    pj_ioqueue_operation_e  op;
+};
+
+struct read_operation
+{
+    PJ_DECL_LIST_MEMBER(struct read_operation);
+    pj_ioqueue_operation_e  op;
+
+    void		   *buf;
+    pj_size_t		    size;
+    unsigned                flags;
+    pj_sockaddr_t	   *rmt_addr;
+    int			   *rmt_addrlen;
+};
+
+struct write_operation
+{
+    PJ_DECL_LIST_MEMBER(struct write_operation);
+    pj_ioqueue_operation_e  op;
+
+    char		   *buf;
+    pj_size_t		    size;
+    pj_ssize_t              written;
+    unsigned                flags;
+    pj_sockaddr_in	    rmt_addr;
+    int			    rmt_addrlen;
+};
+
+#if PJ_HAS_TCP
+struct accept_operation
+{
+    PJ_DECL_LIST_MEMBER(struct accept_operation);
+    pj_ioqueue_operation_e  op;
+
+    pj_sock_t              *accept_fd;
+    pj_sockaddr_t	   *local_addr;
+    pj_sockaddr_t	   *rmt_addr;
+    int			   *addrlen;
+};
+#endif
+
+union operation_key
+{
+    struct generic_operation generic;
+    struct read_operation    read;
+    struct write_operation   write;
+#if PJ_HAS_TCP
+    struct accept_operation  accept;
+#endif
+};
+
+#define DECLARE_COMMON_KEY                          \
+    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t);   \
+    pj_ioqueue_t           *ioqueue;                \
+    pj_mutex_t             *mutex;                  \
+    pj_sock_t		    fd;                     \
+    int                     fd_type;                \
+    void		   *user_data;              \
+    pj_ioqueue_callback	    cb;                     \
+    int                     connecting;             \
+    struct read_operation   read_list;              \
+    struct write_operation  write_list;             \
+    struct accept_operation accept_list;
+
+
+#define DECLARE_COMMON_IOQUEUE                      \
+    pj_lock_t          *lock;                       \
+    pj_bool_t           auto_delete_lock;
+
+
+enum ioqueue_event_type
+{
+    NO_EVENT,
+    READABLE_EVENT,
+    WRITEABLE_EVENT,
+    EXCEPTION_EVENT,
+};
+
+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
+                                pj_sock_t fd,
+                                enum ioqueue_event_type event_type );
+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
+                                     pj_sock_t fd, 
+                                     enum ioqueue_event_type event_type);
+
diff --git a/pjlib/src/pj/ioqueue_dummy.c b/pjlib/src/pj/ioqueue_dummy.c
index 5f15e63..31a6c7d 100644
--- a/pjlib/src/pj/ioqueue_dummy.c
+++ b/pjlib/src/pj/ioqueue_dummy.c
@@ -1,193 +1,193 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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>

-#include <pj/errno.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_status_t) pj_ioqueue_create( pj_pool_t *pool, 

-				       pj_size_t max_fd,

-				       int max_threads,

-				       pj_ioqueue_t **ptr_ioqueue)

-{

-    return PJ_ENOTSUP;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)

-{

-    return PJ_ENOTSUP;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 

-					 pj_lock_t *lock,

-					 pj_bool_t auto_delete )

-{

-    return PJ_ENOTSUP;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

-					      pj_ioqueue_t *ioque,

-					      pj_sock_t sock,

-					      void *user_data,

-					      const pj_ioqueue_callback *cb,

-					      pj_ioqueue_key_t **ptr_key)

-{

-    return PJ_ENOTSUP;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,

-					   pj_ioqueue_key_t *key)

-{

-    return PJ_ENOTSUP;

-}

-

-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(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque,

-				     pj_ioqueue_key_t *key,

-				     void *buffer,

-				     pj_size_t buflen)

-{

-    return -1;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque,

-				     pj_ioqueue_key_t *key,

-				     void *buffer,

-				     pj_size_t buflen,

-				     unsigned flags)

-{

-    return -1;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,

-					 pj_ioqueue_key_t *key,

-					 void *buffer,

-					 pj_size_t buflen,

-					 unsigned flags,

-					 pj_sockaddr_t *addr,

-					 int *addrlen)

-{

-    return -1;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque,

-				      pj_ioqueue_key_t *key,

-				      const void *data,

-				      pj_size_t datalen)

-{

-    return -1;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque,

-				     pj_ioqueue_key_t *key,

-				     const void *data,

-				     pj_size_t datalen,

-				     unsigned flags)

-{

-    return -1;

-}

-

-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque,

-				       pj_ioqueue_key_t *key,

-				       const void *data,

-				       pj_size_t datalen,

-				       unsigned flags,

-				       const pj_sockaddr_t *addr,

-				       int addrlen)

-{

-    return -1;

-}

-

-#if PJ_HAS_TCP

-/*

- * Initiate overlapped accept() operation.

- */

-PJ_DEF(pj_status_t) 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 */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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>
+#include <pj/errno.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_status_t) pj_ioqueue_create( pj_pool_t *pool, 
+				       pj_size_t max_fd,
+				       int max_threads,
+				       pj_ioqueue_t **ptr_ioqueue)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 
+					 pj_lock_t *lock,
+					 pj_bool_t auto_delete )
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					      pj_ioqueue_t *ioque,
+					      pj_sock_t sock,
+					      void *user_data,
+					      const pj_ioqueue_callback *cb,
+					      pj_ioqueue_key_t **ptr_key)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
+					   pj_ioqueue_key_t *key)
+{
+    return PJ_ENOTSUP;
+}
+
+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(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque,
+				     pj_ioqueue_key_t *key,
+				     void *buffer,
+				     pj_size_t buflen)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque,
+				     pj_ioqueue_key_t *key,
+				     void *buffer,
+				     pj_size_t buflen,
+				     unsigned flags)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
+					 pj_ioqueue_key_t *key,
+					 void *buffer,
+					 pj_size_t buflen,
+					 unsigned flags,
+					 pj_sockaddr_t *addr,
+					 int *addrlen)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque,
+				      pj_ioqueue_key_t *key,
+				      const void *data,
+				      pj_size_t datalen)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque,
+				     pj_ioqueue_key_t *key,
+				     const void *data,
+				     pj_size_t datalen,
+				     unsigned flags)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
+				       pj_ioqueue_key_t *key,
+				       const void *data,
+				       pj_size_t datalen,
+				       unsigned flags,
+				       const pj_sockaddr_t *addr,
+				       int addrlen)
+{
+    return -1;
+}
+
+#if PJ_HAS_TCP
+/*
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(pj_status_t) 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 */
+
diff --git a/pjlib/src/pj/ioqueue_epoll.c b/pjlib/src/pj/ioqueue_epoll.c
index 3c80f00..780ea37 100644
--- a/pjlib/src/pj/ioqueue_epoll.c
+++ b/pjlib/src/pj/ioqueue_epoll.c
@@ -1,474 +1,474 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 

- */

-/*

- * ioqueue_epoll.c

- *

- * This is the implementation of IOQueue framework using /dev/epoll

- * API in _both_ Linux user-mode and kernel-mode.

- */

-

-#include <pj/ioqueue.h>

-#include <pj/os.h>

-#include <pj/lock.h>

-#include <pj/log.h>

-#include <pj/list.h>

-#include <pj/pool.h>

-#include <pj/string.h>

-#include <pj/assert.h>

-#include <pj/errno.h>

-#include <pj/sock.h>

-#include <pj/compat/socket.h>

-

-#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0

-    /*

-     * Linux user mode

-     */

-#   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 THIS_FILE   "ioq_epoll"

-

-//#define TRACE_(expr) PJ_LOG(3,expr)

-#define TRACE_(expr)

-

-/*

- * Include common ioqueue abstraction.

- */

-#include "ioqueue_common_abs.h"

-

-/*

- * This describes each key.

- */

-struct pj_ioqueue_key_t

-{

-    DECLARE_COMMON_KEY

-};

-

-/*

- * This describes the I/O queue.

- */

-struct pj_ioqueue_t

-{

-    DECLARE_COMMON_IOQUEUE

-

-    unsigned		max, count;

-    pj_ioqueue_key_t	hlist;

-    int			epfd;

-};

-

-/* Include implementation for common abstraction after we declare

- * pj_ioqueue_key_t and pj_ioqueue_t.

- */

-#include "ioqueue_common_abs.c"

-

-/*

- * pj_ioqueue_name()

- */

-PJ_DEF(const char*) pj_ioqueue_name(void)

-{

-#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0

-	return "epoll-kernel";

-#else

-	return "epoll";

-#endif

-}

-

-/*

- * pj_ioqueue_create()

- *

- * Create select ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

-                                       pj_size_t max_fd,

-                                       pj_ioqueue_t **p_ioqueue)

-{

-    pj_ioqueue_t *ioqueue;

-    pj_status_t rc;

-    pj_lock_t *lock;

-

-    /* Check that arguments are valid. */

-    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 

-                     max_fd > 0, PJ_EINVAL);

-

-    /* Check that size of pj_ioqueue_op_key_t is sufficient */

-    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=

-                     sizeof(union operation_key), PJ_EBUG);

-

-    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));

-

-    ioqueue_init(ioqueue);

-

-    ioqueue->max = max_fd;

-    ioqueue->count = 0;

-    pj_list_init(&ioqueue->hlist);

-

-    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);

-    if (rc != PJ_SUCCESS)

-	return rc;

-

-    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);

-    if (rc != PJ_SUCCESS)

-        return rc;

-

-    ioqueue->epfd = os_epoll_create(max_fd);

-    if (ioqueue->epfd < 0) {

-	ioqueue_destroy(ioqueue);

-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

-    }

-    

-    PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));

-

-    *p_ioqueue = ioqueue;

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_destroy()

- *

- * Destroy ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)

-{

-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

-    PJ_ASSERT_RETURN(ioqueue->epfd > 0, PJ_EINVALIDOP);

-

-    pj_lock_acquire(ioqueue->lock);

-    os_close(ioqueue->epfd);

-    ioqueue->epfd = 0;

-    return ioqueue_destroy(ioqueue);

-}

-

-/*

- * pj_ioqueue_register_sock()

- *

- * Register a socket to ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

-					      pj_ioqueue_t *ioqueue,

-					      pj_sock_t sock,

-					      void *user_data,

-					      const pj_ioqueue_callback *cb,

-                                              pj_ioqueue_key_t **p_key)

-{

-    pj_ioqueue_key_t *key = NULL;

-    pj_uint32_t value;

-    struct epoll_event ev;

-    int status;

-    pj_status_t rc = PJ_SUCCESS;

-    

-    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&

-                     cb && p_key, PJ_EINVAL);

-

-    pj_lock_acquire(ioqueue->lock);

-

-    if (ioqueue->count >= ioqueue->max) {

-        rc = PJ_ETOOMANY;

-	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files"));

-	goto on_return;

-    }

-

-    /* Set socket to nonblocking. */

-    value = 1;

-    if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) {

-	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d", 

-                rc));

-        rc = pj_get_netos_error();

-	goto on_return;

-    }

-

-    /* Create key. */

-    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));

-    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);

-    if (rc != PJ_SUCCESS) {

-	key = NULL;

-	goto on_return;

-    }

-

-    /* os_epoll_ctl. */

-    ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;

-    ev.epoll_data = (epoll_data_type)key;

-    status = os_epoll_ctl(ioqueue->epfd, EPOLL_CTL_ADD, sock, &ev);

-    if (status < 0) {

-	rc = pj_get_os_error();

-	key = NULL;

-	TRACE_((THIS_FILE, 

-                "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d", 

-                status));

-	goto on_return;

-    }

-    

-    /* Register */

-    pj_list_insert_before(&ioqueue->hlist, key);

-    ++ioqueue->count;

-

-on_return:

-    *p_key = key;

-    pj_lock_release(ioqueue->lock);

-    

-    return rc;

-}

-

-/*

- * pj_ioqueue_unregister()

- *

- * Unregister handle from ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)

-{

-    pj_ioqueue_t *ioqueue;

-    struct epoll_event ev;

-    int status;

-    

-    PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);

-

-    ioqueue = key->ioqueue;

-    pj_lock_acquire(ioqueue->lock);

-

-    pj_assert(ioqueue->count > 0);

-    --ioqueue->count;

-    pj_list_erase(key);

-

-    ev.events = 0;

-    ev.epoll_data = (epoll_data_type)key;

-    status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);

-    if (status != 0) {

-	pj_status_t rc = pj_get_os_error();

-	pj_lock_release(ioqueue->lock);

-	return rc;

-    }

-

-    pj_lock_release(ioqueue->lock);

-

-    /* Destroy the key. */

-    ioqueue_destroy_key(key);

-

-    return PJ_SUCCESS;

-}

-

-/* ioqueue_remove_from_set()

- * This function is called from ioqueue_dispatch_event() to instruct

- * the ioqueue to remove the specified descriptor from ioqueue's descriptor

- * set for the specified event.

- */

-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,

-                                     pj_sock_t fd, 

-                                     enum ioqueue_event_type event_type)

-{

-}

-

-/*

- * ioqueue_add_to_set()

- * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc

- * to instruct the ioqueue to add the specified handle to ioqueue's descriptor

- * set for the specified event.

- */

-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,

-                                pj_sock_t fd,

-                                enum ioqueue_event_type event_type )

-{

-}

-

-/*

- * pj_ioqueue_poll()

- *

- */

-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)

-{

-    int i, count, processed;

-    struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];

-    int msec;

-    struct queue {

-	pj_ioqueue_key_t	*key;

-	enum ioqueue_event_type	 event_type;

-    } queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];

-    

-    PJ_CHECK_STACK();

-

-    msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;

-    

-    count = os_epoll_wait( ioqueue->epfd, events, PJ_ARRAY_SIZE(events), msec);

-    if (count <= 0)

-	return count;

-

-    /* Lock ioqueue. */

-    pj_lock_acquire(ioqueue->lock);

-

-    for (processed=0, i=0; i<count; ++i) {

-	pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)

-				events[i].epoll_data;

-

-	/*

-	 * Check readability.

-	 */

-	if ((events[i].events & EPOLLIN) && 

-	    (key_has_pending_read(h) || key_has_pending_accept(h))) {

-	    queue[processed].key = h;

-	    queue[processed].event_type = READABLE_EVENT;

-	    ++processed;

-	}

-

-	/*

-	 * Check for writeability.

-	 */

-	if ((events[i].events & EPOLLOUT) && key_has_pending_write(h)) {

-	    queue[processed].key = h;

-	    queue[processed].event_type = WRITEABLE_EVENT;

-	    ++processed;

-	}

-

-#if PJ_HAS_TCP

-	/*

-	 * Check for completion of connect() operation.

-	 */

-	if ((events[i].events & EPOLLOUT) && (h->connecting)) {

-	    queue[processed].key = h;

-	    queue[processed].event_type = WRITEABLE_EVENT;

-	    ++processed;

-	}

-#endif /* PJ_HAS_TCP */

-	

-	/*

-	 * Check for error condition.

-	 */

-	if (events[i].events & EPOLLERR && (h->connecting)) {

-	    queue[processed].key = h;

-	    queue[processed].event_type = EXCEPTION_EVENT;

-	    ++processed;

-	}

-    }

-    pj_lock_release(ioqueue->lock);

-

-    /* Now process the events. */

-    for (i=0; i<processed; ++i) {

-	switch (queue[i].event_type) {

-        case READABLE_EVENT:

-            ioqueue_dispatch_read_event(ioqueue, queue[i].key);

-            break;

-        case WRITEABLE_EVENT:

-            ioqueue_dispatch_write_event(ioqueue, queue[i].key);

-            break;

-        case EXCEPTION_EVENT:

-            ioqueue_dispatch_exception_event(ioqueue, queue[i].key);

-            break;

-        case NO_EVENT:

-            pj_assert(!"Invalid event!");

-            break;

-        }

-    }

-

-    return processed;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 
+ */
+/*
+ * ioqueue_epoll.c
+ *
+ * This is the implementation of IOQueue framework using /dev/epoll
+ * API in _both_ Linux user-mode and kernel-mode.
+ */
+
+#include <pj/ioqueue.h>
+#include <pj/os.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/list.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/sock.h>
+#include <pj/compat/socket.h>
+
+#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0
+    /*
+     * Linux user mode
+     */
+#   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 THIS_FILE   "ioq_epoll"
+
+//#define TRACE_(expr) PJ_LOG(3,expr)
+#define TRACE_(expr)
+
+/*
+ * Include common ioqueue abstraction.
+ */
+#include "ioqueue_common_abs.h"
+
+/*
+ * This describes each key.
+ */
+struct pj_ioqueue_key_t
+{
+    DECLARE_COMMON_KEY
+};
+
+/*
+ * This describes the I/O queue.
+ */
+struct pj_ioqueue_t
+{
+    DECLARE_COMMON_IOQUEUE
+
+    unsigned		max, count;
+    pj_ioqueue_key_t	hlist;
+    int			epfd;
+};
+
+/* Include implementation for common abstraction after we declare
+ * pj_ioqueue_key_t and pj_ioqueue_t.
+ */
+#include "ioqueue_common_abs.c"
+
+/*
+ * pj_ioqueue_name()
+ */
+PJ_DEF(const char*) pj_ioqueue_name(void)
+{
+#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
+	return "epoll-kernel";
+#else
+	return "epoll";
+#endif
+}
+
+/*
+ * pj_ioqueue_create()
+ *
+ * Create select ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
+                                       pj_size_t max_fd,
+                                       pj_ioqueue_t **p_ioqueue)
+{
+    pj_ioqueue_t *ioqueue;
+    pj_status_t rc;
+    pj_lock_t *lock;
+
+    /* Check that arguments are valid. */
+    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 
+                     max_fd > 0, PJ_EINVAL);
+
+    /* Check that size of pj_ioqueue_op_key_t is sufficient */
+    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
+                     sizeof(union operation_key), PJ_EBUG);
+
+    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
+
+    ioqueue_init(ioqueue);
+
+    ioqueue->max = max_fd;
+    ioqueue->count = 0;
+    pj_list_init(&ioqueue->hlist);
+
+    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
+    if (rc != PJ_SUCCESS)
+        return rc;
+
+    ioqueue->epfd = os_epoll_create(max_fd);
+    if (ioqueue->epfd < 0) {
+	ioqueue_destroy(ioqueue);
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+    }
+    
+    PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));
+
+    *p_ioqueue = ioqueue;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_destroy()
+ *
+ * Destroy ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
+{
+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+    PJ_ASSERT_RETURN(ioqueue->epfd > 0, PJ_EINVALIDOP);
+
+    pj_lock_acquire(ioqueue->lock);
+    os_close(ioqueue->epfd);
+    ioqueue->epfd = 0;
+    return ioqueue_destroy(ioqueue);
+}
+
+/*
+ * pj_ioqueue_register_sock()
+ *
+ * Register a socket to ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					      pj_ioqueue_t *ioqueue,
+					      pj_sock_t sock,
+					      void *user_data,
+					      const pj_ioqueue_callback *cb,
+                                              pj_ioqueue_key_t **p_key)
+{
+    pj_ioqueue_key_t *key = NULL;
+    pj_uint32_t value;
+    struct epoll_event ev;
+    int status;
+    pj_status_t rc = PJ_SUCCESS;
+    
+    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
+                     cb && p_key, PJ_EINVAL);
+
+    pj_lock_acquire(ioqueue->lock);
+
+    if (ioqueue->count >= ioqueue->max) {
+        rc = PJ_ETOOMANY;
+	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files"));
+	goto on_return;
+    }
+
+    /* Set socket to nonblocking. */
+    value = 1;
+    if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) {
+	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d", 
+                rc));
+        rc = pj_get_netos_error();
+	goto on_return;
+    }
+
+    /* Create key. */
+    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
+    if (rc != PJ_SUCCESS) {
+	key = NULL;
+	goto on_return;
+    }
+
+    /* os_epoll_ctl. */
+    ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
+    ev.epoll_data = (epoll_data_type)key;
+    status = os_epoll_ctl(ioqueue->epfd, EPOLL_CTL_ADD, sock, &ev);
+    if (status < 0) {
+	rc = pj_get_os_error();
+	key = NULL;
+	TRACE_((THIS_FILE, 
+                "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d", 
+                status));
+	goto on_return;
+    }
+    
+    /* Register */
+    pj_list_insert_before(&ioqueue->hlist, key);
+    ++ioqueue->count;
+
+on_return:
+    *p_key = key;
+    pj_lock_release(ioqueue->lock);
+    
+    return rc;
+}
+
+/*
+ * pj_ioqueue_unregister()
+ *
+ * Unregister handle from ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
+{
+    pj_ioqueue_t *ioqueue;
+    struct epoll_event ev;
+    int status;
+    
+    PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);
+
+    ioqueue = key->ioqueue;
+    pj_lock_acquire(ioqueue->lock);
+
+    pj_assert(ioqueue->count > 0);
+    --ioqueue->count;
+    pj_list_erase(key);
+
+    ev.events = 0;
+    ev.epoll_data = (epoll_data_type)key;
+    status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);
+    if (status != 0) {
+	pj_status_t rc = pj_get_os_error();
+	pj_lock_release(ioqueue->lock);
+	return rc;
+    }
+
+    pj_lock_release(ioqueue->lock);
+
+    /* Destroy the key. */
+    ioqueue_destroy_key(key);
+
+    return PJ_SUCCESS;
+}
+
+/* ioqueue_remove_from_set()
+ * This function is called from ioqueue_dispatch_event() to instruct
+ * the ioqueue to remove the specified descriptor from ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
+                                     pj_sock_t fd, 
+                                     enum ioqueue_event_type event_type)
+{
+}
+
+/*
+ * ioqueue_add_to_set()
+ * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
+ * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
+                                pj_sock_t fd,
+                                enum ioqueue_event_type event_type )
+{
+}
+
+/*
+ * pj_ioqueue_poll()
+ *
+ */
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
+{
+    int i, count, processed;
+    struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
+    int msec;
+    struct queue {
+	pj_ioqueue_key_t	*key;
+	enum ioqueue_event_type	 event_type;
+    } queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
+    
+    PJ_CHECK_STACK();
+
+    msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;
+    
+    count = os_epoll_wait( ioqueue->epfd, events, PJ_ARRAY_SIZE(events), msec);
+    if (count <= 0)
+	return count;
+
+    /* Lock ioqueue. */
+    pj_lock_acquire(ioqueue->lock);
+
+    for (processed=0, i=0; i<count; ++i) {
+	pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)
+				events[i].epoll_data;
+
+	/*
+	 * Check readability.
+	 */
+	if ((events[i].events & EPOLLIN) && 
+	    (key_has_pending_read(h) || key_has_pending_accept(h))) {
+	    queue[processed].key = h;
+	    queue[processed].event_type = READABLE_EVENT;
+	    ++processed;
+	}
+
+	/*
+	 * Check for writeability.
+	 */
+	if ((events[i].events & EPOLLOUT) && key_has_pending_write(h)) {
+	    queue[processed].key = h;
+	    queue[processed].event_type = WRITEABLE_EVENT;
+	    ++processed;
+	}
+
+#if PJ_HAS_TCP
+	/*
+	 * Check for completion of connect() operation.
+	 */
+	if ((events[i].events & EPOLLOUT) && (h->connecting)) {
+	    queue[processed].key = h;
+	    queue[processed].event_type = WRITEABLE_EVENT;
+	    ++processed;
+	}
+#endif /* PJ_HAS_TCP */
+	
+	/*
+	 * Check for error condition.
+	 */
+	if (events[i].events & EPOLLERR && (h->connecting)) {
+	    queue[processed].key = h;
+	    queue[processed].event_type = EXCEPTION_EVENT;
+	    ++processed;
+	}
+    }
+    pj_lock_release(ioqueue->lock);
+
+    /* Now process the events. */
+    for (i=0; i<processed; ++i) {
+	switch (queue[i].event_type) {
+        case READABLE_EVENT:
+            ioqueue_dispatch_read_event(ioqueue, queue[i].key);
+            break;
+        case WRITEABLE_EVENT:
+            ioqueue_dispatch_write_event(ioqueue, queue[i].key);
+            break;
+        case EXCEPTION_EVENT:
+            ioqueue_dispatch_exception_event(ioqueue, queue[i].key);
+            break;
+        case NO_EVENT:
+            pj_assert(!"Invalid event!");
+            break;
+        }
+    }
+
+    return processed;
+}
+
diff --git a/pjlib/src/pj/ioqueue_linux_kernel.c b/pjlib/src/pj/ioqueue_linux_kernel.c
index eb35198..dba0f13 100644
--- a/pjlib/src/pj/ioqueue_linux_kernel.c
+++ b/pjlib/src/pj/ioqueue_linux_kernel.c
@@ -1,161 +1,161 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 */
+
diff --git a/pjlib/src/pj/ioqueue_select.c b/pjlib/src/pj/ioqueue_select.c
index b313c44..df08d0c 100644
--- a/pjlib/src/pj/ioqueue_select.c
+++ b/pjlib/src/pj/ioqueue_select.c
@@ -1,531 +1,531 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 

- */

-

-/*

- * sock_select.c

- *

- * This is the implementation of IOQueue using pj_sock_select().

- * It runs anywhere where pj_sock_select() is available (currently

- * Win32, Linux, Linux kernel, etc.).

- */

-

-#include <pj/ioqueue.h>

-#include <pj/os.h>

-#include <pj/lock.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>

-#include <pj/compat/socket.h>

-#include <pj/sock_select.h>

-#include <pj/errno.h>

-

-/*

- * Include declaration from common abstraction.

- */

-#include "ioqueue_common_abs.h"

-

-/*

- * ISSUES with ioqueue_select()

- *

- * EAGAIN/EWOULDBLOCK error in recv():

- *  - when multiple threads are working with the ioqueue, application

- *    may receive EAGAIN or EWOULDBLOCK in the receive callback.

- *    This error happens because more than one thread is watching for

- *    the same descriptor set, so when all of them call recv() or recvfrom()

- *    simultaneously, only one will succeed and the rest will get the error.

- *

- */

-#define THIS_FILE   "ioq_select"

-

-/*

- * The select ioqueue relies on socket functions (pj_sock_xxx()) to return

- * the correct error code.

- */

-#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)

-#   error "Error reporting must be enabled for this function to work!"

-#endif

-

-/**

- * Get the number of descriptors in the set. This is defined in sock_select.c

- * This function will only return the number of sockets set from PJ_FD_SET

- * operation. When the set is modified by other means (such as by select()),

- * the count will not be reflected here.

- *

- * That's why don't export this function in the header file, to avoid

- * misunderstanding.

- *

- * @param fdsetp    The descriptor set.

- *

- * @return          Number of descriptors in the set.

- */

-PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp);

-

-

-/*

- * During debugging build, VALIDATE_FD_SET is set.

- * This will check the validity of the fd_sets.

- */

-/*

-#if defined(PJ_DEBUG) && PJ_DEBUG != 0

-#  define VALIDATE_FD_SET		1

-#else

-#  define VALIDATE_FD_SET		0

-#endif

-*/

-#define VALIDATE_FD_SET     0

-

-/*

- * This describes each key.

- */

-struct pj_ioqueue_key_t

-{

-    DECLARE_COMMON_KEY

-};

-

-/*

- * This describes the I/O queue itself.

- */

-struct pj_ioqueue_t

-{

-    DECLARE_COMMON_IOQUEUE

-

-    unsigned		max, count;

-    pj_ioqueue_key_t	key_list;

-    pj_fd_set_t		rfdset;

-    pj_fd_set_t		wfdset;

-#if PJ_HAS_TCP

-    pj_fd_set_t		xfdset;

-#endif

-};

-

-/* Include implementation for common abstraction after we declare

- * pj_ioqueue_key_t and pj_ioqueue_t.

- */

-#include "ioqueue_common_abs.c"

-

-/*

- * pj_ioqueue_name()

- */

-PJ_DEF(const char*) pj_ioqueue_name(void)

-{

-    return "select";

-}

-

-/*

- * pj_ioqueue_create()

- *

- * Create select ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

-                                       pj_size_t max_fd,

-                                       pj_ioqueue_t **p_ioqueue)

-{

-    pj_ioqueue_t *ioqueue;

-    pj_lock_t *lock;

-    pj_status_t rc;

-

-    /* Check that arguments are valid. */

-    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 

-                     max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES, 

-                     PJ_EINVAL);

-

-    /* Check that size of pj_ioqueue_op_key_t is sufficient */

-    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=

-                     sizeof(union operation_key), PJ_EBUG);

-

-    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));

-

-    ioqueue_init(ioqueue);

-

-    ioqueue->max = max_fd;

-    ioqueue->count = 0;

-    PJ_FD_ZERO(&ioqueue->rfdset);

-    PJ_FD_ZERO(&ioqueue->wfdset);

-#if PJ_HAS_TCP

-    PJ_FD_ZERO(&ioqueue->xfdset);

-#endif

-    pj_list_init(&ioqueue->key_list);

-

-    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);

-    if (rc != PJ_SUCCESS)

-	return rc;

-

-    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);

-    if (rc != PJ_SUCCESS)

-        return rc;

-

-    PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue));

-

-    *p_ioqueue = ioqueue;

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_destroy()

- *

- * Destroy ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)

-{

-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

-

-    pj_lock_acquire(ioqueue->lock);

-    return ioqueue_destroy(ioqueue);

-}

-

-

-/*

- * pj_ioqueue_register_sock()

- *

- * Register a handle to ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

-					      pj_ioqueue_t *ioqueue,

-					      pj_sock_t sock,

-					      void *user_data,

-					      const pj_ioqueue_callback *cb,

-                                              pj_ioqueue_key_t **p_key)

-{

-    pj_ioqueue_key_t *key = NULL;

-    pj_uint32_t value;

-    pj_status_t rc = PJ_SUCCESS;

-    

-    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&

-                     cb && p_key, PJ_EINVAL);

-

-    pj_lock_acquire(ioqueue->lock);

-

-    if (ioqueue->count >= ioqueue->max) {

-        rc = PJ_ETOOMANY;

-	goto on_return;

-    }

-

-    /* Set socket to nonblocking. */

-    value = 1;

-#ifdef PJ_WIN32

-    if (ioctlsocket(sock, FIONBIO, (u_long*)&value)) {

-#else

-    if (ioctl(sock, FIONBIO, &value)) {

-#endif

-        rc = pj_get_netos_error();

-	goto on_return;

-    }

-

-    /* Create key. */

-    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));

-    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);

-    if (rc != PJ_SUCCESS) {

-	key = NULL;

-	goto on_return;

-    }

-

-    /* Register */

-    pj_list_insert_before(&ioqueue->key_list, key);

-    ++ioqueue->count;

-

-on_return:

-    /* On error, socket may be left in non-blocking mode. */

-    *p_key = key;

-    pj_lock_release(ioqueue->lock);

-    

-    return rc;

-}

-

-/*

- * pj_ioqueue_unregister()

- *

- * Unregister handle from ioqueue.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)

-{

-    pj_ioqueue_t *ioqueue;

-

-    PJ_ASSERT_RETURN(key, PJ_EINVAL);

-

-    ioqueue = key->ioqueue;

-

-    pj_lock_acquire(ioqueue->lock);

-

-    pj_assert(ioqueue->count > 0);

-    --ioqueue->count;

-    pj_list_erase(key);

-    PJ_FD_CLR(key->fd, &ioqueue->rfdset);

-    PJ_FD_CLR(key->fd, &ioqueue->wfdset);

-#if PJ_HAS_TCP

-    PJ_FD_CLR(key->fd, &ioqueue->xfdset);

-#endif

-

-    /* ioqueue_destroy may try to acquire key's mutex.

-     * Since normally the order of locking is to lock key's mutex first

-     * then ioqueue's mutex, ioqueue_destroy may deadlock unless we

-     * release ioqueue's mutex first.

-     */

-    pj_lock_release(ioqueue->lock);

-

-    /* Destroy the key. */

-    ioqueue_destroy_key(key);

-

-    return PJ_SUCCESS;

-}

-

-

-/* This supposed to check whether the fd_set values are consistent

- * with the operation currently set in each key.

- */

-#if VALIDATE_FD_SET

-static void validate_sets(const pj_ioqueue_t *ioqueue,

-			  const pj_fd_set_t *rfdset,

-			  const pj_fd_set_t *wfdset,

-			  const pj_fd_set_t *xfdset)

-{

-    pj_ioqueue_key_t *key;

-

-    /*

-     * This basicly would not work anymore.

-     * We need to lock key before performing the check, but we can't do

-     * so because we're holding ioqueue mutex. If we acquire key's mutex

-     * now, the will cause deadlock.

-     */

-    pj_assert(0);

-

-    key = ioqueue->key_list.next;

-    while (key != &ioqueue->key_list) {

-	if (!pj_list_empty(&key->read_list)

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-	    || !pj_list_empty(&key->accept_list)

-#endif

-	    ) 

-	{

-	    pj_assert(PJ_FD_ISSET(key->fd, rfdset));

-	} 

-	else {

-	    pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0);

-	}

-	if (!pj_list_empty(&key->write_list)

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-	    || key->connecting

-#endif

-	   )

-	{

-	    pj_assert(PJ_FD_ISSET(key->fd, wfdset));

-	}

-	else {

-	    pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0);

-	}

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-	if (key->connecting)

-	{

-	    pj_assert(PJ_FD_ISSET(key->fd, xfdset));

-	}

-	else {

-	    pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0);

-	}

-#endif /* PJ_HAS_TCP */

-

-	key = key->next;

-    }

-}

-#endif	/* VALIDATE_FD_SET */

-

-

-/* ioqueue_remove_from_set()

- * This function is called from ioqueue_dispatch_event() to instruct

- * the ioqueue to remove the specified descriptor from ioqueue's descriptor

- * set for the specified event.

- */

-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,

-                                     pj_sock_t fd, 

-                                     enum ioqueue_event_type event_type)

-{

-    pj_lock_acquire(ioqueue->lock);

-

-    if (event_type == READABLE_EVENT)

-        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->rfdset);

-    else if (event_type == WRITEABLE_EVENT)

-        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->wfdset);

-    else if (event_type == EXCEPTION_EVENT)

-        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->xfdset);

-    else

-        pj_assert(0);

-

-    pj_lock_release(ioqueue->lock);

-}

-

-/*

- * ioqueue_add_to_set()

- * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc

- * to instruct the ioqueue to add the specified handle to ioqueue's descriptor

- * set for the specified event.

- */

-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,

-                                pj_sock_t fd,

-                                enum ioqueue_event_type event_type )

-{

-    pj_lock_acquire(ioqueue->lock);

-

-    if (event_type == READABLE_EVENT)

-        PJ_FD_SET((pj_sock_t)fd, &ioqueue->rfdset);

-    else if (event_type == WRITEABLE_EVENT)

-        PJ_FD_SET((pj_sock_t)fd, &ioqueue->wfdset);

-    else if (event_type == EXCEPTION_EVENT)

-        PJ_FD_SET((pj_sock_t)fd, &ioqueue->xfdset);

-    else

-        pj_assert(0);

-

-    pj_lock_release(ioqueue->lock);

-}

-

-/*

- * pj_ioqueue_poll()

- *

- * Few things worth written:

- *

- *  - we used to do only one callback called per poll, but it didn't go

- *    very well. The reason is because on some situation, the write 

- *    callback gets called all the time, thus doesn't give the read

- *    callback to get called. This happens, for example, when user

- *    submit write operation inside the write callback.

- *    As the result, we changed the behaviour so that now multiple

- *    callbacks are called in a single poll. It should be fast too,

- *    just that we need to be carefull with the ioqueue data structs.

- *

- *  - to guarantee preemptiveness etc, the poll function must strictly

- *    work on fd_set copy of the ioqueue (not the original one).

- */

-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)

-{

-    pj_fd_set_t rfdset, wfdset, xfdset;

-    int count, counter;

-    pj_ioqueue_key_t *h;

-    struct event

-    {

-        pj_ioqueue_key_t	*key;

-        enum ioqueue_event_type  event_type;

-    } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];

-

-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

-

-    /* Lock ioqueue before making fd_set copies */

-    pj_lock_acquire(ioqueue->lock);

-

-    /* We will only do select() when there are sockets to be polled.

-     * Otherwise select() will return error.

-     */

-    if (PJ_FD_COUNT(&ioqueue->rfdset)==0 &&

-        PJ_FD_COUNT(&ioqueue->wfdset)==0 &&

-        PJ_FD_COUNT(&ioqueue->xfdset)==0)

-    {

-        pj_lock_release(ioqueue->lock);

-        if (timeout)

-            pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout));

-        return 0;

-    }

-

-    /* Copy ioqueue's pj_fd_set_t to local variables. */

-    pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t));

-    pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t));

-#if PJ_HAS_TCP

-    pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t));

-#else

-    PJ_FD_ZERO(&xfdset);

-#endif

-

-#if VALIDATE_FD_SET

-    validate_sets(ioqueue, &rfdset, &wfdset, &xfdset);

-#endif

-

-    /* Unlock ioqueue before select(). */

-    pj_lock_release(ioqueue->lock);

-

-    count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout);

-    

-    if (count <= 0)

-	return count;

-    else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL)

-        count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL;

-

-    /* Scan descriptor sets for event and add the events in the event

-     * array to be processed later in this function. We do this so that

-     * events can be processed in parallel without holding ioqueue lock.

-     */

-    pj_lock_acquire(ioqueue->lock);

-

-    counter = 0;

-

-    /* Scan for writable sockets first to handle piggy-back data

-     * coming with accept().

-     */

-    h = ioqueue->key_list.next;

-    for ( ; h!=&ioqueue->key_list && counter<count; h = h->next) {

-	if ( (key_has_pending_write(h) || key_has_pending_connect(h))

-	     && PJ_FD_ISSET(h->fd, &wfdset))

-        {

-            event[counter].key = h;

-            event[counter].event_type = WRITEABLE_EVENT;

-            ++counter;

-        }

-

-        /* Scan for readable socket. */

-	if ((key_has_pending_read(h) || key_has_pending_accept(h))

-            && PJ_FD_ISSET(h->fd, &rfdset))

-        {

-            event[counter].key = h;

-            event[counter].event_type = READABLE_EVENT;

-            ++counter;

-	}

-

-#if PJ_HAS_TCP

-        if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset)) {

-            event[counter].key = h;

-            event[counter].event_type = EXCEPTION_EVENT;

-            ++counter;

-        }

-#endif

-    }

-

-    pj_lock_release(ioqueue->lock);

-

-    count = counter;

-

-    /* Now process all events. The dispatch functions will take care

-     * of locking in each of the key

-     */

-    for (counter=0; counter<count; ++counter) {

-        switch (event[counter].event_type) {

-        case READABLE_EVENT:

-            ioqueue_dispatch_read_event(ioqueue, event[counter].key);

-            break;

-        case WRITEABLE_EVENT:

-            ioqueue_dispatch_write_event(ioqueue, event[counter].key);

-            break;

-        case EXCEPTION_EVENT:

-            ioqueue_dispatch_exception_event(ioqueue, event[counter].key);

-            break;

-        case NO_EVENT:

-            pj_assert(!"Invalid event!");

-            break;

-        }

-    }

-

-    return count;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 
+ */
+
+/*
+ * sock_select.c
+ *
+ * This is the implementation of IOQueue using pj_sock_select().
+ * It runs anywhere where pj_sock_select() is available (currently
+ * Win32, Linux, Linux kernel, etc.).
+ */
+
+#include <pj/ioqueue.h>
+#include <pj/os.h>
+#include <pj/lock.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>
+#include <pj/compat/socket.h>
+#include <pj/sock_select.h>
+#include <pj/errno.h>
+
+/*
+ * Include declaration from common abstraction.
+ */
+#include "ioqueue_common_abs.h"
+
+/*
+ * ISSUES with ioqueue_select()
+ *
+ * EAGAIN/EWOULDBLOCK error in recv():
+ *  - when multiple threads are working with the ioqueue, application
+ *    may receive EAGAIN or EWOULDBLOCK in the receive callback.
+ *    This error happens because more than one thread is watching for
+ *    the same descriptor set, so when all of them call recv() or recvfrom()
+ *    simultaneously, only one will succeed and the rest will get the error.
+ *
+ */
+#define THIS_FILE   "ioq_select"
+
+/*
+ * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
+ * the correct error code.
+ */
+#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
+#   error "Error reporting must be enabled for this function to work!"
+#endif
+
+/**
+ * Get the number of descriptors in the set. This is defined in sock_select.c
+ * This function will only return the number of sockets set from PJ_FD_SET
+ * operation. When the set is modified by other means (such as by select()),
+ * the count will not be reflected here.
+ *
+ * That's why don't export this function in the header file, to avoid
+ * misunderstanding.
+ *
+ * @param fdsetp    The descriptor set.
+ *
+ * @return          Number of descriptors in the set.
+ */
+PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp);
+
+
+/*
+ * During debugging build, VALIDATE_FD_SET is set.
+ * This will check the validity of the fd_sets.
+ */
+/*
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+#  define VALIDATE_FD_SET		1
+#else
+#  define VALIDATE_FD_SET		0
+#endif
+*/
+#define VALIDATE_FD_SET     0
+
+/*
+ * This describes each key.
+ */
+struct pj_ioqueue_key_t
+{
+    DECLARE_COMMON_KEY
+};
+
+/*
+ * This describes the I/O queue itself.
+ */
+struct pj_ioqueue_t
+{
+    DECLARE_COMMON_IOQUEUE
+
+    unsigned		max, count;
+    pj_ioqueue_key_t	key_list;
+    pj_fd_set_t		rfdset;
+    pj_fd_set_t		wfdset;
+#if PJ_HAS_TCP
+    pj_fd_set_t		xfdset;
+#endif
+};
+
+/* Include implementation for common abstraction after we declare
+ * pj_ioqueue_key_t and pj_ioqueue_t.
+ */
+#include "ioqueue_common_abs.c"
+
+/*
+ * pj_ioqueue_name()
+ */
+PJ_DEF(const char*) pj_ioqueue_name(void)
+{
+    return "select";
+}
+
+/*
+ * pj_ioqueue_create()
+ *
+ * Create select ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
+                                       pj_size_t max_fd,
+                                       pj_ioqueue_t **p_ioqueue)
+{
+    pj_ioqueue_t *ioqueue;
+    pj_lock_t *lock;
+    pj_status_t rc;
+
+    /* Check that arguments are valid. */
+    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 
+                     max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES, 
+                     PJ_EINVAL);
+
+    /* Check that size of pj_ioqueue_op_key_t is sufficient */
+    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
+                     sizeof(union operation_key), PJ_EBUG);
+
+    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
+
+    ioqueue_init(ioqueue);
+
+    ioqueue->max = max_fd;
+    ioqueue->count = 0;
+    PJ_FD_ZERO(&ioqueue->rfdset);
+    PJ_FD_ZERO(&ioqueue->wfdset);
+#if PJ_HAS_TCP
+    PJ_FD_ZERO(&ioqueue->xfdset);
+#endif
+    pj_list_init(&ioqueue->key_list);
+
+    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
+    if (rc != PJ_SUCCESS)
+        return rc;
+
+    PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue));
+
+    *p_ioqueue = ioqueue;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_destroy()
+ *
+ * Destroy ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
+{
+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+
+    pj_lock_acquire(ioqueue->lock);
+    return ioqueue_destroy(ioqueue);
+}
+
+
+/*
+ * pj_ioqueue_register_sock()
+ *
+ * Register a handle to ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					      pj_ioqueue_t *ioqueue,
+					      pj_sock_t sock,
+					      void *user_data,
+					      const pj_ioqueue_callback *cb,
+                                              pj_ioqueue_key_t **p_key)
+{
+    pj_ioqueue_key_t *key = NULL;
+    pj_uint32_t value;
+    pj_status_t rc = PJ_SUCCESS;
+    
+    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
+                     cb && p_key, PJ_EINVAL);
+
+    pj_lock_acquire(ioqueue->lock);
+
+    if (ioqueue->count >= ioqueue->max) {
+        rc = PJ_ETOOMANY;
+	goto on_return;
+    }
+
+    /* Set socket to nonblocking. */
+    value = 1;
+#ifdef PJ_WIN32
+    if (ioctlsocket(sock, FIONBIO, (u_long*)&value)) {
+#else
+    if (ioctl(sock, FIONBIO, &value)) {
+#endif
+        rc = pj_get_netos_error();
+	goto on_return;
+    }
+
+    /* Create key. */
+    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
+    if (rc != PJ_SUCCESS) {
+	key = NULL;
+	goto on_return;
+    }
+
+    /* Register */
+    pj_list_insert_before(&ioqueue->key_list, key);
+    ++ioqueue->count;
+
+on_return:
+    /* On error, socket may be left in non-blocking mode. */
+    *p_key = key;
+    pj_lock_release(ioqueue->lock);
+    
+    return rc;
+}
+
+/*
+ * pj_ioqueue_unregister()
+ *
+ * Unregister handle from ioqueue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
+{
+    pj_ioqueue_t *ioqueue;
+
+    PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+    ioqueue = key->ioqueue;
+
+    pj_lock_acquire(ioqueue->lock);
+
+    pj_assert(ioqueue->count > 0);
+    --ioqueue->count;
+    pj_list_erase(key);
+    PJ_FD_CLR(key->fd, &ioqueue->rfdset);
+    PJ_FD_CLR(key->fd, &ioqueue->wfdset);
+#if PJ_HAS_TCP
+    PJ_FD_CLR(key->fd, &ioqueue->xfdset);
+#endif
+
+    /* ioqueue_destroy may try to acquire key's mutex.
+     * Since normally the order of locking is to lock key's mutex first
+     * then ioqueue's mutex, ioqueue_destroy may deadlock unless we
+     * release ioqueue's mutex first.
+     */
+    pj_lock_release(ioqueue->lock);
+
+    /* Destroy the key. */
+    ioqueue_destroy_key(key);
+
+    return PJ_SUCCESS;
+}
+
+
+/* This supposed to check whether the fd_set values are consistent
+ * with the operation currently set in each key.
+ */
+#if VALIDATE_FD_SET
+static void validate_sets(const pj_ioqueue_t *ioqueue,
+			  const pj_fd_set_t *rfdset,
+			  const pj_fd_set_t *wfdset,
+			  const pj_fd_set_t *xfdset)
+{
+    pj_ioqueue_key_t *key;
+
+    /*
+     * This basicly would not work anymore.
+     * We need to lock key before performing the check, but we can't do
+     * so because we're holding ioqueue mutex. If we acquire key's mutex
+     * now, the will cause deadlock.
+     */
+    pj_assert(0);
+
+    key = ioqueue->key_list.next;
+    while (key != &ioqueue->key_list) {
+	if (!pj_list_empty(&key->read_list)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+	    || !pj_list_empty(&key->accept_list)
+#endif
+	    ) 
+	{
+	    pj_assert(PJ_FD_ISSET(key->fd, rfdset));
+	} 
+	else {
+	    pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0);
+	}
+	if (!pj_list_empty(&key->write_list)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+	    || key->connecting
+#endif
+	   )
+	{
+	    pj_assert(PJ_FD_ISSET(key->fd, wfdset));
+	}
+	else {
+	    pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0);
+	}
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+	if (key->connecting)
+	{
+	    pj_assert(PJ_FD_ISSET(key->fd, xfdset));
+	}
+	else {
+	    pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0);
+	}
+#endif /* PJ_HAS_TCP */
+
+	key = key->next;
+    }
+}
+#endif	/* VALIDATE_FD_SET */
+
+
+/* ioqueue_remove_from_set()
+ * This function is called from ioqueue_dispatch_event() to instruct
+ * the ioqueue to remove the specified descriptor from ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
+                                     pj_sock_t fd, 
+                                     enum ioqueue_event_type event_type)
+{
+    pj_lock_acquire(ioqueue->lock);
+
+    if (event_type == READABLE_EVENT)
+        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->rfdset);
+    else if (event_type == WRITEABLE_EVENT)
+        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->wfdset);
+    else if (event_type == EXCEPTION_EVENT)
+        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->xfdset);
+    else
+        pj_assert(0);
+
+    pj_lock_release(ioqueue->lock);
+}
+
+/*
+ * ioqueue_add_to_set()
+ * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
+ * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
+ * set for the specified event.
+ */
+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
+                                pj_sock_t fd,
+                                enum ioqueue_event_type event_type )
+{
+    pj_lock_acquire(ioqueue->lock);
+
+    if (event_type == READABLE_EVENT)
+        PJ_FD_SET((pj_sock_t)fd, &ioqueue->rfdset);
+    else if (event_type == WRITEABLE_EVENT)
+        PJ_FD_SET((pj_sock_t)fd, &ioqueue->wfdset);
+    else if (event_type == EXCEPTION_EVENT)
+        PJ_FD_SET((pj_sock_t)fd, &ioqueue->xfdset);
+    else
+        pj_assert(0);
+
+    pj_lock_release(ioqueue->lock);
+}
+
+/*
+ * pj_ioqueue_poll()
+ *
+ * Few things worth written:
+ *
+ *  - we used to do only one callback called per poll, but it didn't go
+ *    very well. The reason is because on some situation, the write 
+ *    callback gets called all the time, thus doesn't give the read
+ *    callback to get called. This happens, for example, when user
+ *    submit write operation inside the write callback.
+ *    As the result, we changed the behaviour so that now multiple
+ *    callbacks are called in a single poll. It should be fast too,
+ *    just that we need to be carefull with the ioqueue data structs.
+ *
+ *  - to guarantee preemptiveness etc, the poll function must strictly
+ *    work on fd_set copy of the ioqueue (not the original one).
+ */
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
+{
+    pj_fd_set_t rfdset, wfdset, xfdset;
+    int count, counter;
+    pj_ioqueue_key_t *h;
+    struct event
+    {
+        pj_ioqueue_key_t	*key;
+        enum ioqueue_event_type  event_type;
+    } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
+
+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+
+    /* Lock ioqueue before making fd_set copies */
+    pj_lock_acquire(ioqueue->lock);
+
+    /* We will only do select() when there are sockets to be polled.
+     * Otherwise select() will return error.
+     */
+    if (PJ_FD_COUNT(&ioqueue->rfdset)==0 &&
+        PJ_FD_COUNT(&ioqueue->wfdset)==0 &&
+        PJ_FD_COUNT(&ioqueue->xfdset)==0)
+    {
+        pj_lock_release(ioqueue->lock);
+        if (timeout)
+            pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout));
+        return 0;
+    }
+
+    /* Copy ioqueue's pj_fd_set_t to local variables. */
+    pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t));
+    pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t));
+#if PJ_HAS_TCP
+    pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t));
+#else
+    PJ_FD_ZERO(&xfdset);
+#endif
+
+#if VALIDATE_FD_SET
+    validate_sets(ioqueue, &rfdset, &wfdset, &xfdset);
+#endif
+
+    /* Unlock ioqueue before select(). */
+    pj_lock_release(ioqueue->lock);
+
+    count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout);
+    
+    if (count <= 0)
+	return count;
+    else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL)
+        count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL;
+
+    /* Scan descriptor sets for event and add the events in the event
+     * array to be processed later in this function. We do this so that
+     * events can be processed in parallel without holding ioqueue lock.
+     */
+    pj_lock_acquire(ioqueue->lock);
+
+    counter = 0;
+
+    /* Scan for writable sockets first to handle piggy-back data
+     * coming with accept().
+     */
+    h = ioqueue->key_list.next;
+    for ( ; h!=&ioqueue->key_list && counter<count; h = h->next) {
+	if ( (key_has_pending_write(h) || key_has_pending_connect(h))
+	     && PJ_FD_ISSET(h->fd, &wfdset))
+        {
+            event[counter].key = h;
+            event[counter].event_type = WRITEABLE_EVENT;
+            ++counter;
+        }
+
+        /* Scan for readable socket. */
+	if ((key_has_pending_read(h) || key_has_pending_accept(h))
+            && PJ_FD_ISSET(h->fd, &rfdset))
+        {
+            event[counter].key = h;
+            event[counter].event_type = READABLE_EVENT;
+            ++counter;
+	}
+
+#if PJ_HAS_TCP
+        if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset)) {
+            event[counter].key = h;
+            event[counter].event_type = EXCEPTION_EVENT;
+            ++counter;
+        }
+#endif
+    }
+
+    pj_lock_release(ioqueue->lock);
+
+    count = counter;
+
+    /* Now process all events. The dispatch functions will take care
+     * of locking in each of the key
+     */
+    for (counter=0; counter<count; ++counter) {
+        switch (event[counter].event_type) {
+        case READABLE_EVENT:
+            ioqueue_dispatch_read_event(ioqueue, event[counter].key);
+            break;
+        case WRITEABLE_EVENT:
+            ioqueue_dispatch_write_event(ioqueue, event[counter].key);
+            break;
+        case EXCEPTION_EVENT:
+            ioqueue_dispatch_exception_event(ioqueue, event[counter].key);
+            break;
+        case NO_EVENT:
+            pj_assert(!"Invalid event!");
+            break;
+        }
+    }
+
+    return count;
+}
+
diff --git a/pjlib/src/pj/ioqueue_winnt.c b/pjlib/src/pj/ioqueue_winnt.c
index 828b568..e46d36a 100644
--- a/pjlib/src/pj/ioqueue_winnt.c
+++ b/pjlib/src/pj/ioqueue_winnt.c
@@ -1,960 +1,960 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/lock.h>

-#include <pj/pool.h>

-#include <pj/string.h>

-#include <pj/sock.h>

-#include <pj/array.h>

-#include <pj/log.h>

-#include <pj/assert.h>

-#include <pj/errno.h>

-

-

-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0

-#  include <winsock2.h>

-#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0

-#  include <winsock.h>

-#endif

-

-#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0

-#  include <mswsock.h>

-#endif

-

-

-/* The address specified in AcceptEx() must be 16 more than the size of

- * SOCKADDR (source: MSDN).

- */

-#define ACCEPT_ADDR_LEN	    (sizeof(pj_sockaddr_in)+16)

-

-typedef struct generic_overlapped

-{

-    WSAOVERLAPPED	   overlapped;

-    pj_ioqueue_operation_e operation;

-} generic_overlapped;

-

-/*

- * OVERLAPPPED structure for send and receive.

- */

-typedef struct ioqueue_overlapped

-{

-    WSAOVERLAPPED	   overlapped;

-    pj_ioqueue_operation_e operation;

-    WSABUF		   wsabuf;

-    pj_sockaddr_in         dummy_addr;

-    int                    dummy_addrlen;

-} ioqueue_overlapped;

-

-#if PJ_HAS_TCP

-/*

- * OVERLAP structure for accept.

- */

-typedef struct ioqueue_accept_rec

-{

-    WSAOVERLAPPED	    overlapped;

-    pj_ioqueue_operation_e  operation;

-    pj_sock_t		    newsock;

-    pj_sock_t		   *newsock_ptr;

-    int			   *addrlen;

-    void		   *remote;

-    void		   *local;

-    char		    accept_buf[2 * ACCEPT_ADDR_LEN];

-} ioqueue_accept_rec;

-#endif

-

-/*

- * Structure to hold pending operation key.

- */

-union operation_key

-{

-    generic_overlapped      generic;

-    ioqueue_overlapped      overlapped;

-#if PJ_HAS_TCP

-    ioqueue_accept_rec      accept;

-#endif

-};

-

-/* Type of handle in the key. */

-enum handle_type

-{

-    HND_IS_UNKNOWN,

-    HND_IS_FILE,

-    HND_IS_SOCKET,

-};

-

-/*

- * Structure for individual socket.

- */

-struct pj_ioqueue_key_t

-{

-    pj_ioqueue_t       *ioqueue;

-    HANDLE		hnd;

-    void	       *user_data;

-    enum handle_type    hnd_type;

-#if PJ_HAS_TCP

-    int			connecting;

-#endif

-    pj_ioqueue_callback	cb;

-};

-

-/*

- * IO Queue structure.

- */

-struct pj_ioqueue_t

-{

-    HANDLE	      iocp;

-    pj_lock_t        *lock;

-    pj_bool_t         auto_delete_lock;

-    unsigned	      event_count;

-    HANDLE	      event_pool[MAXIMUM_WAIT_OBJECTS+1];

-#if PJ_HAS_TCP

-    unsigned	      connecting_count;

-    HANDLE	      connecting_handles[MAXIMUM_WAIT_OBJECTS+1];

-    pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1];

-#endif

-};

-

-

-#if PJ_HAS_TCP

-/*

- * Process the socket when the overlapped accept() completed.

- */

-static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped)

-{

-    struct sockaddr *local;

-    struct sockaddr *remote;

-    int locallen, remotelen;

-

-    PJ_CHECK_STACK();

-

-    /* Operation complete immediately. */

-    GetAcceptExSockaddrs( accept_overlapped->accept_buf,

-			  0, 

-			  ACCEPT_ADDR_LEN,

-			  ACCEPT_ADDR_LEN,

-			  &local,

-			  &locallen,

-			  &remote,

-			  &remotelen);

-    if (*accept_overlapped->addrlen > locallen) {

-        pj_memcpy(accept_overlapped->local, local, locallen);

-        pj_memcpy(accept_overlapped->remote, remote, locallen);

-    } else {

-        pj_memset(accept_overlapped->local, 0, *accept_overlapped->addrlen);

-        pj_memset(accept_overlapped->remote, 0, *accept_overlapped->addrlen);

-    }

-    *accept_overlapped->addrlen = locallen;

-    if (accept_overlapped->newsock_ptr)

-        *accept_overlapped->newsock_ptr = accept_overlapped->newsock;

-    accept_overlapped->operation = 0;

-    accept_overlapped->newsock = PJ_INVALID_SOCKET;

-}

-

-static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos)

-{

-    pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos];

-    HANDLE hEvent = ioqueue->connecting_handles[pos];

-

-    /* Remove key from array of connecting handles. */

-    pj_array_erase(ioqueue->connecting_keys, sizeof(key),

-		   ioqueue->connecting_count, pos);

-    pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE),

-		   ioqueue->connecting_count, pos);

-    --ioqueue->connecting_count;

-

-    /* Disassociate the socket from the event. */

-    WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0);

-

-    /* Put event object to pool. */

-    if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) {

-	ioqueue->event_pool[ioqueue->event_count++] = hEvent;

-    } else {

-	/* Shouldn't happen. There should be no more pending connections

-	 * than max. 

-	 */

-	pj_assert(0);

-	CloseHandle(hEvent);

-    }

-

-}

-

-/*

- * Poll for the completion of non-blocking connect().

- * If there's a completion, the function return the key of the completed

- * socket, and 'result' argument contains the connect() result. If connect()

- * succeeded, 'result' will have value zero, otherwise will have the error

- * code.

- */

-static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue, 

-					   pj_ssize_t *connect_err )

-{

-    pj_ioqueue_key_t *key = NULL;

-

-    if (ioqueue->connecting_count) {

-	DWORD result;

-

-	pj_lock_acquire(ioqueue->lock);

-	result = WaitForMultipleObjects(ioqueue->connecting_count,

-					ioqueue->connecting_handles,

-					FALSE, 0);

-	if (result >= WAIT_OBJECT_0 && 

-	    result < WAIT_OBJECT_0+ioqueue->connecting_count) 

-	{

-	    WSANETWORKEVENTS net_events;

-

-	    /* Got completed connect(). */

-	    unsigned pos = result - WAIT_OBJECT_0;

-	    key = ioqueue->connecting_keys[pos];

-

-	    /* See whether connect has succeeded. */

-	    WSAEnumNetworkEvents((pj_sock_t)key->hnd, 

-				 ioqueue->connecting_handles[pos], 

-				 &net_events);

-	    *connect_err = 

-                PJ_STATUS_FROM_OS(net_events.iErrorCode[FD_CONNECT_BIT]);

-

-	    /* Erase socket from pending connect. */

-	    erase_connecting_socket(ioqueue, pos);

-	}

-	pj_lock_release(ioqueue->lock);

-    }

-    return key;

-}

-#endif

-

-/*

- * pj_ioqueue_name()

- */

-PJ_DEF(const char*) pj_ioqueue_name(void)

-{

-    return "iocp";

-}

-

-/*

- * pj_ioqueue_create()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

-				       pj_size_t max_fd,

-				       pj_ioqueue_t **p_ioqueue)

-{

-    pj_ioqueue_t *ioqueue;

-    pj_status_t rc;

-

-    PJ_UNUSED_ARG(max_fd);

-    PJ_ASSERT_RETURN(pool && p_ioqueue, PJ_EINVAL);

-

-    rc = sizeof(union operation_key);

-

-    /* Check that sizeof(pj_ioqueue_op_key_t) makes sense. */

-    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= 

-                     sizeof(union operation_key), PJ_EBUG);

-

-    ioqueue = pj_pool_zalloc(pool, sizeof(*ioqueue));

-    ioqueue->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

-    if (ioqueue->iocp == NULL)

-	return PJ_RETURN_OS_ERROR(GetLastError());

-

-    rc = pj_lock_create_simple_mutex(pool, NULL, &ioqueue->lock);

-    if (rc != PJ_SUCCESS) {

-	CloseHandle(ioqueue->iocp);

-	return rc;

-    }

-

-    ioqueue->auto_delete_lock = PJ_TRUE;

-

-    *p_ioqueue = ioqueue;

-

-    PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioqueue));

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_destroy()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )

-{

-    unsigned i;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

-

-    /* Destroy events in the pool */

-    for (i=0; i<ioqueue->event_count; ++i) {

-	CloseHandle(ioqueue->event_pool[i]);

-    }

-    ioqueue->event_count = 0;

-

-    if (CloseHandle(ioqueue->iocp) != TRUE)

-	return PJ_RETURN_OS_ERROR(GetLastError());

-

-    if (ioqueue->auto_delete_lock)

-        pj_lock_destroy(ioqueue->lock);

-

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_set_lock()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 

-					 pj_lock_t *lock,

-					 pj_bool_t auto_delete )

-{

-    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);

-

-    if (ioqueue->auto_delete_lock) {

-        pj_lock_destroy(ioqueue->lock);

-    }

-

-    ioqueue->lock = lock;

-    ioqueue->auto_delete_lock = auto_delete;

-

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_register_sock()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

-					      pj_ioqueue_t *ioqueue,

-					      pj_sock_t sock,

-					      void *user_data,

-					      const pj_ioqueue_callback *cb,

-					      pj_ioqueue_key_t **key )

-{

-    HANDLE hioq;

-    pj_ioqueue_key_t *rec;

-    u_long value;

-    int rc;

-

-    PJ_ASSERT_RETURN(pool && ioqueue && cb && key, PJ_EINVAL);

-

-    /* Build the key for this socket. */

-    rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));

-    rec->ioqueue = ioqueue;

-    rec->hnd = (HANDLE)sock;

-    rec->hnd_type = HND_IS_SOCKET;

-    rec->user_data = user_data;

-    pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback));

-

-    /* Set socket to nonblocking. */

-    value = 1;

-    rc = ioctlsocket(sock, FIONBIO, &value);

-    if (rc != 0) {

-        return PJ_RETURN_OS_ERROR(WSAGetLastError());

-    }

-

-    /* Associate with IOCP */

-    hioq = CreateIoCompletionPort((HANDLE)sock, ioqueue->iocp, (DWORD)rec, 0);

-    if (!hioq) {

-	return PJ_RETURN_OS_ERROR(GetLastError());

-    }

-

-    *key = rec;

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_unregister()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )

-{

-    PJ_ASSERT_RETURN(key, PJ_EINVAL);

-

-#if PJ_HAS_TCP

-    if (key->connecting) {

-	unsigned pos;

-        pj_ioqueue_t *ioqueue;

-

-        ioqueue = key->ioqueue;

-

-	/* Erase from connecting_handles */

-	pj_lock_acquire(ioqueue->lock);

-	for (pos=0; pos < ioqueue->connecting_count; ++pos) {

-	    if (ioqueue->connecting_keys[pos] == key) {

-		erase_connecting_socket(ioqueue, pos);

-		break;

-	    }

-	}

-	key->connecting = 0;

-	pj_lock_release(ioqueue->lock);

-    }

-#endif

-    if (key->hnd_type == HND_IS_FILE) {

-        CloseHandle(key->hnd);

-    }

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_get_user_data()

- */

-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )

-{

-    PJ_ASSERT_RETURN(key, NULL);

-    return key->user_data;

-}

-

-/*

- * pj_ioqueue_set_user_data()

- */

-PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,

-                                              void *user_data,

-                                              void **old_data )

-{

-    PJ_ASSERT_RETURN(key, PJ_EINVAL);

-    

-    if (old_data)

-        *old_data = key->user_data;

-

-    key->user_data = user_data;

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_ioqueue_poll()

- *

- * Poll for events.

- */

-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)

-{

-    DWORD dwMsec, dwBytesTransfered, dwKey;

-    generic_overlapped *pOv;

-    pj_ioqueue_key_t *key;

-    pj_ssize_t size_status;

-    BOOL rc;

-

-    PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL);

-

-    /* Check the connecting array. */

-#if PJ_HAS_TCP

-    key = check_connecting(ioqueue, &size_status);

-    if (key != NULL) {

-	key->cb.on_connect_complete(key, (int)size_status);

-	return 1;

-    }

-#endif

-

-    /* Calculate miliseconds timeout for GetQueuedCompletionStatus */

-    dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE;

-

-    /* Poll for completion status. */

-    rc = GetQueuedCompletionStatus(ioqueue->iocp, &dwBytesTransfered, &dwKey,

-				   (OVERLAPPED**)&pOv, dwMsec);

-

-    /* The return value is:

-     * - nonzero if event was dequeued.

-     * - zero and pOv==NULL if no event was dequeued.

-     * - zero and pOv!=NULL if event for failed I/O was dequeued.

-     */

-    if (pOv) {

-	/* Event was dequeued for either successfull or failed I/O */

-	key = (pj_ioqueue_key_t*)dwKey;

-	size_status = dwBytesTransfered;

-	switch (pOv->operation) {

-	case PJ_IOQUEUE_OP_READ:

-	case PJ_IOQUEUE_OP_RECV:

-	case PJ_IOQUEUE_OP_RECV_FROM:

-            pOv->operation = 0;

-            if (key->cb.on_read_complete)

-	        key->cb.on_read_complete(key, (pj_ioqueue_op_key_t*)pOv, 

-                                         size_status);

-	    break;

-	case PJ_IOQUEUE_OP_WRITE:

-	case PJ_IOQUEUE_OP_SEND:

-	case PJ_IOQUEUE_OP_SEND_TO:

-            pOv->operation = 0;

-            if (key->cb.on_write_complete)

-	        key->cb.on_write_complete(key, (pj_ioqueue_op_key_t*)pOv, 

-                                                size_status);

-	    break;

-#if PJ_HAS_TCP

-	case PJ_IOQUEUE_OP_ACCEPT:

-	    /* special case for accept. */

-	    ioqueue_on_accept_complete((ioqueue_accept_rec*)pOv);

-            if (key->cb.on_accept_complete) {

-                ioqueue_accept_rec *accept_rec = (ioqueue_accept_rec*)pOv;

-	        key->cb.on_accept_complete(key, 

-                                           (pj_ioqueue_op_key_t*)pOv, 

-                                           accept_rec->newsock,

-                                           PJ_SUCCESS);

-            }

-	    break;

-	case PJ_IOQUEUE_OP_CONNECT:

-#endif

-	case PJ_IOQUEUE_OP_NONE:

-	    pj_assert(0);

-	    break;

-	}

-	return 1;

-    }

-

-    if (GetLastError()==WAIT_TIMEOUT) {

-	/* Check the connecting array (again). */

-#if PJ_HAS_TCP

-	key = check_connecting(ioqueue, &size_status);

-	if (key != NULL) {

-	    key->cb.on_connect_complete(key, (int)size_status);

-	    return 1;

-	}

-#endif

-	return 0;

-    }

-    return -1;

-}

-

-/*

- * pj_ioqueue_recv()

- *

- * Initiate overlapped WSARecv() operation.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,

-                                      pj_ioqueue_op_key_t *op_key,

-				      void *buffer,

-				      pj_ssize_t *length,

-				      pj_uint32_t flags )

-{

-    /*

-     * Ideally we should just call pj_ioqueue_recvfrom() with NULL addr and

-     * addrlen here. But unfortunately it generates EINVAL... :-(

-     *  -bennylp

-     */

-    int rc;

-    DWORD bytesRead;

-    DWORD dwFlags = 0;

-    union operation_key *op_key_rec;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);

-

-    op_key_rec = (union operation_key*)op_key->internal__;

-    op_key_rec->overlapped.wsabuf.buf = buffer;

-    op_key_rec->overlapped.wsabuf.len = *length;

-

-    dwFlags = flags;

-    

-    /* Try non-overlapped received first to see if data is

-     * immediately available.

-     */

-    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {

-	rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

-		     &bytesRead, &dwFlags, NULL, NULL);

-	if (rc == 0) {

-	    *length = bytesRead;

-	    return PJ_SUCCESS;

-	} else {

-	    DWORD dwError = WSAGetLastError();

-	    if (dwError != WSAEWOULDBLOCK) {

-		*length = -1;

-		return PJ_RETURN_OS_ERROR(dwError);

-	    }

-	}

-    }

-

-    dwFlags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

-

-    /*

-     * No immediate data available.

-     * Register overlapped Recv() operation.

-     */

-    pj_memset(&op_key_rec->overlapped.overlapped, 0,

-              sizeof(op_key_rec->overlapped.overlapped));

-    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;

-

-    rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 

-                  &bytesRead, &dwFlags, 

-		  &op_key_rec->overlapped.overlapped, NULL);

-    if (rc == SOCKET_ERROR) {

-	DWORD dwStatus = WSAGetLastError();

-        if (dwStatus!=WSA_IO_PENDING) {

-            *length = -1;

-            return PJ_STATUS_FROM_OS(dwStatus);

-        }

-    }

-

-    /* Pending operation has been scheduled. */

-    return PJ_EPENDING;

-}

-

-/*

- * pj_ioqueue_recvfrom()

- *

- * Initiate overlapped RecvFrom() operation.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,

-                                         pj_ioqueue_op_key_t *op_key,

-					 void *buffer,

-					 pj_ssize_t *length,

-                                         pj_uint32_t flags,

-					 pj_sockaddr_t *addr,

-					 int *addrlen)

-{

-    int rc;

-    DWORD bytesRead;

-    DWORD dwFlags = 0;

-    union operation_key *op_key_rec;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(key && op_key && buffer, PJ_EINVAL);

-

-    op_key_rec = (union operation_key*)op_key->internal__;

-    op_key_rec->overlapped.wsabuf.buf = buffer;

-    op_key_rec->overlapped.wsabuf.len = *length;

-

-    dwFlags = flags;

-    

-    /* Try non-overlapped received first to see if data is

-     * immediately available.

-     */

-    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {

-	rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

-			 &bytesRead, &dwFlags, addr, addrlen, NULL, NULL);

-	if (rc == 0) {

-	    *length = bytesRead;

-	    return PJ_SUCCESS;

-	} else {

-	    DWORD dwError = WSAGetLastError();

-	    if (dwError != WSAEWOULDBLOCK) {

-		*length = -1;

-		return PJ_RETURN_OS_ERROR(dwError);

-	    }

-	}

-    }

-

-    dwFlags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

-

-    /*

-     * No immediate data available.

-     * Register overlapped Recv() operation.

-     */

-    pj_memset(&op_key_rec->overlapped.overlapped, 0,

-              sizeof(op_key_rec->overlapped.overlapped));

-    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;

-

-    rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 

-                     &bytesRead, &dwFlags, addr, addrlen,

-		     &op_key_rec->overlapped.overlapped, NULL);

-    if (rc == SOCKET_ERROR) {

-	DWORD dwStatus = WSAGetLastError();

-        if (dwStatus!=WSA_IO_PENDING) {

-            *length = -1;

-            return PJ_STATUS_FROM_OS(dwStatus);

-        }

-    } 

-    

-    /* Pending operation has been scheduled. */

-    return PJ_EPENDING;

-}

-

-/*

- * pj_ioqueue_send()

- *

- * Initiate overlapped Send operation.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_send(  pj_ioqueue_key_t *key,

-                                      pj_ioqueue_op_key_t *op_key,

-				      const void *data,

-				      pj_ssize_t *length,

-				      pj_uint32_t flags )

-{

-    return pj_ioqueue_sendto(key, op_key, data, length, flags, NULL, 0);

-}

-

-

-/*

- * pj_ioqueue_sendto()

- *

- * Initiate overlapped SendTo operation.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,

-                                       pj_ioqueue_op_key_t *op_key,

-				       const void *data,

-				       pj_ssize_t *length,

-                                       pj_uint32_t flags,

-				       const pj_sockaddr_t *addr,

-				       int addrlen)

-{

-    int rc;

-    DWORD bytesWritten;

-    DWORD dwFlags;

-    union operation_key *op_key_rec;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(key && op_key && data, PJ_EINVAL);

-    

-    op_key_rec = (union operation_key*)op_key->internal__;

-

-    /*

-     * First try blocking write.

-     */

-    op_key_rec->overlapped.wsabuf.buf = (void*)data;

-    op_key_rec->overlapped.wsabuf.len = *length;

-

-    dwFlags = flags;

-

-    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {

-	rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

-		       &bytesWritten, dwFlags, addr, addrlen,

-		       NULL, NULL);

-	if (rc == 0) {

-	    *length = bytesWritten;

-	    return PJ_SUCCESS;

-	} else {

-	    DWORD dwStatus = WSAGetLastError();

-	    if (dwStatus != WSAEWOULDBLOCK) {

-		*length = -1;

-		return PJ_RETURN_OS_ERROR(dwStatus);

-	    }

-	}

-    }

-

-    dwFlags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);

-

-    /*

-     * Data can't be sent immediately.

-     * Schedule asynchronous WSASend().

-     */

-    pj_memset(&op_key_rec->overlapped.overlapped, 0,

-              sizeof(op_key_rec->overlapped.overlapped));

-    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_SEND;

-

-    rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

-                   &bytesWritten,  dwFlags, addr, addrlen,

-		   &op_key_rec->overlapped.overlapped, NULL);

-    if (rc == SOCKET_ERROR) {

-	DWORD dwStatus = WSAGetLastError();

-        if (dwStatus!=WSA_IO_PENDING)

-            return PJ_STATUS_FROM_OS(dwStatus);

-    }

-

-    /* Asynchronous operation successfully submitted. */

-    return PJ_EPENDING;

-}

-

-#if PJ_HAS_TCP

-

-/*

- * pj_ioqueue_accept()

- *

- * Initiate overlapped accept() operation.

- */

-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,

-                                       pj_ioqueue_op_key_t *op_key,

-			               pj_sock_t *new_sock,

-			               pj_sockaddr_t *local,

-			               pj_sockaddr_t *remote,

-			               int *addrlen)

-{

-    BOOL rc;

-    DWORD bytesReceived;

-    pj_status_t status;

-    union operation_key *op_key_rec;

-    SOCKET sock;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);

-

-    /*

-     * See if there is a new connection immediately available.

-     */

-    sock = WSAAccept((SOCKET)key->hnd, remote, addrlen, NULL, 0);

-    if (sock != INVALID_SOCKET) {

-        /* Yes! New socket is available! */

-        int status;

-

-        status = getsockname(sock, local, addrlen);

-        if (status != 0) {

-            DWORD dwError = WSAGetLastError();

-            closesocket(sock);

-            return PJ_RETURN_OS_ERROR(dwError);

-        }

-

-        *new_sock = sock;

-        return PJ_SUCCESS;

-

-    } else {

-        DWORD dwError = WSAGetLastError();

-        if (dwError != WSAEWOULDBLOCK) {

-            return PJ_RETURN_OS_ERROR(dwError);

-        }

-    }

-

-    /*

-     * No connection is immediately available.

-     * Must schedule an asynchronous operation.

-     */

-    op_key_rec = (union operation_key*)op_key->internal__;

-    

-    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, 

-                            &op_key_rec->accept.newsock);

-    if (status != PJ_SUCCESS)

-	return status;

-

-    /* On WinXP or later, use SO_UPDATE_ACCEPT_CONTEXT so that socket 

-     * addresses can be obtained with getsockname() and getpeername().

-     */

-    status = setsockopt(op_key_rec->accept.newsock, SOL_SOCKET,

-                        SO_UPDATE_ACCEPT_CONTEXT, 

-                        (char*)&key->hnd, sizeof(SOCKET));

-    /* SO_UPDATE_ACCEPT_CONTEXT is for WinXP or later.

-     * So ignore the error status.

-     */

-

-    op_key_rec->accept.operation = PJ_IOQUEUE_OP_ACCEPT;

-    op_key_rec->accept.addrlen = addrlen;

-    op_key_rec->accept.local = local;

-    op_key_rec->accept.remote = remote;

-    op_key_rec->accept.newsock_ptr = new_sock;

-    pj_memset(&op_key_rec->accept.overlapped, 0, 

-	      sizeof(op_key_rec->accept.overlapped));

-

-    rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)op_key_rec->accept.newsock,

-		   op_key_rec->accept.accept_buf,

-		   0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN,

-		   &bytesReceived,

-		   &op_key_rec->accept.overlapped );

-

-    if (rc == TRUE) {

-	ioqueue_on_accept_complete(&op_key_rec->accept);

-	return PJ_SUCCESS;

-    } else {

-	DWORD dwStatus = WSAGetLastError();

-	if (dwStatus!=WSA_IO_PENDING)

-            return PJ_STATUS_FROM_OS(dwStatus);

-    }

-

-    /* Asynchronous Accept() has been submitted. */

-    return PJ_EPENDING;

-}

-

-

-/*

- * pj_ioqueue_connect()

- *

- * 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_key_t *key,

-					const pj_sockaddr_t *addr,

-					int addrlen )

-{

-    HANDLE hEvent;

-    pj_ioqueue_t *ioqueue;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);

-

-    /* Initiate connect() */

-    if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) {

-	DWORD dwStatus;

-	dwStatus = WSAGetLastError();

-        if (dwStatus != WSAEWOULDBLOCK) {

-	    return PJ_RETURN_OS_ERROR(dwStatus);

-	}

-    } else {

-	/* Connect has completed immediately! */

-	return PJ_SUCCESS;

-    }

-

-    ioqueue = key->ioqueue;

-

-    /* Add to the array of connecting socket to be polled */

-    pj_lock_acquire(ioqueue->lock);

-

-    if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) {

-	pj_lock_release(ioqueue->lock);

-	return PJ_ETOOMANYCONN;

-    }

-

-    /* Get or create event object. */

-    if (ioqueue->event_count) {

-	hEvent = ioqueue->event_pool[ioqueue->event_count - 1];

-	--ioqueue->event_count;

-    } else {

-	hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

-	if (hEvent == NULL) {

-	    DWORD dwStatus = GetLastError();

-	    pj_lock_release(ioqueue->lock);

-	    return PJ_STATUS_FROM_OS(dwStatus);

-	}

-    }

-

-    /* Mark key as connecting.

-     * We can't use array index since key can be removed dynamically. 

-     */

-    key->connecting = 1;

-

-    /* Associate socket events to the event object. */

-    if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) {

-	CloseHandle(hEvent);

-	pj_lock_release(ioqueue->lock);

-	return PJ_RETURN_OS_ERROR(WSAGetLastError());

-    }

-

-    /* Add to array. */

-    ioqueue->connecting_keys[ ioqueue->connecting_count ] = key;

-    ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent;

-    ioqueue->connecting_count++;

-

-    pj_lock_release(ioqueue->lock);

-

-    return PJ_EPENDING;

-}

-#endif	/* #if PJ_HAS_TCP */

-

-

-PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,

-				     pj_size_t size )

-{

-    pj_memset(op_key, 0, size);

-}

-

-PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,

-                                         pj_ioqueue_op_key_t *op_key )

-{

-    BOOL rc;

-    DWORD bytesTransfered;

-

-    rc = GetOverlappedResult( key->hnd, (LPOVERLAPPED)op_key,

-                              &bytesTransfered, FALSE );

-

-    if (rc == FALSE) {

-        return GetLastError()==ERROR_IO_INCOMPLETE;

-    }

-

-    return FALSE;

-}

-

-

-PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,

-                                                pj_ioqueue_op_key_t *op_key,

-                                                pj_ssize_t bytes_status )

-{

-    BOOL rc;

-

-    rc = PostQueuedCompletionStatus(key->ioqueue->iocp, bytes_status,

-                                    (long)key, (OVERLAPPED*)op_key );

-    if (rc == FALSE) {

-        return PJ_RETURN_OS_ERROR(GetLastError());

-    }

-

-    return PJ_SUCCESS;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/lock.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/sock.h>
+#include <pj/array.h>
+#include <pj/log.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+
+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
+#  include <winsock2.h>
+#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
+#  include <winsock.h>
+#endif
+
+#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0
+#  include <mswsock.h>
+#endif
+
+
+/* The address specified in AcceptEx() must be 16 more than the size of
+ * SOCKADDR (source: MSDN).
+ */
+#define ACCEPT_ADDR_LEN	    (sizeof(pj_sockaddr_in)+16)
+
+typedef struct generic_overlapped
+{
+    WSAOVERLAPPED	   overlapped;
+    pj_ioqueue_operation_e operation;
+} generic_overlapped;
+
+/*
+ * OVERLAPPPED structure for send and receive.
+ */
+typedef struct ioqueue_overlapped
+{
+    WSAOVERLAPPED	   overlapped;
+    pj_ioqueue_operation_e operation;
+    WSABUF		   wsabuf;
+    pj_sockaddr_in         dummy_addr;
+    int                    dummy_addrlen;
+} ioqueue_overlapped;
+
+#if PJ_HAS_TCP
+/*
+ * OVERLAP structure for accept.
+ */
+typedef struct ioqueue_accept_rec
+{
+    WSAOVERLAPPED	    overlapped;
+    pj_ioqueue_operation_e  operation;
+    pj_sock_t		    newsock;
+    pj_sock_t		   *newsock_ptr;
+    int			   *addrlen;
+    void		   *remote;
+    void		   *local;
+    char		    accept_buf[2 * ACCEPT_ADDR_LEN];
+} ioqueue_accept_rec;
+#endif
+
+/*
+ * Structure to hold pending operation key.
+ */
+union operation_key
+{
+    generic_overlapped      generic;
+    ioqueue_overlapped      overlapped;
+#if PJ_HAS_TCP
+    ioqueue_accept_rec      accept;
+#endif
+};
+
+/* Type of handle in the key. */
+enum handle_type
+{
+    HND_IS_UNKNOWN,
+    HND_IS_FILE,
+    HND_IS_SOCKET,
+};
+
+/*
+ * Structure for individual socket.
+ */
+struct pj_ioqueue_key_t
+{
+    pj_ioqueue_t       *ioqueue;
+    HANDLE		hnd;
+    void	       *user_data;
+    enum handle_type    hnd_type;
+#if PJ_HAS_TCP
+    int			connecting;
+#endif
+    pj_ioqueue_callback	cb;
+};
+
+/*
+ * IO Queue structure.
+ */
+struct pj_ioqueue_t
+{
+    HANDLE	      iocp;
+    pj_lock_t        *lock;
+    pj_bool_t         auto_delete_lock;
+    unsigned	      event_count;
+    HANDLE	      event_pool[MAXIMUM_WAIT_OBJECTS+1];
+#if PJ_HAS_TCP
+    unsigned	      connecting_count;
+    HANDLE	      connecting_handles[MAXIMUM_WAIT_OBJECTS+1];
+    pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1];
+#endif
+};
+
+
+#if PJ_HAS_TCP
+/*
+ * Process the socket when the overlapped accept() completed.
+ */
+static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped)
+{
+    struct sockaddr *local;
+    struct sockaddr *remote;
+    int locallen, remotelen;
+
+    PJ_CHECK_STACK();
+
+    /* Operation complete immediately. */
+    GetAcceptExSockaddrs( accept_overlapped->accept_buf,
+			  0, 
+			  ACCEPT_ADDR_LEN,
+			  ACCEPT_ADDR_LEN,
+			  &local,
+			  &locallen,
+			  &remote,
+			  &remotelen);
+    if (*accept_overlapped->addrlen > locallen) {
+        pj_memcpy(accept_overlapped->local, local, locallen);
+        pj_memcpy(accept_overlapped->remote, remote, locallen);
+    } else {
+        pj_memset(accept_overlapped->local, 0, *accept_overlapped->addrlen);
+        pj_memset(accept_overlapped->remote, 0, *accept_overlapped->addrlen);
+    }
+    *accept_overlapped->addrlen = locallen;
+    if (accept_overlapped->newsock_ptr)
+        *accept_overlapped->newsock_ptr = accept_overlapped->newsock;
+    accept_overlapped->operation = 0;
+    accept_overlapped->newsock = PJ_INVALID_SOCKET;
+}
+
+static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos)
+{
+    pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos];
+    HANDLE hEvent = ioqueue->connecting_handles[pos];
+
+    /* Remove key from array of connecting handles. */
+    pj_array_erase(ioqueue->connecting_keys, sizeof(key),
+		   ioqueue->connecting_count, pos);
+    pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE),
+		   ioqueue->connecting_count, pos);
+    --ioqueue->connecting_count;
+
+    /* Disassociate the socket from the event. */
+    WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0);
+
+    /* Put event object to pool. */
+    if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) {
+	ioqueue->event_pool[ioqueue->event_count++] = hEvent;
+    } else {
+	/* Shouldn't happen. There should be no more pending connections
+	 * than max. 
+	 */
+	pj_assert(0);
+	CloseHandle(hEvent);
+    }
+
+}
+
+/*
+ * Poll for the completion of non-blocking connect().
+ * If there's a completion, the function return the key of the completed
+ * socket, and 'result' argument contains the connect() result. If connect()
+ * succeeded, 'result' will have value zero, otherwise will have the error
+ * code.
+ */
+static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue, 
+					   pj_ssize_t *connect_err )
+{
+    pj_ioqueue_key_t *key = NULL;
+
+    if (ioqueue->connecting_count) {
+	DWORD result;
+
+	pj_lock_acquire(ioqueue->lock);
+	result = WaitForMultipleObjects(ioqueue->connecting_count,
+					ioqueue->connecting_handles,
+					FALSE, 0);
+	if (result >= WAIT_OBJECT_0 && 
+	    result < WAIT_OBJECT_0+ioqueue->connecting_count) 
+	{
+	    WSANETWORKEVENTS net_events;
+
+	    /* Got completed connect(). */
+	    unsigned pos = result - WAIT_OBJECT_0;
+	    key = ioqueue->connecting_keys[pos];
+
+	    /* See whether connect has succeeded. */
+	    WSAEnumNetworkEvents((pj_sock_t)key->hnd, 
+				 ioqueue->connecting_handles[pos], 
+				 &net_events);
+	    *connect_err = 
+                PJ_STATUS_FROM_OS(net_events.iErrorCode[FD_CONNECT_BIT]);
+
+	    /* Erase socket from pending connect. */
+	    erase_connecting_socket(ioqueue, pos);
+	}
+	pj_lock_release(ioqueue->lock);
+    }
+    return key;
+}
+#endif
+
+/*
+ * pj_ioqueue_name()
+ */
+PJ_DEF(const char*) pj_ioqueue_name(void)
+{
+    return "iocp";
+}
+
+/*
+ * pj_ioqueue_create()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
+				       pj_size_t max_fd,
+				       pj_ioqueue_t **p_ioqueue)
+{
+    pj_ioqueue_t *ioqueue;
+    pj_status_t rc;
+
+    PJ_UNUSED_ARG(max_fd);
+    PJ_ASSERT_RETURN(pool && p_ioqueue, PJ_EINVAL);
+
+    rc = sizeof(union operation_key);
+
+    /* Check that sizeof(pj_ioqueue_op_key_t) makes sense. */
+    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= 
+                     sizeof(union operation_key), PJ_EBUG);
+
+    ioqueue = pj_pool_zalloc(pool, sizeof(*ioqueue));
+    ioqueue->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+    if (ioqueue->iocp == NULL)
+	return PJ_RETURN_OS_ERROR(GetLastError());
+
+    rc = pj_lock_create_simple_mutex(pool, NULL, &ioqueue->lock);
+    if (rc != PJ_SUCCESS) {
+	CloseHandle(ioqueue->iocp);
+	return rc;
+    }
+
+    ioqueue->auto_delete_lock = PJ_TRUE;
+
+    *p_ioqueue = ioqueue;
+
+    PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioqueue));
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_destroy()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )
+{
+    unsigned i;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
+
+    /* Destroy events in the pool */
+    for (i=0; i<ioqueue->event_count; ++i) {
+	CloseHandle(ioqueue->event_pool[i]);
+    }
+    ioqueue->event_count = 0;
+
+    if (CloseHandle(ioqueue->iocp) != TRUE)
+	return PJ_RETURN_OS_ERROR(GetLastError());
+
+    if (ioqueue->auto_delete_lock)
+        pj_lock_destroy(ioqueue->lock);
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_set_lock()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 
+					 pj_lock_t *lock,
+					 pj_bool_t auto_delete )
+{
+    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
+
+    if (ioqueue->auto_delete_lock) {
+        pj_lock_destroy(ioqueue->lock);
+    }
+
+    ioqueue->lock = lock;
+    ioqueue->auto_delete_lock = auto_delete;
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_register_sock()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					      pj_ioqueue_t *ioqueue,
+					      pj_sock_t sock,
+					      void *user_data,
+					      const pj_ioqueue_callback *cb,
+					      pj_ioqueue_key_t **key )
+{
+    HANDLE hioq;
+    pj_ioqueue_key_t *rec;
+    u_long value;
+    int rc;
+
+    PJ_ASSERT_RETURN(pool && ioqueue && cb && key, PJ_EINVAL);
+
+    /* Build the key for this socket. */
+    rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+    rec->ioqueue = ioqueue;
+    rec->hnd = (HANDLE)sock;
+    rec->hnd_type = HND_IS_SOCKET;
+    rec->user_data = user_data;
+    pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback));
+
+    /* Set socket to nonblocking. */
+    value = 1;
+    rc = ioctlsocket(sock, FIONBIO, &value);
+    if (rc != 0) {
+        return PJ_RETURN_OS_ERROR(WSAGetLastError());
+    }
+
+    /* Associate with IOCP */
+    hioq = CreateIoCompletionPort((HANDLE)sock, ioqueue->iocp, (DWORD)rec, 0);
+    if (!hioq) {
+	return PJ_RETURN_OS_ERROR(GetLastError());
+    }
+
+    *key = rec;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_unregister()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
+{
+    PJ_ASSERT_RETURN(key, PJ_EINVAL);
+
+#if PJ_HAS_TCP
+    if (key->connecting) {
+	unsigned pos;
+        pj_ioqueue_t *ioqueue;
+
+        ioqueue = key->ioqueue;
+
+	/* Erase from connecting_handles */
+	pj_lock_acquire(ioqueue->lock);
+	for (pos=0; pos < ioqueue->connecting_count; ++pos) {
+	    if (ioqueue->connecting_keys[pos] == key) {
+		erase_connecting_socket(ioqueue, pos);
+		break;
+	    }
+	}
+	key->connecting = 0;
+	pj_lock_release(ioqueue->lock);
+    }
+#endif
+    if (key->hnd_type == HND_IS_FILE) {
+        CloseHandle(key->hnd);
+    }
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_get_user_data()
+ */
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+    PJ_ASSERT_RETURN(key, NULL);
+    return key->user_data;
+}
+
+/*
+ * pj_ioqueue_set_user_data()
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+                                              void *user_data,
+                                              void **old_data )
+{
+    PJ_ASSERT_RETURN(key, PJ_EINVAL);
+    
+    if (old_data)
+        *old_data = key->user_data;
+
+    key->user_data = user_data;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_ioqueue_poll()
+ *
+ * Poll for events.
+ */
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
+{
+    DWORD dwMsec, dwBytesTransfered, dwKey;
+    generic_overlapped *pOv;
+    pj_ioqueue_key_t *key;
+    pj_ssize_t size_status;
+    BOOL rc;
+
+    PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL);
+
+    /* Check the connecting array. */
+#if PJ_HAS_TCP
+    key = check_connecting(ioqueue, &size_status);
+    if (key != NULL) {
+	key->cb.on_connect_complete(key, (int)size_status);
+	return 1;
+    }
+#endif
+
+    /* Calculate miliseconds timeout for GetQueuedCompletionStatus */
+    dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE;
+
+    /* Poll for completion status. */
+    rc = GetQueuedCompletionStatus(ioqueue->iocp, &dwBytesTransfered, &dwKey,
+				   (OVERLAPPED**)&pOv, dwMsec);
+
+    /* The return value is:
+     * - nonzero if event was dequeued.
+     * - zero and pOv==NULL if no event was dequeued.
+     * - zero and pOv!=NULL if event for failed I/O was dequeued.
+     */
+    if (pOv) {
+	/* Event was dequeued for either successfull or failed I/O */
+	key = (pj_ioqueue_key_t*)dwKey;
+	size_status = dwBytesTransfered;
+	switch (pOv->operation) {
+	case PJ_IOQUEUE_OP_READ:
+	case PJ_IOQUEUE_OP_RECV:
+	case PJ_IOQUEUE_OP_RECV_FROM:
+            pOv->operation = 0;
+            if (key->cb.on_read_complete)
+	        key->cb.on_read_complete(key, (pj_ioqueue_op_key_t*)pOv, 
+                                         size_status);
+	    break;
+	case PJ_IOQUEUE_OP_WRITE:
+	case PJ_IOQUEUE_OP_SEND:
+	case PJ_IOQUEUE_OP_SEND_TO:
+            pOv->operation = 0;
+            if (key->cb.on_write_complete)
+	        key->cb.on_write_complete(key, (pj_ioqueue_op_key_t*)pOv, 
+                                                size_status);
+	    break;
+#if PJ_HAS_TCP
+	case PJ_IOQUEUE_OP_ACCEPT:
+	    /* special case for accept. */
+	    ioqueue_on_accept_complete((ioqueue_accept_rec*)pOv);
+            if (key->cb.on_accept_complete) {
+                ioqueue_accept_rec *accept_rec = (ioqueue_accept_rec*)pOv;
+	        key->cb.on_accept_complete(key, 
+                                           (pj_ioqueue_op_key_t*)pOv, 
+                                           accept_rec->newsock,
+                                           PJ_SUCCESS);
+            }
+	    break;
+	case PJ_IOQUEUE_OP_CONNECT:
+#endif
+	case PJ_IOQUEUE_OP_NONE:
+	    pj_assert(0);
+	    break;
+	}
+	return 1;
+    }
+
+    if (GetLastError()==WAIT_TIMEOUT) {
+	/* Check the connecting array (again). */
+#if PJ_HAS_TCP
+	key = check_connecting(ioqueue, &size_status);
+	if (key != NULL) {
+	    key->cb.on_connect_complete(key, (int)size_status);
+	    return 1;
+	}
+#endif
+	return 0;
+    }
+    return -1;
+}
+
+/*
+ * pj_ioqueue_recv()
+ *
+ * Initiate overlapped WSARecv() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,
+                                      pj_ioqueue_op_key_t *op_key,
+				      void *buffer,
+				      pj_ssize_t *length,
+				      pj_uint32_t flags )
+{
+    /*
+     * Ideally we should just call pj_ioqueue_recvfrom() with NULL addr and
+     * addrlen here. But unfortunately it generates EINVAL... :-(
+     *  -bennylp
+     */
+    int rc;
+    DWORD bytesRead;
+    DWORD dwFlags = 0;
+    union operation_key *op_key_rec;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
+
+    op_key_rec = (union operation_key*)op_key->internal__;
+    op_key_rec->overlapped.wsabuf.buf = buffer;
+    op_key_rec->overlapped.wsabuf.len = *length;
+
+    dwFlags = flags;
+    
+    /* Try non-overlapped received first to see if data is
+     * immediately available.
+     */
+    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
+	rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+		     &bytesRead, &dwFlags, NULL, NULL);
+	if (rc == 0) {
+	    *length = bytesRead;
+	    return PJ_SUCCESS;
+	} else {
+	    DWORD dwError = WSAGetLastError();
+	    if (dwError != WSAEWOULDBLOCK) {
+		*length = -1;
+		return PJ_RETURN_OS_ERROR(dwError);
+	    }
+	}
+    }
+
+    dwFlags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+    /*
+     * No immediate data available.
+     * Register overlapped Recv() operation.
+     */
+    pj_memset(&op_key_rec->overlapped.overlapped, 0,
+              sizeof(op_key_rec->overlapped.overlapped));
+    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
+
+    rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 
+                  &bytesRead, &dwFlags, 
+		  &op_key_rec->overlapped.overlapped, NULL);
+    if (rc == SOCKET_ERROR) {
+	DWORD dwStatus = WSAGetLastError();
+        if (dwStatus!=WSA_IO_PENDING) {
+            *length = -1;
+            return PJ_STATUS_FROM_OS(dwStatus);
+        }
+    }
+
+    /* Pending operation has been scheduled. */
+    return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_recvfrom()
+ *
+ * Initiate overlapped RecvFrom() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
+                                         pj_ioqueue_op_key_t *op_key,
+					 void *buffer,
+					 pj_ssize_t *length,
+                                         pj_uint32_t flags,
+					 pj_sockaddr_t *addr,
+					 int *addrlen)
+{
+    int rc;
+    DWORD bytesRead;
+    DWORD dwFlags = 0;
+    union operation_key *op_key_rec;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(key && op_key && buffer, PJ_EINVAL);
+
+    op_key_rec = (union operation_key*)op_key->internal__;
+    op_key_rec->overlapped.wsabuf.buf = buffer;
+    op_key_rec->overlapped.wsabuf.len = *length;
+
+    dwFlags = flags;
+    
+    /* Try non-overlapped received first to see if data is
+     * immediately available.
+     */
+    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
+	rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+			 &bytesRead, &dwFlags, addr, addrlen, NULL, NULL);
+	if (rc == 0) {
+	    *length = bytesRead;
+	    return PJ_SUCCESS;
+	} else {
+	    DWORD dwError = WSAGetLastError();
+	    if (dwError != WSAEWOULDBLOCK) {
+		*length = -1;
+		return PJ_RETURN_OS_ERROR(dwError);
+	    }
+	}
+    }
+
+    dwFlags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+    /*
+     * No immediate data available.
+     * Register overlapped Recv() operation.
+     */
+    pj_memset(&op_key_rec->overlapped.overlapped, 0,
+              sizeof(op_key_rec->overlapped.overlapped));
+    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
+
+    rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 
+                     &bytesRead, &dwFlags, addr, addrlen,
+		     &op_key_rec->overlapped.overlapped, NULL);
+    if (rc == SOCKET_ERROR) {
+	DWORD dwStatus = WSAGetLastError();
+        if (dwStatus!=WSA_IO_PENDING) {
+            *length = -1;
+            return PJ_STATUS_FROM_OS(dwStatus);
+        }
+    } 
+    
+    /* Pending operation has been scheduled. */
+    return PJ_EPENDING;
+}
+
+/*
+ * pj_ioqueue_send()
+ *
+ * Initiate overlapped Send operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_send(  pj_ioqueue_key_t *key,
+                                      pj_ioqueue_op_key_t *op_key,
+				      const void *data,
+				      pj_ssize_t *length,
+				      pj_uint32_t flags )
+{
+    return pj_ioqueue_sendto(key, op_key, data, length, flags, NULL, 0);
+}
+
+
+/*
+ * pj_ioqueue_sendto()
+ *
+ * Initiate overlapped SendTo operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
+                                       pj_ioqueue_op_key_t *op_key,
+				       const void *data,
+				       pj_ssize_t *length,
+                                       pj_uint32_t flags,
+				       const pj_sockaddr_t *addr,
+				       int addrlen)
+{
+    int rc;
+    DWORD bytesWritten;
+    DWORD dwFlags;
+    union operation_key *op_key_rec;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(key && op_key && data, PJ_EINVAL);
+    
+    op_key_rec = (union operation_key*)op_key->internal__;
+
+    /*
+     * First try blocking write.
+     */
+    op_key_rec->overlapped.wsabuf.buf = (void*)data;
+    op_key_rec->overlapped.wsabuf.len = *length;
+
+    dwFlags = flags;
+
+    if ((flags & PJ_IOQUEUE_ALWAYS_ASYNC) == 0) {
+	rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+		       &bytesWritten, dwFlags, addr, addrlen,
+		       NULL, NULL);
+	if (rc == 0) {
+	    *length = bytesWritten;
+	    return PJ_SUCCESS;
+	} else {
+	    DWORD dwStatus = WSAGetLastError();
+	    if (dwStatus != WSAEWOULDBLOCK) {
+		*length = -1;
+		return PJ_RETURN_OS_ERROR(dwStatus);
+	    }
+	}
+    }
+
+    dwFlags &= ~(PJ_IOQUEUE_ALWAYS_ASYNC);
+
+    /*
+     * Data can't be sent immediately.
+     * Schedule asynchronous WSASend().
+     */
+    pj_memset(&op_key_rec->overlapped.overlapped, 0,
+              sizeof(op_key_rec->overlapped.overlapped));
+    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_SEND;
+
+    rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
+                   &bytesWritten,  dwFlags, addr, addrlen,
+		   &op_key_rec->overlapped.overlapped, NULL);
+    if (rc == SOCKET_ERROR) {
+	DWORD dwStatus = WSAGetLastError();
+        if (dwStatus!=WSA_IO_PENDING)
+            return PJ_STATUS_FROM_OS(dwStatus);
+    }
+
+    /* Asynchronous operation successfully submitted. */
+    return PJ_EPENDING;
+}
+
+#if PJ_HAS_TCP
+
+/*
+ * pj_ioqueue_accept()
+ *
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
+                                       pj_ioqueue_op_key_t *op_key,
+			               pj_sock_t *new_sock,
+			               pj_sockaddr_t *local,
+			               pj_sockaddr_t *remote,
+			               int *addrlen)
+{
+    BOOL rc;
+    DWORD bytesReceived;
+    pj_status_t status;
+    union operation_key *op_key_rec;
+    SOCKET sock;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
+
+    /*
+     * See if there is a new connection immediately available.
+     */
+    sock = WSAAccept((SOCKET)key->hnd, remote, addrlen, NULL, 0);
+    if (sock != INVALID_SOCKET) {
+        /* Yes! New socket is available! */
+        int status;
+
+        status = getsockname(sock, local, addrlen);
+        if (status != 0) {
+            DWORD dwError = WSAGetLastError();
+            closesocket(sock);
+            return PJ_RETURN_OS_ERROR(dwError);
+        }
+
+        *new_sock = sock;
+        return PJ_SUCCESS;
+
+    } else {
+        DWORD dwError = WSAGetLastError();
+        if (dwError != WSAEWOULDBLOCK) {
+            return PJ_RETURN_OS_ERROR(dwError);
+        }
+    }
+
+    /*
+     * No connection is immediately available.
+     * Must schedule an asynchronous operation.
+     */
+    op_key_rec = (union operation_key*)op_key->internal__;
+    
+    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, 
+                            &op_key_rec->accept.newsock);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* On WinXP or later, use SO_UPDATE_ACCEPT_CONTEXT so that socket 
+     * addresses can be obtained with getsockname() and getpeername().
+     */
+    status = setsockopt(op_key_rec->accept.newsock, SOL_SOCKET,
+                        SO_UPDATE_ACCEPT_CONTEXT, 
+                        (char*)&key->hnd, sizeof(SOCKET));
+    /* SO_UPDATE_ACCEPT_CONTEXT is for WinXP or later.
+     * So ignore the error status.
+     */
+
+    op_key_rec->accept.operation = PJ_IOQUEUE_OP_ACCEPT;
+    op_key_rec->accept.addrlen = addrlen;
+    op_key_rec->accept.local = local;
+    op_key_rec->accept.remote = remote;
+    op_key_rec->accept.newsock_ptr = new_sock;
+    pj_memset(&op_key_rec->accept.overlapped, 0, 
+	      sizeof(op_key_rec->accept.overlapped));
+
+    rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)op_key_rec->accept.newsock,
+		   op_key_rec->accept.accept_buf,
+		   0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN,
+		   &bytesReceived,
+		   &op_key_rec->accept.overlapped );
+
+    if (rc == TRUE) {
+	ioqueue_on_accept_complete(&op_key_rec->accept);
+	return PJ_SUCCESS;
+    } else {
+	DWORD dwStatus = WSAGetLastError();
+	if (dwStatus!=WSA_IO_PENDING)
+            return PJ_STATUS_FROM_OS(dwStatus);
+    }
+
+    /* Asynchronous Accept() has been submitted. */
+    return PJ_EPENDING;
+}
+
+
+/*
+ * pj_ioqueue_connect()
+ *
+ * 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_key_t *key,
+					const pj_sockaddr_t *addr,
+					int addrlen )
+{
+    HANDLE hEvent;
+    pj_ioqueue_t *ioqueue;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
+
+    /* Initiate connect() */
+    if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) {
+	DWORD dwStatus;
+	dwStatus = WSAGetLastError();
+        if (dwStatus != WSAEWOULDBLOCK) {
+	    return PJ_RETURN_OS_ERROR(dwStatus);
+	}
+    } else {
+	/* Connect has completed immediately! */
+	return PJ_SUCCESS;
+    }
+
+    ioqueue = key->ioqueue;
+
+    /* Add to the array of connecting socket to be polled */
+    pj_lock_acquire(ioqueue->lock);
+
+    if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) {
+	pj_lock_release(ioqueue->lock);
+	return PJ_ETOOMANYCONN;
+    }
+
+    /* Get or create event object. */
+    if (ioqueue->event_count) {
+	hEvent = ioqueue->event_pool[ioqueue->event_count - 1];
+	--ioqueue->event_count;
+    } else {
+	hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+	if (hEvent == NULL) {
+	    DWORD dwStatus = GetLastError();
+	    pj_lock_release(ioqueue->lock);
+	    return PJ_STATUS_FROM_OS(dwStatus);
+	}
+    }
+
+    /* Mark key as connecting.
+     * We can't use array index since key can be removed dynamically. 
+     */
+    key->connecting = 1;
+
+    /* Associate socket events to the event object. */
+    if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) {
+	CloseHandle(hEvent);
+	pj_lock_release(ioqueue->lock);
+	return PJ_RETURN_OS_ERROR(WSAGetLastError());
+    }
+
+    /* Add to array. */
+    ioqueue->connecting_keys[ ioqueue->connecting_count ] = key;
+    ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent;
+    ioqueue->connecting_count++;
+
+    pj_lock_release(ioqueue->lock);
+
+    return PJ_EPENDING;
+}
+#endif	/* #if PJ_HAS_TCP */
+
+
+PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
+				     pj_size_t size )
+{
+    pj_memset(op_key, 0, size);
+}
+
+PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
+                                         pj_ioqueue_op_key_t *op_key )
+{
+    BOOL rc;
+    DWORD bytesTransfered;
+
+    rc = GetOverlappedResult( key->hnd, (LPOVERLAPPED)op_key,
+                              &bytesTransfered, FALSE );
+
+    if (rc == FALSE) {
+        return GetLastError()==ERROR_IO_INCOMPLETE;
+    }
+
+    return FALSE;
+}
+
+
+PJ_DEF(pj_status_t) pj_ioqueue_post_completion( pj_ioqueue_key_t *key,
+                                                pj_ioqueue_op_key_t *op_key,
+                                                pj_ssize_t bytes_status )
+{
+    BOOL rc;
+
+    rc = PostQueuedCompletionStatus(key->ioqueue->iocp, bytes_status,
+                                    (long)key, (OVERLAPPED*)op_key );
+    if (rc == FALSE) {
+        return PJ_RETURN_OS_ERROR(GetLastError());
+    }
+
+    return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/list.c b/pjlib/src/pj/list.c
index c39814d..98d98bb 100644
--- a/pjlib/src/pj/list.c
+++ b/pjlib/src/pj/list.c
@@ -1,25 +1,25 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/list.h>

-

-#if !PJ_FUNCTIONS_ARE_INLINED

-#  include <pj/list_i.h>

-#endif

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/list.h>
+
+#if !PJ_FUNCTIONS_ARE_INLINED
+#  include <pj/list_i.h>
+#endif
+
+
diff --git a/pjlib/src/pj/lock.c b/pjlib/src/pj/lock.c
index 2422905..65de868 100644
--- a/pjlib/src/pj/lock.c
+++ b/pjlib/src/pj/lock.c
@@ -1,194 +1,194 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/lock.h>

-#include <pj/os.h>

-#include <pj/assert.h>

-#include <pj/pool.h>

-#include <pj/string.h>

-#include <pj/errno.h>

-

-

-typedef void LOCK_OBJ;

-

-/*

- * Lock structure.

- */

-struct pj_lock_t

-{

-    LOCK_OBJ *lock_object;

-

-    pj_status_t	(*acquire)	(LOCK_OBJ*);

-    pj_status_t	(*tryacquire)	(LOCK_OBJ*);

-    pj_status_t	(*release)	(LOCK_OBJ*);

-    pj_status_t	(*destroy)	(LOCK_OBJ*);

-};

-

-typedef pj_status_t (*FPTR)(LOCK_OBJ*);

-

-/******************************************************************************

- * Implementation of lock object with mutex.

- */

-static pj_lock_t mutex_lock_template = 

-{

-    NULL,

-    (FPTR) &pj_mutex_lock,

-    (FPTR) &pj_mutex_trylock,

-    (FPTR) &pj_mutex_unlock,

-    (FPTR) &pj_mutex_destroy

-};

-

-static pj_status_t create_mutex_lock( pj_pool_t *pool,

-				      const char *name,

-				      int type,

-				      pj_lock_t **lock )

-{

-    pj_lock_t *p_lock;

-    pj_status_t rc;

-

-    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);

-

-    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));

-    if (!p_lock)

-	return PJ_ENOMEM;

-

-    pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t));

-    rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object);

-    if (rc != PJ_SUCCESS)

-	return rc;

-

-    *lock = p_lock;

-    return PJ_SUCCESS;

-}

-

-

-PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,

-						 const char *name,

-						 pj_lock_t **lock )

-{

-    return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock);

-}

-

-PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,

-						    const char *name,

-						    pj_lock_t **lock )

-{

-    return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock);

-}

-

-

-/******************************************************************************

- * Implementation of NULL lock object.

- */

-static pj_status_t null_op(void *arg)

-{

-    PJ_UNUSED_ARG(arg);

-    return PJ_SUCCESS;

-}

-

-static pj_lock_t null_lock_template = 

-{

-    NULL,

-    &null_op,

-    &null_op,

-    &null_op,

-    &null_op

-};

-

-PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,

-					       const char *name,

-					       pj_lock_t **lock )

-{

-    PJ_UNUSED_ARG(name);

-    PJ_UNUSED_ARG(pool);

-

-    PJ_ASSERT_RETURN(lock, PJ_EINVAL);

-

-    *lock = &null_lock_template;

-    return PJ_SUCCESS;

-}

-

-

-/******************************************************************************

- * Implementation of semaphore lock object.

- */

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-

-static pj_lock_t sem_lock_template = 

-{

-    NULL,

-    (FPTR) &pj_sem_wait,

-    (FPTR) &pj_sem_trywait,

-    (FPTR) &pj_sem_post,

-    (FPTR) &pj_sem_destroy

-};

-

-PJ_DEF(pj_status_t) pj_lock_create_semaphore(  pj_pool_t *pool,

-					       const char *name,

-					       unsigned initial,

-					       unsigned max,

-					       pj_lock_t **lock )

-{

-    pj_lock_t *p_lock;

-    pj_status_t rc;

-

-    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);

-

-    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));

-    if (!p_lock)

-	return PJ_ENOMEM;

-

-    pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t));

-    rc = pj_sem_create( pool, name, initial, max, 

-		        (pj_sem_t**)&p_lock->lock_object);

-    if (rc != PJ_SUCCESS)

-        return rc;

-

-    *lock = p_lock;

-

-    return PJ_SUCCESS;

-}

-

-

-#endif	/* PJ_HAS_SEMAPHORE */

-

-

-PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock )

-{

-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

-    return (*lock->acquire)(lock->lock_object);

-}

-

-PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock )

-{

-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

-    return (*lock->tryacquire)(lock->lock_object);

-}

-

-PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock )

-{

-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

-    return (*lock->release)(lock->lock_object);

-}

-

-PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock )

-{

-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

-    return (*lock->destroy)(lock->lock_object);

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/lock.h>
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/errno.h>
+
+
+typedef void LOCK_OBJ;
+
+/*
+ * Lock structure.
+ */
+struct pj_lock_t
+{
+    LOCK_OBJ *lock_object;
+
+    pj_status_t	(*acquire)	(LOCK_OBJ*);
+    pj_status_t	(*tryacquire)	(LOCK_OBJ*);
+    pj_status_t	(*release)	(LOCK_OBJ*);
+    pj_status_t	(*destroy)	(LOCK_OBJ*);
+};
+
+typedef pj_status_t (*FPTR)(LOCK_OBJ*);
+
+/******************************************************************************
+ * Implementation of lock object with mutex.
+ */
+static pj_lock_t mutex_lock_template = 
+{
+    NULL,
+    (FPTR) &pj_mutex_lock,
+    (FPTR) &pj_mutex_trylock,
+    (FPTR) &pj_mutex_unlock,
+    (FPTR) &pj_mutex_destroy
+};
+
+static pj_status_t create_mutex_lock( pj_pool_t *pool,
+				      const char *name,
+				      int type,
+				      pj_lock_t **lock )
+{
+    pj_lock_t *p_lock;
+    pj_status_t rc;
+
+    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
+
+    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
+    if (!p_lock)
+	return PJ_ENOMEM;
+
+    pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t));
+    rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object);
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+    *lock = p_lock;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,
+						 const char *name,
+						 pj_lock_t **lock )
+{
+    return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock);
+}
+
+PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,
+						    const char *name,
+						    pj_lock_t **lock )
+{
+    return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock);
+}
+
+
+/******************************************************************************
+ * Implementation of NULL lock object.
+ */
+static pj_status_t null_op(void *arg)
+{
+    PJ_UNUSED_ARG(arg);
+    return PJ_SUCCESS;
+}
+
+static pj_lock_t null_lock_template = 
+{
+    NULL,
+    &null_op,
+    &null_op,
+    &null_op,
+    &null_op
+};
+
+PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,
+					       const char *name,
+					       pj_lock_t **lock )
+{
+    PJ_UNUSED_ARG(name);
+    PJ_UNUSED_ARG(pool);
+
+    PJ_ASSERT_RETURN(lock, PJ_EINVAL);
+
+    *lock = &null_lock_template;
+    return PJ_SUCCESS;
+}
+
+
+/******************************************************************************
+ * Implementation of semaphore lock object.
+ */
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+static pj_lock_t sem_lock_template = 
+{
+    NULL,
+    (FPTR) &pj_sem_wait,
+    (FPTR) &pj_sem_trywait,
+    (FPTR) &pj_sem_post,
+    (FPTR) &pj_sem_destroy
+};
+
+PJ_DEF(pj_status_t) pj_lock_create_semaphore(  pj_pool_t *pool,
+					       const char *name,
+					       unsigned initial,
+					       unsigned max,
+					       pj_lock_t **lock )
+{
+    pj_lock_t *p_lock;
+    pj_status_t rc;
+
+    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
+
+    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
+    if (!p_lock)
+	return PJ_ENOMEM;
+
+    pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t));
+    rc = pj_sem_create( pool, name, initial, max, 
+		        (pj_sem_t**)&p_lock->lock_object);
+    if (rc != PJ_SUCCESS)
+        return rc;
+
+    *lock = p_lock;
+
+    return PJ_SUCCESS;
+}
+
+
+#endif	/* PJ_HAS_SEMAPHORE */
+
+
+PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock )
+{
+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+    return (*lock->acquire)(lock->lock_object);
+}
+
+PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock )
+{
+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+    return (*lock->tryacquire)(lock->lock_object);
+}
+
+PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock )
+{
+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+    return (*lock->release)(lock->lock_object);
+}
+
+PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock )
+{
+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
+    return (*lock->destroy)(lock->lock_object);
+}
+
diff --git a/pjlib/src/pj/log.c b/pjlib/src/pj/log.c
index 55e7cf3..2077fc9 100644
--- a/pjlib/src/pj/log.c
+++ b/pjlib/src/pj/log.c
@@ -1,224 +1,224 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/types.h>

-#include <pj/log.h>

-#include <pj/string.h>

-#include <pj/os.h>

-#include <pj/compat/vsprintf.h>

-#include <pj/compat/stdarg.h>

-

-#if PJ_LOG_MAX_LEVEL >= 1

-

-static int log_max_level = PJ_LOG_MAX_LEVEL;

-static pj_log_func *log_writer = &pj_log_write;

-static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC |

-			    PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE;

-

-#if PJ_LOG_USE_STACK_BUFFER==0

-static char log_buffer[PJ_LOG_MAX_SIZE];

-#endif

-

-PJ_DEF(void) pj_log_set_decor(unsigned decor)

-{

-    log_decor = decor;

-}

-

-PJ_DEF(unsigned) pj_log_get_decor(void)

-{

-    return log_decor;

-}

-

-PJ_DEF(void) pj_log_set_level(int level)

-{

-    log_max_level = level;

-}

-

-PJ_DEF(int) pj_log_get_level(void)

-{

-    return log_max_level;

-}

-

-PJ_DEF(void) pj_log_set_log_func( pj_log_func *func )

-{

-    log_writer = func;

-}

-

-PJ_DEF(pj_log_func*) pj_log_get_log_func(void)

-{

-    return log_writer;

-}

-

-PJ_DEF(void) pj_log( const char *sender, int level, 

-		     const char *format, va_list marker)

-{

-    pj_time_val now;

-    pj_parsed_time ptime;

-    char *pre;

-#if PJ_LOG_USE_STACK_BUFFER

-    char log_buffer[PJ_LOG_MAX_SIZE];

-#endif

-    int len;

-

-    PJ_CHECK_STACK();

-

-    if (level > log_max_level)

-	return;

-

-    /* Get current date/time. */

-    pj_gettimeofday(&now);

-    pj_time_decode(&now, &ptime);

-

-    pre = log_buffer;

-    if (log_decor & PJ_LOG_HAS_DAY_NAME) {

-	static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",

-				       "Thu", "Fri", "Sat"};

-	strcpy(pre, wdays[ptime.wday]);

-	pre += 3;

-    }

-    if (log_decor & PJ_LOG_HAS_YEAR) {

-	*pre++ = ' ';

-	pre += pj_utoa(ptime.year, pre);

-    }

-    if (log_decor & PJ_LOG_HAS_MONTH) {

-	*pre++ = '-';

-	pre += pj_utoa_pad(ptime.mon, pre, 2, '0');

-    }

-    if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {

-	*pre++ = ' ';

-	pre += pj_utoa_pad(ptime.day, pre, 2, '0');

-    }

-    if (log_decor & PJ_LOG_HAS_TIME) {

-	*pre++ = ' ';

-	pre += pj_utoa_pad(ptime.hour, pre, 2, '0');

-	*pre++ = ':';

-	pre += pj_utoa_pad(ptime.min, pre, 2, '0');

-	*pre++ = ':';

-	pre += pj_utoa_pad(ptime.sec, pre, 2, '0');

-    }

-    if (log_decor & PJ_LOG_HAS_MICRO_SEC) {

-	*pre++ = '.';

-	pre += pj_utoa_pad(ptime.msec, pre, 3, '0');

-    }

-    if (log_decor & PJ_LOG_HAS_SENDER) {

-	enum { SENDER_WIDTH = 12 };

-	int sender_len = strlen(sender);

-	*pre++ = ' ';

-	if (sender_len <= SENDER_WIDTH) {

-	    while (sender_len < SENDER_WIDTH)

-		*pre++ = ' ', ++sender_len;

-	    while (*sender)

-		*pre++ = *sender++;

-	} else {

-	    int i;

-	    for (i=0; i<SENDER_WIDTH; ++i)

-		*pre++ = *sender++;

-	}

-    }

-

-    if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)

-	*pre++ = ' ';

-

-    len = pre - log_buffer;

-

-    /* Print the whole message to the string log_buffer. */

-    len = len + vsnprintf(pre, sizeof(log_buffer)-len, format, marker);

-    if (len > 0 && len < sizeof(log_buffer)-1) {

-	if (log_decor & PJ_LOG_HAS_NEWLINE) {

-	    log_buffer[len++] = '\n';

-	}

-	log_buffer[len++] = '\0';

-    } else {

-	len = sizeof(log_buffer)-1;

-	if (log_decor & PJ_LOG_HAS_NEWLINE) {

-	    log_buffer[sizeof(log_buffer)-2] = '\n';

-	}

-	log_buffer[sizeof(log_buffer)-1] = '\0';

-    }

-

-    if (log_writer)

-	(*log_writer)(level, log_buffer, len);

-}

-

-PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...)

-{

-    va_list arg;

-    va_start(arg, format);

-    pj_log(obj, 0, format, arg);

-    va_end(arg);

-}

-

-PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...)

-{

-    va_list arg;

-    va_start(arg, format);

-    pj_log(obj, 1, format, arg);

-    va_end(arg);

-}

-#endif	/* PJ_LOG_MAX_LEVEL >= 1 */

-

-#if PJ_LOG_MAX_LEVEL >= 2

-PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...)

-{

-    va_list arg;

-    va_start(arg, format);

-    pj_log(obj, 2, format, arg);

-    va_end(arg);

-}

-#endif

-

-#if PJ_LOG_MAX_LEVEL >= 3

-PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...)

-{

-    va_list arg;

-    va_start(arg, format);

-    pj_log(obj, 3, format, arg);

-    va_end(arg);

-}

-#endif

-

-#if PJ_LOG_MAX_LEVEL >= 4

-PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...)

-{

-    va_list arg;

-    va_start(arg, format);

-    pj_log(obj, 4, format, arg);

-    va_end(arg);

-}

-#endif

-

-#if PJ_LOG_MAX_LEVEL >= 5

-PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...)

-{

-    va_list arg;

-    va_start(arg, format);

-    pj_log(obj, 5, format, arg);

-    va_end(arg);

-}

-#endif

-

-#if PJ_LOG_MAX_LEVEL >= 6

-PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...)

-{

-    va_list arg;

-    va_start(arg, format);

-    pj_log(obj, 6, format, arg);

-    va_end(arg);

-}

-#endif

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/types.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/os.h>
+#include <pj/compat/vsprintf.h>
+#include <pj/compat/stdarg.h>
+
+#if PJ_LOG_MAX_LEVEL >= 1
+
+static int log_max_level = PJ_LOG_MAX_LEVEL;
+static pj_log_func *log_writer = &pj_log_write;
+static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC |
+			    PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE;
+
+#if PJ_LOG_USE_STACK_BUFFER==0
+static char log_buffer[PJ_LOG_MAX_SIZE];
+#endif
+
+PJ_DEF(void) pj_log_set_decor(unsigned decor)
+{
+    log_decor = decor;
+}
+
+PJ_DEF(unsigned) pj_log_get_decor(void)
+{
+    return log_decor;
+}
+
+PJ_DEF(void) pj_log_set_level(int level)
+{
+    log_max_level = level;
+}
+
+PJ_DEF(int) pj_log_get_level(void)
+{
+    return log_max_level;
+}
+
+PJ_DEF(void) pj_log_set_log_func( pj_log_func *func )
+{
+    log_writer = func;
+}
+
+PJ_DEF(pj_log_func*) pj_log_get_log_func(void)
+{
+    return log_writer;
+}
+
+PJ_DEF(void) pj_log( const char *sender, int level, 
+		     const char *format, va_list marker)
+{
+    pj_time_val now;
+    pj_parsed_time ptime;
+    char *pre;
+#if PJ_LOG_USE_STACK_BUFFER
+    char log_buffer[PJ_LOG_MAX_SIZE];
+#endif
+    int len;
+
+    PJ_CHECK_STACK();
+
+    if (level > log_max_level)
+	return;
+
+    /* Get current date/time. */
+    pj_gettimeofday(&now);
+    pj_time_decode(&now, &ptime);
+
+    pre = log_buffer;
+    if (log_decor & PJ_LOG_HAS_DAY_NAME) {
+	static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",
+				       "Thu", "Fri", "Sat"};
+	strcpy(pre, wdays[ptime.wday]);
+	pre += 3;
+    }
+    if (log_decor & PJ_LOG_HAS_YEAR) {
+	*pre++ = ' ';
+	pre += pj_utoa(ptime.year, pre);
+    }
+    if (log_decor & PJ_LOG_HAS_MONTH) {
+	*pre++ = '-';
+	pre += pj_utoa_pad(ptime.mon, pre, 2, '0');
+    }
+    if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {
+	*pre++ = ' ';
+	pre += pj_utoa_pad(ptime.day, pre, 2, '0');
+    }
+    if (log_decor & PJ_LOG_HAS_TIME) {
+	*pre++ = ' ';
+	pre += pj_utoa_pad(ptime.hour, pre, 2, '0');
+	*pre++ = ':';
+	pre += pj_utoa_pad(ptime.min, pre, 2, '0');
+	*pre++ = ':';
+	pre += pj_utoa_pad(ptime.sec, pre, 2, '0');
+    }
+    if (log_decor & PJ_LOG_HAS_MICRO_SEC) {
+	*pre++ = '.';
+	pre += pj_utoa_pad(ptime.msec, pre, 3, '0');
+    }
+    if (log_decor & PJ_LOG_HAS_SENDER) {
+	enum { SENDER_WIDTH = 12 };
+	int sender_len = strlen(sender);
+	*pre++ = ' ';
+	if (sender_len <= SENDER_WIDTH) {
+	    while (sender_len < SENDER_WIDTH)
+		*pre++ = ' ', ++sender_len;
+	    while (*sender)
+		*pre++ = *sender++;
+	} else {
+	    int i;
+	    for (i=0; i<SENDER_WIDTH; ++i)
+		*pre++ = *sender++;
+	}
+    }
+
+    if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)
+	*pre++ = ' ';
+
+    len = pre - log_buffer;
+
+    /* Print the whole message to the string log_buffer. */
+    len = len + vsnprintf(pre, sizeof(log_buffer)-len, format, marker);
+    if (len > 0 && len < sizeof(log_buffer)-1) {
+	if (log_decor & PJ_LOG_HAS_NEWLINE) {
+	    log_buffer[len++] = '\n';
+	}
+	log_buffer[len++] = '\0';
+    } else {
+	len = sizeof(log_buffer)-1;
+	if (log_decor & PJ_LOG_HAS_NEWLINE) {
+	    log_buffer[sizeof(log_buffer)-2] = '\n';
+	}
+	log_buffer[sizeof(log_buffer)-1] = '\0';
+    }
+
+    if (log_writer)
+	(*log_writer)(level, log_buffer, len);
+}
+
+PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    pj_log(obj, 0, format, arg);
+    va_end(arg);
+}
+
+PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    pj_log(obj, 1, format, arg);
+    va_end(arg);
+}
+#endif	/* PJ_LOG_MAX_LEVEL >= 1 */
+
+#if PJ_LOG_MAX_LEVEL >= 2
+PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    pj_log(obj, 2, format, arg);
+    va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 3
+PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    pj_log(obj, 3, format, arg);
+    va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 4
+PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    pj_log(obj, 4, format, arg);
+    va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 5
+PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    pj_log(obj, 5, format, arg);
+    va_end(arg);
+}
+#endif
+
+#if PJ_LOG_MAX_LEVEL >= 6
+PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...)
+{
+    va_list arg;
+    va_start(arg, format);
+    pj_log(obj, 6, format, arg);
+    va_end(arg);
+}
+#endif
+
diff --git a/pjlib/src/pj/log_writer_printk.c b/pjlib/src/pj/log_writer_printk.c
index fa901bb..bf846b4 100644
--- a/pjlib/src/pj/log_writer_printk.c
+++ b/pjlib/src/pj/log_writer_printk.c
@@ -1,27 +1,27 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/log.h>

-#include <pj/os.h>

-

-PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)

-{

-    PJ_CHECK_STACK();

-    printk(KERN_INFO "%s", buffer);

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/log.h>
+#include <pj/os.h>
+
+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
+{
+    PJ_CHECK_STACK();
+    printk(KERN_INFO "%s", buffer);
+}
+
diff --git a/pjlib/src/pj/log_writer_stdout.c b/pjlib/src/pj/log_writer_stdout.c
index 506e97e..4a1f9d9 100644
--- a/pjlib/src/pj/log_writer_stdout.c
+++ b/pjlib/src/pj/log_writer_stdout.c
@@ -1,70 +1,70 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/log.h>

-#include <pj/os.h>

-#include <pj/compat/stdfileio.h>

-

-#define CLR_FATAL    (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R)

-#define CLR_WARNING  (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G)

-#define CLR_INFO     (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \

-		      PJ_TERM_COLOR_B)

-#define CLR_DEFAULT  (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B)

-

-static void term_set_color(int level)

-{

-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

-    unsigned attr = 0;

-    switch (level) {

-    case 0:

-    case 1: attr = CLR_FATAL; 

-	break;

-    case 2: attr = CLR_WARNING; 

-	break;

-    case 3: attr = CLR_INFO; 

-	break;

-    default:

-	attr = CLR_DEFAULT;

-	break;

-    }

-

-    pj_term_set_color(attr);

-#endif

-}

-

-static void term_restore_color(void)

-{

-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

-    pj_term_set_color(CLR_DEFAULT);

-#endif

-}

-

-

-PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(len);

-

-    /* Copy to terminal/file. */

-    term_set_color(level);

-    fputs(buffer, stdout);

-    term_restore_color();

-

-    fflush(stdout);

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/log.h>
+#include <pj/os.h>
+#include <pj/compat/stdfileio.h>
+
+#define CLR_FATAL    (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R)
+#define CLR_WARNING  (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G)
+#define CLR_INFO     (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \
+		      PJ_TERM_COLOR_B)
+#define CLR_DEFAULT  (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B)
+
+static void term_set_color(int level)
+{
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+    unsigned attr = 0;
+    switch (level) {
+    case 0:
+    case 1: attr = CLR_FATAL; 
+	break;
+    case 2: attr = CLR_WARNING; 
+	break;
+    case 3: attr = CLR_INFO; 
+	break;
+    default:
+	attr = CLR_DEFAULT;
+	break;
+    }
+
+    pj_term_set_color(attr);
+#endif
+}
+
+static void term_restore_color(void)
+{
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+    pj_term_set_color(CLR_DEFAULT);
+#endif
+}
+
+
+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(len);
+
+    /* Copy to terminal/file. */
+    term_set_color(level);
+    fputs(buffer, stdout);
+    term_restore_color();
+
+    fflush(stdout);
+}
+
diff --git a/pjlib/src/pj/os_core_linux_kernel.c b/pjlib/src/pj/os_core_linux_kernel.c
index d908457..b91e4e0 100644
--- a/pjlib/src/pj/os_core_linux_kernel.c
+++ b/pjlib/src/pj/os_core_linux_kernel.c
@@ -1,689 +1,689 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 (max 15 chars + 0 !) */

-    thread->obj_name[15] = '\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) {

-	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);

-	return PJ_SUCCESS;

-    }

-

-    /* Initialize and set the thread entry. */

-    pj_memset(desc, 0, 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_sprintf(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 */

-

-

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 (max 15 chars + 0 !) */
+    thread->obj_name[15] = '\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) {
+	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+	return PJ_SUCCESS;
+    }
+
+    /* Initialize and set the thread entry. */
+    pj_memset(desc, 0, 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_sprintf(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 */
+
+
+
+
diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c
index 41dfbae..91305be 100644
--- a/pjlib/src/pj/os_core_unix.c
+++ b/pjlib/src/pj/os_core_unix.c
@@ -1,1255 +1,1255 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/rand.h>

-#include <pj/string.h>

-#include <pj/guid.h>

-#include <pj/compat/sprintf.h>

-#include <pj/except.h>

-#include <pj/errno.h>

-

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-#  include <semaphore.h>

-#endif

-

-#include <unistd.h>	    // getpid()

-#include <errno.h>	    // errno

-

-#define __USE_GNU

-//uncomment this to get pthread_mutexattr_settype declaration.

-//unfortunately this causes syntax error in pthread.h! :(

-//#define __USE_UNIX98

-#include <pthread.h>

-

-#define THIS_FILE   "osunix"

-

-struct pj_thread_t

-{

-    char	    obj_name[PJ_MAX_OBJ_NAME];

-    pthread_t	    thread;

-    pj_thread_proc *proc;

-    void	   *arg;

-

-    pj_mutex_t	   *suspended_mutex;

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-    pj_uint32_t	    stk_size;

-    pj_uint32_t	    stk_max_usage;

-    char	   *stk_start;

-    const char	   *caller_file;

-    int		    caller_line;

-#endif

-};

-

-struct pj_atomic_t

-{

-    pj_mutex_t	       *mutex;

-    pj_atomic_value_t	value;

-};

-

-struct pj_mutex_t

-{

-    pthread_mutex_t     mutex;

-    char		obj_name[PJ_MAX_OBJ_NAME];

-#if PJ_DEBUG

-    int		        nesting_level;

-    pj_thread_t	       *owner;

-#endif

-};

-

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-struct pj_sem_t

-{

-    sem_t		sem;

-    char		obj_name[PJ_MAX_OBJ_NAME];

-};

-#endif /* PJ_HAS_SEMAPHORE */

-

-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

-struct pj_event_t

-{

-    char		obj_name[PJ_MAX_OBJ_NAME];

-};

-#endif	/* PJ_HAS_EVENT_OBJ */

-

-

-#if PJ_HAS_THREADS

-    static pj_thread_t main_thread;

-    static long thread_tls_id;

-    static pj_mutex_t critical_section;

-#else

-#   define MAX_THREADS 32

-    static int tls_flag[MAX_THREADS];

-    static void *tls[MAX_THREADS];

-#endif

-

-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);

-

-/*

- * pj_init(void).

- * Init PJLIB!

- */

-PJ_DEF(pj_status_t) pj_init(void)

-{

-    char dummy_guid[PJ_GUID_MAX_LENGTH];

-    pj_str_t guid;

-    pj_status_t rc;

-

-    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));

-

-#if PJ_HAS_THREADS

-    /* Init this thread's TLS. */

-    if ((rc=pj_thread_init()) != 0) {

-	return rc;

-    }

-

-    /* Critical section. */

-    if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0)

-	return rc;

-

-#endif

-

-    /* 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;

-    

-    /* Init random seed. */

-    pj_srand( clock() );

-

-    /* Startup GUID. */

-    guid.ptr = dummy_guid;

-    pj_generate_unique_string( &guid );

-

-    /* 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;

-

-    /* Startup timestamp */

-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

-    {

-	pj_timestamp dummy_ts;

-	if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {

-	    return rc;

-	}

-    }

-#endif   

-

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_getpid(void)

- */

-PJ_DEF(pj_uint32_t) pj_getpid(void)

-{

-    PJ_CHECK_STACK();

-    return getpid();

-}

-

-/*

- * pj_thread_register(..)

- */

-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,

-					 pj_thread_desc desc,

-					 pj_thread_t **ptr_thread)

-{

-#if PJ_HAS_THREADS

-    char stack_ptr;

-    pj_status_t rc;

-    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) {

-	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);

-	return PJ_SUCCESS;

-    }

-

-    /* Initialize and set the thread entry. */

-    pj_memset(desc, 0, sizeof(struct pj_thread_t));

-    thread->thread = pthread_self();

-

-    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_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);

-    

-    rc = pj_thread_local_set(thread_tls_id, thread);

-    if (rc != PJ_SUCCESS)

-	return rc;

-

-#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;

-#else

-    pj_thread_t *thread = (pj_thread_t*)desc;

-    *ptr_thread = thread;

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_thread_init(void)

- */

-pj_status_t pj_thread_init(void)

-{

-#if PJ_HAS_THREADS

-    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("thr%p", (long*)&main_thread, &dummy);

-#else

-    PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));

-    return PJ_EINVALIDOP;

-#endif

-}

-

-#if PJ_HAS_THREADS

-/*

- * thread_main()

- *

- * This is the main entry for all threads.

- */

-static void *thread_main(void *param)

-{

-    pj_thread_t *rec = param;

-    void *result;

-    pj_status_t rc;

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-    rec->stk_start = (char*)&rec;

-#endif

-

-    /* Set current thread id. */

-    rc = pj_thread_local_set(thread_tls_id, rec);

-    if (rc != PJ_SUCCESS) {

-	pj_assert(!"Thread TLS ID is not set (pj_init() error?)");

-    }

-

-    /* Check if suspension is required. */

-    if (rec->suspended_mutex)

-	pj_mutex_lock(rec->suspended_mutex);

-

-    PJ_LOG(6,(rec->obj_name, "Thread started"));

-

-    /* Call user's entry! */

-    result = (void*)(long)(*rec->proc)(rec->arg);

-

-    /* Done. */

-    PJ_LOG(6,(rec->obj_name, "Thread quitting"));

-    return result;

-}

-#endif

-

-/*

- * pj_thread_create(...)

- */

-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)

-{

-#if PJ_HAS_THREADS

-    pj_thread_t *rec;

-    int rc;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);

-

-    /* Create thread record and assign name for the thread */

-    rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));

-    if (!rec)

-	return PJ_ENOMEM;

-    

-    /* Set name. */

-    if (!thread_name) 

-	thread_name = "thr%p";

-    

-    if (strchr(thread_name, '%')) {

-	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);

-    } else {

-	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);

-	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

-    }

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;

-    rec->stk_max_usage = 0;

-#endif

-

-    /* Emulate suspended thread with mutex. */

-    if (flags & PJ_THREAD_SUSPENDED) {

-	rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);

-	if (rc != PJ_SUCCESS)

-	    return rc;

-

-	pj_mutex_lock(rec->suspended_mutex);

-    } else {

-	pj_assert(rec->suspended_mutex == NULL);

-    }

-    

-    PJ_LOG(6, (rec->obj_name, "Thread created"));

-

-    /* Create the thread. */

-    rec->proc = proc;

-    rec->arg = arg;

-    rc = pthread_create( &rec->thread, NULL, thread_main, rec);

-    if (rc != 0)

-	return PJ_RETURN_OS_ERROR(rc);

-

-    *ptr_thread = rec;

-    return PJ_SUCCESS;

-#else

-    pj_assert(!"Threading is disabled!");

-    return PJ_EINVALIDOP;

-#endif

-}

-

-/*

- * pj_thread-get_name()

- */

-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)

-{

-#if PJ_HAS_THREADS

-    pj_thread_t *rec = (pj_thread_t*)p;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(p, "");

-

-    return rec->obj_name;

-#else

-    return "";

-#endif

-}

-

-/*

- * pj_thread_resume()

- */

-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)

-{

-    pj_status_t rc;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(p, PJ_EINVAL);

-

-    rc = pj_mutex_unlock(p->suspended_mutex);

-

-    return rc;

-}

-

-/*

- * pj_thread_this()

- */

-PJ_DEF(pj_thread_t*) pj_thread_this(void)

-{

-#if PJ_HAS_THREADS

-    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);

-    pj_assert(rec != NULL);

-

-    /*

-     * MUST NOT check stack because this function is called

-     * by PJ_CHECK_STACK() itself!!!

-     *

-     */

-

-    return rec;

-#else

-    pj_assert(!"Threading is not enabled!");

-    return NULL;

-#endif

-}

-

-/*

- * pj_thread_join()

- */

-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)

-{

-#if PJ_HAS_THREADS

-    pj_thread_t *rec = (pj_thread_t *)p;

-    void *ret;

-    int result;

-

-    PJ_CHECK_STACK();

-

-    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));

-    result = pthread_join( rec->thread, &ret);

-

-    if (result == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(result);

-#else

-    PJ_CHECK_STACK();

-    pj_assert(!"No multithreading support!");

-    return PJ_EINVALIDOP;

-#endif

-}

-

-/*

- * pj_thread_destroy()

- */

-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)

-{

-    /* This function is used to destroy thread handle in other platforms.

-     * I suppose there's nothing to do here..

-     */

-    PJ_CHECK_STACK();

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_thread_sleep()

- */

-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)

-{

-    PJ_CHECK_STACK();

-    return usleep(msec * 1000);

-}

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-/*

- * pj_thread_check_stack()

- * Implementation for PJ_CHECK_STACK()

- */

-PJ_DEF(void) pj_thread_check_stack(const char *file, int line)

-{

-    char stk_ptr;

-    pj_uint32_t usage;

-    pj_thread_t *thread = pj_thread_this();

-

-    /* Calculate current usage. */

-    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :

-		thread->stk_start - &stk_ptr;

-

-    /* Assert if stack usage is dangerously high. */

-    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));

-

-    /* Keep statistic. */

-    if (usage > thread->stk_max_usage) {

-	thread->stk_max_usage = usage;

-	thread->caller_file = file;

-	thread->caller_line = line;

-    }

-}

-

-/*

- * pj_thread_get_stack_max_usage()

- */

-PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)

-{

-    return thread->stk_max_usage;

-}

-

-/*

- * pj_thread_get_stack_info()

- */

-PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,

-					      const char **file,

-					      int *line )

-{

-    pj_assert(thread);

-

-    *file = thread->caller_file;

-    *line = thread->caller_line;

-    return 0;

-}

-

-#endif	/* PJ_OS_HAS_CHECK_STACK */

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * pj_atomic_create()

- */

-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 

-				      pj_atomic_value_t initial,

-				      pj_atomic_t **ptr_atomic)

-{

-    pj_status_t rc;

-    pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));

-    if (!atomic_var)

-	return PJ_ENOMEM;

-    

-#if PJ_HAS_THREADS

-    rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);

-    if (rc != PJ_SUCCESS)

-	return rc;

-#endif

-    atomic_var->value = initial;

-

-    *ptr_atomic = atomic_var;

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_atomic_destroy()

- */

-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )

-{

-    PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);

-#if PJ_HAS_THREADS

-    return pj_mutex_destroy( atomic_var->mutex );

-#else

-    return 0;

-#endif

-}

-

-/*

- * pj_atomic_set()

- */

-PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)

-{

-    PJ_CHECK_STACK();

-

-#if PJ_HAS_THREADS

-    pj_mutex_lock( atomic_var->mutex );

-#endif

-    atomic_var->value = value;

-#if PJ_HAS_THREADS

-    pj_mutex_unlock( atomic_var->mutex);

-#endif 

-}

-

-/*

- * pj_atomic_get()

- */

-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)

-{

-    pj_atomic_value_t oldval;

-    

-    PJ_CHECK_STACK();

-

-#if PJ_HAS_THREADS

-    pj_mutex_lock( atomic_var->mutex );

-#endif

-    oldval = atomic_var->value;

-#if PJ_HAS_THREADS

-    pj_mutex_unlock( atomic_var->mutex);

-#endif

-    return oldval;

-}

-

-/*

- * pj_atomic_inc_and_get()

- */

-PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)

-{

-    pj_atomic_value_t new_value;

-

-    PJ_CHECK_STACK();

-

-#if PJ_HAS_THREADS

-    pj_mutex_lock( atomic_var->mutex );

-#endif

-    new_value = ++atomic_var->value;

-#if PJ_HAS_THREADS

-    pj_mutex_unlock( atomic_var->mutex);

-#endif

-

-    return new_value;

-}

-/*

- * pj_atomic_inc()

- */

-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)

-{

-    pj_atomic_inc_and_get(atomic_var);

-}

-

-/*

- * pj_atomic_dec_and_get()

- */

-PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)

-{

-    pj_atomic_value_t new_value;

-

-    PJ_CHECK_STACK();

-

-#if PJ_HAS_THREADS

-    pj_mutex_lock( atomic_var->mutex );

-#endif

-    new_value = --atomic_var->value;

-#if PJ_HAS_THREADS

-    pj_mutex_unlock( atomic_var->mutex);

-#endif

-

-    return new_value;

-}

-

-/*

- * pj_atomic_dec()

- */

-PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)

-{

-    pj_atomic_dec_and_get(atomic_var);

-}

-

-/*

- * pj_atomic_add_and_get()

- */ 

-PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var, 

-                                                 pj_atomic_value_t value )

-{

-    pj_atomic_value_t new_value;

-

-#if PJ_HAS_THREADS

-    pj_mutex_lock(atomic_var->mutex);

-#endif

-    

-    atomic_var->value += value;

-    new_value = atomic_var->value;

-

-#if PJ_HAS_THREADS

-    pj_mutex_unlock(atomic_var->mutex);

-#endif

-

-    return new_value;

-}

-

-/*

- * pj_atomic_add()

- */ 

-PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var, 

-                            pj_atomic_value_t value )

-{

-    pj_atomic_add_and_get(atomic_var, value);

-}

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * pj_thread_local_alloc()

- */

-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)

-{

-#if PJ_HAS_THREADS

-    pthread_key_t key;

-    int rc;

-

-    PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);

-

-    pj_assert( sizeof(pthread_key_t) <= sizeof(long));

-    if ((rc=pthread_key_create(&key, NULL)) != 0)

-	return PJ_RETURN_OS_ERROR(rc);

-

-    *p_index = key;

-    return PJ_SUCCESS;

-#else

-    int i;

-    for (i=0; i<MAX_THREADS; ++i) {

-	if (tls_flag[i] == 0)

-	    break;

-    }

-    if (i == MAX_THREADS) 

-	return PJ_ETOOMANY;

-    

-    tls_flag[i] = 1;

-    tls[i] = NULL;

-

-    *p_index = i;

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_thread_local_free()

- */

-PJ_DEF(void) pj_thread_local_free(long index)

-{

-    PJ_CHECK_STACK();

-#if PJ_HAS_THREADS

-    pthread_key_delete(index);

-#else

-    tls_flag[index] = 0;

-#endif

-}

-

-/*

- * pj_thread_local_set()

- */

-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)

-{

-    //Can't check stack because this function is called in the

-    //beginning before main thread is initialized.

-    //PJ_CHECK_STACK();

-#if PJ_HAS_THREADS

-    int rc=pthread_setspecific(index, value);

-    return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);

-#else

-    pj_assert(index >= 0 && index < MAX_THREADS);

-    tls[index] = value;

-    return PJ_SUCCESS;

-#endif

-}

-

-PJ_DEF(void*) pj_thread_local_get(long index)

-{

-    //Can't check stack because this function is called

-    //by PJ_CHECK_STACK() itself!!!

-    //PJ_CHECK_STACK();

-#if PJ_HAS_THREADS

-    return pthread_getspecific(index);

-#else

-    pj_assert(index >= 0 && index < MAX_THREADS);

-    return tls[index];

-#endif

-}

-

-///////////////////////////////////////////////////////////////////////////////

-PJ_DEF(void) pj_enter_critical_section(void)

-{

-#if PJ_HAS_THREADS

-    pj_mutex_lock(&critical_section);

-#endif

-}

-

-PJ_DEF(void) pj_leave_critical_section(void)

-{

-#if PJ_HAS_THREADS

-    pj_mutex_unlock(&critical_section);

-#endif

-}

-

-

-///////////////////////////////////////////////////////////////////////////////

-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)

-{

-#if PJ_HAS_THREADS

-    pthread_mutexattr_t attr;

-    int rc;

-

-    PJ_CHECK_STACK();

-

-    pthread_mutexattr_init(&attr);

-

-    if (type == PJ_MUTEX_SIMPLE) {

-#if defined(PJ_LINUX) && PJ_LINUX!=0

-	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);

-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);

-#else

-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);

-#endif

-    } else {

-#if defined(PJ_LINUX) && PJ_LINUX!=0

-	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);

-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);

-#else

-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

-#endif

-    }

-    

-    if (rc != 0) {

-	return PJ_RETURN_OS_ERROR(rc);

-    }

-

-    rc = pthread_mutex_init(&mutex->mutex, &attr);

-    if (rc != 0) {

-	return PJ_RETURN_OS_ERROR(rc);

-    }

-    

-#if PJ_DEBUG

-    /* Set owner. */

-    mutex->nesting_level = 0;

-    mutex->owner = NULL;

-#endif

-

-    /* Set name. */

-    if (!name) {

-	name = "mtx%p";

-    }

-    if (strchr(name, '%')) {

-	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);

-    } else {

-	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);

-	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

-    }

-

-    PJ_LOG(6, (mutex->obj_name, "Mutex created"));

-    return PJ_SUCCESS;

-#else /* PJ_HAS_THREADS */

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_mutex_create()

- */

-PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 

-				    const char *name, 

-				    int type,

-				    pj_mutex_t **ptr_mutex)

-{

-#if PJ_HAS_THREADS

-    pj_status_t rc;

-    pj_mutex_t *mutex;

-

-    PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);

-

-    mutex = pj_pool_alloc(pool, sizeof(*mutex));

-    if (!mutex) return PJ_ENOMEM;

-

-    if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)

-	return rc;

-    

-    *ptr_mutex = mutex;

-    return PJ_SUCCESS;

-#else /* PJ_HAS_THREADS */

-    return (pj_mutex_t*)1;

-#endif

-}

-

-/*

- * pj_mutex_create_simple()

- */

-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_mutex_create_recursive()

- */

-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_mutex_lock()

- */

-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)

-{

-#if PJ_HAS_THREADS

-    pj_status_t status;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 

-				pj_thread_this()->obj_name));

-

-    status = pthread_mutex_lock( &mutex->mutex );

-

-    PJ_LOG(6,(mutex->obj_name, 

-	      (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),

-	      pj_thread_this()->obj_name));

-

-#if PJ_DEBUG

-    if (status == PJ_SUCCESS) {

-	mutex->owner = pj_thread_this();

-	++mutex->nesting_level;

-    }

-#endif

-

-    if (status == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(status);

-#else	/* PJ_HAS_THREADS */

-    pj_assert( mutex == (pj_mutex_t*)1 );

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_mutex_unlock()

- */

-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)

-{

-#if PJ_HAS_THREADS

-    pj_status_t status;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-#if PJ_DEBUG

-    pj_assert(mutex->owner == pj_thread_this());

-    if (--mutex->nesting_level == 0) {

-	mutex->owner = NULL;

-    }

-#endif

-

-    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 

-				pj_thread_this()->obj_name));

-

-    status = pthread_mutex_unlock( &mutex->mutex );

-    if (status == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(status);

-

-#else /* PJ_HAS_THREADS */

-    pj_assert( mutex == (pj_mutex_t*)1 );

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_mutex_trylock()

- */

-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)

-{

-#if PJ_HAS_THREADS

-    int status;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-    status = pthread_mutex_trylock( &mutex->mutex );

-

-    if (status==0) {

-	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 

-				  pj_thread_this()->obj_name));

-

-#if PJ_DEBUG

-	mutex->owner = pj_thread_this();

-	++mutex->nesting_level;

-#endif

-    }

-    

-    if (status==0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(status);

-#else	/* PJ_HAS_THREADS */

-    pj_assert( mutex == (pj_mutex_t*)1);

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_mutex_destroy()

- */

-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)

-{

-    int status;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-#if PJ_HAS_THREADS

-    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));

-    status = pthread_mutex_destroy( &mutex->mutex );

-    if (status == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(status);

-#else

-    pj_assert( mutex == (pj_mutex_t*)1 );

-    status = PJ_SUCCESS;

-    return status;

-#endif

-}

-

-#if PJ_DEBUG

-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)

-{

-#if PJ_HAS_THREADS

-    return mutex->owner == pj_thread_this();

-#else

-    return 1;

-#endif

-}

-#endif

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-

-/*

- * pj_sem_create()

- */

-PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 

-				   const char *name,

-				   unsigned initial, 

-				   unsigned max,

-				   pj_sem_t **ptr_sem)

-{

-#if PJ_HAS_THREADS

-    pj_sem_t *sem;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);

-

-    sem = pj_pool_alloc(pool, sizeof(*sem));    

-    if (!sem) return PJ_ENOMEM;

-

-    if (sem_init( &sem->sem, 0, initial) != 0) 

-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

-    

-    /* Set name. */

-    if (!name) {

-	name = "sem%p";

-    }

-    if (strchr(name, '%')) {

-	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);

-    } else {

-	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);

-	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

-    }

-

-    PJ_LOG(6, (sem->obj_name, "Semaphore created"));

-

-    *ptr_sem = sem;

-    return PJ_SUCCESS;

-#else

-    *ptr_sem = (pj_sem_t*)1;

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_sem_wait()

- */

-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)

-{

-#if PJ_HAS_THREADS

-    int result;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 

-			      pj_thread_this()->obj_name));

-

-    result = sem_wait( &sem->sem );

-    

-    if (result == 0) {

-	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 

-				  pj_thread_this()->obj_name));

-    } else {

-	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 

-				  pj_thread_this()->obj_name));

-    }

-

-    if (result == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

-#else

-    pj_assert( sem == (pj_sem_t*) 1 );

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_sem_trywait()

- */

-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)

-{

-#if PJ_HAS_THREADS

-    int result;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    result = sem_trywait( &sem->sem );

-    

-    if (result == 0) {

-	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 

-				  pj_thread_this()->obj_name));

-    } 

-    if (result == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

-#else

-    pj_assert( sem == (pj_sem_t*)1 );

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_sem_post()

- */

-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)

-{

-#if PJ_HAS_THREADS

-    int result;

-    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",

-			      pj_thread_this()->obj_name));

-    result = sem_post( &sem->sem );

-

-    if (result == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

-#else

-    pj_assert( sem == (pj_sem_t*) 1);

-    return PJ_SUCCESS;

-#endif

-}

-

-/*

- * pj_sem_destroy()

- */

-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)

-{

-#if PJ_HAS_THREADS

-    int result;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",

-			      pj_thread_this()->obj_name));

-    result = sem_destroy( &sem->sem );

-

-    if (result == 0)

-	return PJ_SUCCESS;

-    else

-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

-#else

-    pj_assert( sem == (pj_sem_t*) 1 );

-    return PJ_SUCCESS;

-#endif

-}

-

-#endif	/* PJ_HAS_SEMAPHORE */

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

-

-/*

- * pj_event_create()

- */

-PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,

-				    pj_bool_t manual_reset, pj_bool_t initial,

-				    pj_event_t **ptr_event)

-{

-    pj_assert(!"Not supported!");

-    PJ_UNUSED_ARG(pool);

-    PJ_UNUSED_ARG(name);

-    PJ_UNUSED_ARG(manual_reset);

-    PJ_UNUSED_ARG(initial);

-    PJ_UNUSED_ARG(ptr_event);

-    return PJ_EINVALIDOP;

-}

-

-/*

- * pj_event_wait()

- */

-PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)

-{

-    PJ_UNUSED_ARG(event);

-    return PJ_EINVALIDOP;

-}

-

-/*

- * pj_event_trywait()

- */

-PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)

-{

-    PJ_UNUSED_ARG(event);

-    return PJ_EINVALIDOP;

-}

-

-/*

- * pj_event_set()

- */

-PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)

-{

-    PJ_UNUSED_ARG(event);

-    return PJ_EINVALIDOP;

-}

-

-/*

- * pj_event_pulse()

- */

-PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)

-{

-    PJ_UNUSED_ARG(event);

-    return PJ_EINVALIDOP;

-}

-

-/*

- * pj_event_reset()

- */

-PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)

-{

-    PJ_UNUSED_ARG(event);

-    return PJ_EINVALIDOP;

-}

-

-/*

- * pj_event_destroy()

- */

-PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)

-{

-    PJ_UNUSED_ARG(event);

-    return PJ_EINVALIDOP;

-}

-

-#endif	/* PJ_HAS_EVENT_OBJ */

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

-/*

- * Terminal

- */

-

-/**

- * Set terminal color.

- */

-PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)

-{

-    PJ_UNUSED_ARG(color);

-    return PJ_EINVALIDOP;

-}

-

-/**

- * Get current terminal foreground color.

- */

-PJ_DEF(pj_color_t) pj_term_get_color(void)

-{

-    return 0;

-}

-

-#endif	/* PJ_TERM_HAS_COLOR */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/rand.h>
+#include <pj/string.h>
+#include <pj/guid.h>
+#include <pj/compat/sprintf.h>
+#include <pj/except.h>
+#include <pj/errno.h>
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+#  include <semaphore.h>
+#endif
+
+#include <unistd.h>	    // getpid()
+#include <errno.h>	    // errno
+
+#define __USE_GNU
+//uncomment this to get pthread_mutexattr_settype declaration.
+//unfortunately this causes syntax error in pthread.h! :(
+//#define __USE_UNIX98
+#include <pthread.h>
+
+#define THIS_FILE   "osunix"
+
+struct pj_thread_t
+{
+    char	    obj_name[PJ_MAX_OBJ_NAME];
+    pthread_t	    thread;
+    pj_thread_proc *proc;
+    void	   *arg;
+
+    pj_mutex_t	   *suspended_mutex;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+    pj_uint32_t	    stk_size;
+    pj_uint32_t	    stk_max_usage;
+    char	   *stk_start;
+    const char	   *caller_file;
+    int		    caller_line;
+#endif
+};
+
+struct pj_atomic_t
+{
+    pj_mutex_t	       *mutex;
+    pj_atomic_value_t	value;
+};
+
+struct pj_mutex_t
+{
+    pthread_mutex_t     mutex;
+    char		obj_name[PJ_MAX_OBJ_NAME];
+#if PJ_DEBUG
+    int		        nesting_level;
+    pj_thread_t	       *owner;
+#endif
+};
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+struct pj_sem_t
+{
+    sem_t		sem;
+    char		obj_name[PJ_MAX_OBJ_NAME];
+};
+#endif /* PJ_HAS_SEMAPHORE */
+
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+struct pj_event_t
+{
+    char		obj_name[PJ_MAX_OBJ_NAME];
+};
+#endif	/* PJ_HAS_EVENT_OBJ */
+
+
+#if PJ_HAS_THREADS
+    static pj_thread_t main_thread;
+    static long thread_tls_id;
+    static pj_mutex_t critical_section;
+#else
+#   define MAX_THREADS 32
+    static int tls_flag[MAX_THREADS];
+    static void *tls[MAX_THREADS];
+#endif
+
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);
+
+/*
+ * pj_init(void).
+ * Init PJLIB!
+ */
+PJ_DEF(pj_status_t) pj_init(void)
+{
+    char dummy_guid[PJ_GUID_MAX_LENGTH];
+    pj_str_t guid;
+    pj_status_t rc;
+
+    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
+
+#if PJ_HAS_THREADS
+    /* Init this thread's TLS. */
+    if ((rc=pj_thread_init()) != 0) {
+	return rc;
+    }
+
+    /* Critical section. */
+    if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0)
+	return rc;
+
+#endif
+
+    /* 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;
+    
+    /* Init random seed. */
+    pj_srand( clock() );
+
+    /* Startup GUID. */
+    guid.ptr = dummy_guid;
+    pj_generate_unique_string( &guid );
+
+    /* 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;
+
+    /* Startup timestamp */
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+    {
+	pj_timestamp dummy_ts;
+	if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
+	    return rc;
+	}
+    }
+#endif   
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_getpid(void)
+ */
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+    PJ_CHECK_STACK();
+    return getpid();
+}
+
+/*
+ * pj_thread_register(..)
+ */
+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
+					 pj_thread_desc desc,
+					 pj_thread_t **ptr_thread)
+{
+#if PJ_HAS_THREADS
+    char stack_ptr;
+    pj_status_t rc;
+    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) {
+	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+	return PJ_SUCCESS;
+    }
+
+    /* Initialize and set the thread entry. */
+    pj_memset(desc, 0, sizeof(struct pj_thread_t));
+    thread->thread = pthread_self();
+
+    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_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
+    
+    rc = pj_thread_local_set(thread_tls_id, thread);
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+#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;
+#else
+    pj_thread_t *thread = (pj_thread_t*)desc;
+    *ptr_thread = thread;
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_thread_init(void)
+ */
+pj_status_t pj_thread_init(void)
+{
+#if PJ_HAS_THREADS
+    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("thr%p", (long*)&main_thread, &dummy);
+#else
+    PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));
+    return PJ_EINVALIDOP;
+#endif
+}
+
+#if PJ_HAS_THREADS
+/*
+ * thread_main()
+ *
+ * This is the main entry for all threads.
+ */
+static void *thread_main(void *param)
+{
+    pj_thread_t *rec = param;
+    void *result;
+    pj_status_t rc;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+    rec->stk_start = (char*)&rec;
+#endif
+
+    /* Set current thread id. */
+    rc = pj_thread_local_set(thread_tls_id, rec);
+    if (rc != PJ_SUCCESS) {
+	pj_assert(!"Thread TLS ID is not set (pj_init() error?)");
+    }
+
+    /* Check if suspension is required. */
+    if (rec->suspended_mutex)
+	pj_mutex_lock(rec->suspended_mutex);
+
+    PJ_LOG(6,(rec->obj_name, "Thread started"));
+
+    /* Call user's entry! */
+    result = (void*)(long)(*rec->proc)(rec->arg);
+
+    /* Done. */
+    PJ_LOG(6,(rec->obj_name, "Thread quitting"));
+    return result;
+}
+#endif
+
+/*
+ * pj_thread_create(...)
+ */
+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)
+{
+#if PJ_HAS_THREADS
+    pj_thread_t *rec;
+    int rc;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
+
+    /* Create thread record and assign name for the thread */
+    rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
+    if (!rec)
+	return PJ_ENOMEM;
+    
+    /* Set name. */
+    if (!thread_name) 
+	thread_name = "thr%p";
+    
+    if (strchr(thread_name, '%')) {
+	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
+    } else {
+	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
+	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
+    rec->stk_max_usage = 0;
+#endif
+
+    /* Emulate suspended thread with mutex. */
+    if (flags & PJ_THREAD_SUSPENDED) {
+	rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
+	if (rc != PJ_SUCCESS)
+	    return rc;
+
+	pj_mutex_lock(rec->suspended_mutex);
+    } else {
+	pj_assert(rec->suspended_mutex == NULL);
+    }
+    
+    PJ_LOG(6, (rec->obj_name, "Thread created"));
+
+    /* Create the thread. */
+    rec->proc = proc;
+    rec->arg = arg;
+    rc = pthread_create( &rec->thread, NULL, thread_main, rec);
+    if (rc != 0)
+	return PJ_RETURN_OS_ERROR(rc);
+
+    *ptr_thread = rec;
+    return PJ_SUCCESS;
+#else
+    pj_assert(!"Threading is disabled!");
+    return PJ_EINVALIDOP;
+#endif
+}
+
+/*
+ * pj_thread-get_name()
+ */
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
+{
+#if PJ_HAS_THREADS
+    pj_thread_t *rec = (pj_thread_t*)p;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(p, "");
+
+    return rec->obj_name;
+#else
+    return "";
+#endif
+}
+
+/*
+ * pj_thread_resume()
+ */
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
+{
+    pj_status_t rc;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+    rc = pj_mutex_unlock(p->suspended_mutex);
+
+    return rc;
+}
+
+/*
+ * pj_thread_this()
+ */
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+#if PJ_HAS_THREADS
+    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
+    pj_assert(rec != NULL);
+
+    /*
+     * MUST NOT check stack because this function is called
+     * by PJ_CHECK_STACK() itself!!!
+     *
+     */
+
+    return rec;
+#else
+    pj_assert(!"Threading is not enabled!");
+    return NULL;
+#endif
+}
+
+/*
+ * pj_thread_join()
+ */
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
+{
+#if PJ_HAS_THREADS
+    pj_thread_t *rec = (pj_thread_t *)p;
+    void *ret;
+    int result;
+
+    PJ_CHECK_STACK();
+
+    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
+    result = pthread_join( rec->thread, &ret);
+
+    if (result == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(result);
+#else
+    PJ_CHECK_STACK();
+    pj_assert(!"No multithreading support!");
+    return PJ_EINVALIDOP;
+#endif
+}
+
+/*
+ * pj_thread_destroy()
+ */
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
+{
+    /* This function is used to destroy thread handle in other platforms.
+     * I suppose there's nothing to do here..
+     */
+    PJ_CHECK_STACK();
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_sleep()
+ */
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+    PJ_CHECK_STACK();
+    return usleep(msec * 1000);
+}
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+/*
+ * pj_thread_check_stack()
+ * Implementation for PJ_CHECK_STACK()
+ */
+PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
+{
+    char stk_ptr;
+    pj_uint32_t usage;
+    pj_thread_t *thread = pj_thread_this();
+
+    /* Calculate current usage. */
+    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
+		thread->stk_start - &stk_ptr;
+
+    /* Assert if stack usage is dangerously high. */
+    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
+
+    /* Keep statistic. */
+    if (usage > thread->stk_max_usage) {
+	thread->stk_max_usage = usage;
+	thread->caller_file = file;
+	thread->caller_line = line;
+    }
+}
+
+/*
+ * pj_thread_get_stack_max_usage()
+ */
+PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
+{
+    return thread->stk_max_usage;
+}
+
+/*
+ * pj_thread_get_stack_info()
+ */
+PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
+					      const char **file,
+					      int *line )
+{
+    pj_assert(thread);
+
+    *file = thread->caller_file;
+    *line = thread->caller_line;
+    return 0;
+}
+
+#endif	/* PJ_OS_HAS_CHECK_STACK */
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_atomic_create()
+ */
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
+				      pj_atomic_value_t initial,
+				      pj_atomic_t **ptr_atomic)
+{
+    pj_status_t rc;
+    pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
+    if (!atomic_var)
+	return PJ_ENOMEM;
+    
+#if PJ_HAS_THREADS
+    rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
+    if (rc != PJ_SUCCESS)
+	return rc;
+#endif
+    atomic_var->value = initial;
+
+    *ptr_atomic = atomic_var;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_atomic_destroy()
+ */
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
+{
+    PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);
+#if PJ_HAS_THREADS
+    return pj_mutex_destroy( atomic_var->mutex );
+#else
+    return 0;
+#endif
+}
+
+/*
+ * pj_atomic_set()
+ */
+PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)
+{
+    PJ_CHECK_STACK();
+
+#if PJ_HAS_THREADS
+    pj_mutex_lock( atomic_var->mutex );
+#endif
+    atomic_var->value = value;
+#if PJ_HAS_THREADS
+    pj_mutex_unlock( atomic_var->mutex);
+#endif 
+}
+
+/*
+ * pj_atomic_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
+{
+    pj_atomic_value_t oldval;
+    
+    PJ_CHECK_STACK();
+
+#if PJ_HAS_THREADS
+    pj_mutex_lock( atomic_var->mutex );
+#endif
+    oldval = atomic_var->value;
+#if PJ_HAS_THREADS
+    pj_mutex_unlock( atomic_var->mutex);
+#endif
+    return oldval;
+}
+
+/*
+ * pj_atomic_inc_and_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
+{
+    pj_atomic_value_t new_value;
+
+    PJ_CHECK_STACK();
+
+#if PJ_HAS_THREADS
+    pj_mutex_lock( atomic_var->mutex );
+#endif
+    new_value = ++atomic_var->value;
+#if PJ_HAS_THREADS
+    pj_mutex_unlock( atomic_var->mutex);
+#endif
+
+    return new_value;
+}
+/*
+ * pj_atomic_inc()
+ */
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
+{
+    pj_atomic_inc_and_get(atomic_var);
+}
+
+/*
+ * pj_atomic_dec_and_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
+{
+    pj_atomic_value_t new_value;
+
+    PJ_CHECK_STACK();
+
+#if PJ_HAS_THREADS
+    pj_mutex_lock( atomic_var->mutex );
+#endif
+    new_value = --atomic_var->value;
+#if PJ_HAS_THREADS
+    pj_mutex_unlock( atomic_var->mutex);
+#endif
+
+    return new_value;
+}
+
+/*
+ * pj_atomic_dec()
+ */
+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
+{
+    pj_atomic_dec_and_get(atomic_var);
+}
+
+/*
+ * pj_atomic_add_and_get()
+ */ 
+PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var, 
+                                                 pj_atomic_value_t value )
+{
+    pj_atomic_value_t new_value;
+
+#if PJ_HAS_THREADS
+    pj_mutex_lock(atomic_var->mutex);
+#endif
+    
+    atomic_var->value += value;
+    new_value = atomic_var->value;
+
+#if PJ_HAS_THREADS
+    pj_mutex_unlock(atomic_var->mutex);
+#endif
+
+    return new_value;
+}
+
+/*
+ * pj_atomic_add()
+ */ 
+PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var, 
+                            pj_atomic_value_t value )
+{
+    pj_atomic_add_and_get(atomic_var, value);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_thread_local_alloc()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)
+{
+#if PJ_HAS_THREADS
+    pthread_key_t key;
+    int rc;
+
+    PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);
+
+    pj_assert( sizeof(pthread_key_t) <= sizeof(long));
+    if ((rc=pthread_key_create(&key, NULL)) != 0)
+	return PJ_RETURN_OS_ERROR(rc);
+
+    *p_index = key;
+    return PJ_SUCCESS;
+#else
+    int i;
+    for (i=0; i<MAX_THREADS; ++i) {
+	if (tls_flag[i] == 0)
+	    break;
+    }
+    if (i == MAX_THREADS) 
+	return PJ_ETOOMANY;
+    
+    tls_flag[i] = 1;
+    tls[i] = NULL;
+
+    *p_index = i;
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_thread_local_free()
+ */
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+    PJ_CHECK_STACK();
+#if PJ_HAS_THREADS
+    pthread_key_delete(index);
+#else
+    tls_flag[index] = 0;
+#endif
+}
+
+/*
+ * pj_thread_local_set()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+    //Can't check stack because this function is called in the
+    //beginning before main thread is initialized.
+    //PJ_CHECK_STACK();
+#if PJ_HAS_THREADS
+    int rc=pthread_setspecific(index, value);
+    return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
+#else
+    pj_assert(index >= 0 && index < MAX_THREADS);
+    tls[index] = value;
+    return PJ_SUCCESS;
+#endif
+}
+
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+    //Can't check stack because this function is called
+    //by PJ_CHECK_STACK() itself!!!
+    //PJ_CHECK_STACK();
+#if PJ_HAS_THREADS
+    return pthread_getspecific(index);
+#else
+    pj_assert(index >= 0 && index < MAX_THREADS);
+    return tls[index];
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+#if PJ_HAS_THREADS
+    pj_mutex_lock(&critical_section);
+#endif
+}
+
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+#if PJ_HAS_THREADS
+    pj_mutex_unlock(&critical_section);
+#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
+{
+#if PJ_HAS_THREADS
+    pthread_mutexattr_t attr;
+    int rc;
+
+    PJ_CHECK_STACK();
+
+    pthread_mutexattr_init(&attr);
+
+    if (type == PJ_MUTEX_SIMPLE) {
+#if defined(PJ_LINUX) && PJ_LINUX!=0
+	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
+#else
+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+#endif
+    } else {
+#if defined(PJ_LINUX) && PJ_LINUX!=0
+	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+#else
+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+#endif
+    }
+    
+    if (rc != 0) {
+	return PJ_RETURN_OS_ERROR(rc);
+    }
+
+    rc = pthread_mutex_init(&mutex->mutex, &attr);
+    if (rc != 0) {
+	return PJ_RETURN_OS_ERROR(rc);
+    }
+    
+#if PJ_DEBUG
+    /* Set owner. */
+    mutex->nesting_level = 0;
+    mutex->owner = NULL;
+#endif
+
+    /* Set name. */
+    if (!name) {
+	name = "mtx%p";
+    }
+    if (strchr(name, '%')) {
+	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
+    } else {
+	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
+	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+
+    PJ_LOG(6, (mutex->obj_name, "Mutex created"));
+    return PJ_SUCCESS;
+#else /* PJ_HAS_THREADS */
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_create()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
+				    const char *name, 
+				    int type,
+				    pj_mutex_t **ptr_mutex)
+{
+#if PJ_HAS_THREADS
+    pj_status_t rc;
+    pj_mutex_t *mutex;
+
+    PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);
+
+    mutex = pj_pool_alloc(pool, sizeof(*mutex));
+    if (!mutex) return PJ_ENOMEM;
+
+    if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)
+	return rc;
+    
+    *ptr_mutex = mutex;
+    return PJ_SUCCESS;
+#else /* PJ_HAS_THREADS */
+    return (pj_mutex_t*)1;
+#endif
+}
+
+/*
+ * pj_mutex_create_simple()
+ */
+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_mutex_create_recursive()
+ */
+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_mutex_lock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+    pj_status_t status;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 
+				pj_thread_this()->obj_name));
+
+    status = pthread_mutex_lock( &mutex->mutex );
+
+    PJ_LOG(6,(mutex->obj_name, 
+	      (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),
+	      pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+    if (status == PJ_SUCCESS) {
+	mutex->owner = pj_thread_this();
+	++mutex->nesting_level;
+    }
+#endif
+
+    if (status == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(status);
+#else	/* PJ_HAS_THREADS */
+    pj_assert( mutex == (pj_mutex_t*)1 );
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_unlock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+    pj_status_t status;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_DEBUG
+    pj_assert(mutex->owner == pj_thread_this());
+    if (--mutex->nesting_level == 0) {
+	mutex->owner = NULL;
+    }
+#endif
+
+    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 
+				pj_thread_this()->obj_name));
+
+    status = pthread_mutex_unlock( &mutex->mutex );
+    if (status == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(status);
+
+#else /* PJ_HAS_THREADS */
+    pj_assert( mutex == (pj_mutex_t*)1 );
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_trylock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+    int status;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+    status = pthread_mutex_trylock( &mutex->mutex );
+
+    if (status==0) {
+	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 
+				  pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+	mutex->owner = pj_thread_this();
+	++mutex->nesting_level;
+#endif
+    }
+    
+    if (status==0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(status);
+#else	/* PJ_HAS_THREADS */
+    pj_assert( mutex == (pj_mutex_t*)1);
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_mutex_destroy()
+ */
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+    int status;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_HAS_THREADS
+    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
+    status = pthread_mutex_destroy( &mutex->mutex );
+    if (status == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(status);
+#else
+    pj_assert( mutex == (pj_mutex_t*)1 );
+    status = PJ_SUCCESS;
+    return status;
+#endif
+}
+
+#if PJ_DEBUG
+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
+{
+#if PJ_HAS_THREADS
+    return mutex->owner == pj_thread_this();
+#else
+    return 1;
+#endif
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+/*
+ * pj_sem_create()
+ */
+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 
+				   const char *name,
+				   unsigned initial, 
+				   unsigned max,
+				   pj_sem_t **ptr_sem)
+{
+#if PJ_HAS_THREADS
+    pj_sem_t *sem;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);
+
+    sem = pj_pool_alloc(pool, sizeof(*sem));    
+    if (!sem) return PJ_ENOMEM;
+
+    if (sem_init( &sem->sem, 0, initial) != 0) 
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+    
+    /* Set name. */
+    if (!name) {
+	name = "sem%p";
+    }
+    if (strchr(name, '%')) {
+	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
+    } else {
+	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
+	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+
+    PJ_LOG(6, (sem->obj_name, "Semaphore created"));
+
+    *ptr_sem = sem;
+    return PJ_SUCCESS;
+#else
+    *ptr_sem = (pj_sem_t*)1;
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_wait()
+ */
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+    int result;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 
+			      pj_thread_this()->obj_name));
+
+    result = sem_wait( &sem->sem );
+    
+    if (result == 0) {
+	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
+				  pj_thread_this()->obj_name));
+    } else {
+	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 
+				  pj_thread_this()->obj_name));
+    }
+
+    if (result == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+    pj_assert( sem == (pj_sem_t*) 1 );
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_trywait()
+ */
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+    int result;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    result = sem_trywait( &sem->sem );
+    
+    if (result == 0) {
+	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
+				  pj_thread_this()->obj_name));
+    } 
+    if (result == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+    pj_assert( sem == (pj_sem_t*)1 );
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_post()
+ */
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+    int result;
+    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
+			      pj_thread_this()->obj_name));
+    result = sem_post( &sem->sem );
+
+    if (result == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+    pj_assert( sem == (pj_sem_t*) 1);
+    return PJ_SUCCESS;
+#endif
+}
+
+/*
+ * pj_sem_destroy()
+ */
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+#if PJ_HAS_THREADS
+    int result;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
+			      pj_thread_this()->obj_name));
+    result = sem_destroy( &sem->sem );
+
+    if (result == 0)
+	return PJ_SUCCESS;
+    else
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+#else
+    pj_assert( sem == (pj_sem_t*) 1 );
+    return PJ_SUCCESS;
+#endif
+}
+
+#endif	/* PJ_HAS_SEMAPHORE */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+
+/*
+ * pj_event_create()
+ */
+PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
+				    pj_bool_t manual_reset, pj_bool_t initial,
+				    pj_event_t **ptr_event)
+{
+    pj_assert(!"Not supported!");
+    PJ_UNUSED_ARG(pool);
+    PJ_UNUSED_ARG(name);
+    PJ_UNUSED_ARG(manual_reset);
+    PJ_UNUSED_ARG(initial);
+    PJ_UNUSED_ARG(ptr_event);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_wait()
+ */
+PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
+{
+    PJ_UNUSED_ARG(event);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_trywait()
+ */
+PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
+{
+    PJ_UNUSED_ARG(event);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_set()
+ */
+PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
+{
+    PJ_UNUSED_ARG(event);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_pulse()
+ */
+PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
+{
+    PJ_UNUSED_ARG(event);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_reset()
+ */
+PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
+{
+    PJ_UNUSED_ARG(event);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_event_destroy()
+ */
+PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
+{
+    PJ_UNUSED_ARG(event);
+    return PJ_EINVALIDOP;
+}
+
+#endif	/* PJ_HAS_EVENT_OBJ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+/*
+ * Terminal
+ */
+
+/**
+ * Set terminal color.
+ */
+PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
+{
+    PJ_UNUSED_ARG(color);
+    return PJ_EINVALIDOP;
+}
+
+/**
+ * Get current terminal foreground color.
+ */
+PJ_DEF(pj_color_t) pj_term_get_color(void)
+{
+    return 0;
+}
+
+#endif	/* PJ_TERM_HAS_COLOR */
+
diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c
index b8e6b28..91add77 100644
--- a/pjlib/src/pj/os_core_win32.c
+++ b/pjlib/src/pj/os_core_win32.c
@@ -1,1227 +1,1227 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/pool.h>

-#include <pj/log.h>

-#include <pj/string.h>

-#include <pj/guid.h>

-#include <pj/rand.h>

-#include <pj/assert.h>

-#include <pj/compat/vsprintf.h>

-#include <pj/compat/sprintf.h>

-#include <pj/errno.h>

-#include <pj/except.h>

-#include <stddef.h>

-#include <stdlib.h>

-#include <stdio.h>

-

-#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0

-#  include <winsock.h>

-#endif

-

-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0

-#  include <winsock2.h>

-#endif

-

-/*

- * Implementation of pj_thread_t.

- */

-struct pj_thread_t

-{

-    char	    obj_name[PJ_MAX_OBJ_NAME];

-    HANDLE	    hthread;

-    DWORD	    idthread;

-    pj_thread_proc *proc;

-    void	   *arg;

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-    pj_uint32_t	    stk_size;

-    pj_uint32_t	    stk_max_usage;

-    char	   *stk_start;

-    const char	   *caller_file;

-    int		    caller_line;

-#endif

-};

-

-

-/*

- * Implementation of pj_mutex_t.

- */

-struct pj_mutex_t

-{

-#if PJ_WIN32_WINNT >= 0x0400

-    CRITICAL_SECTION	crit;

-#else

-    HANDLE		hMutex;

-#endif

-    char		obj_name[PJ_MAX_OBJ_NAME];

-#if PJ_DEBUG

-    int		        nesting_level;

-    pj_thread_t	       *owner;

-#endif

-};

-

-/*

- * Implementation of pj_sem_t.

- */

-typedef struct pj_sem_t

-{

-    HANDLE		hSemaphore;

-    char		obj_name[PJ_MAX_OBJ_NAME];

-} pj_mem_t;

-

-

-/*

- * Implementation of pj_event_t.

- */

-struct pj_event_t

-{

-    HANDLE		hEvent;

-    char		obj_name[PJ_MAX_OBJ_NAME];

-};

-

-/*

- * Implementation of pj_atomic_t.

- */

-struct pj_atomic_t

-{

-    long value;

-};

-

-/*

- * Static global variables.

- */

-static pj_thread_desc main_thread;

-static long thread_tls_id;

-static pj_mutex_t critical_section_mutex;

-

-

-/*

- * Some static prototypes.

- */

-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);

-

-

-/*

- * pj_init(void).

- * Init PJLIB!

- */

-PJ_DEF(pj_status_t) pj_init(void)

-{

-    WSADATA wsa;

-    char dummy_guid[32]; /* use maximum GUID length */

-    pj_str_t guid;

-    pj_status_t rc;

-

-    /* Init Winsock.. */

-    if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {

-	return PJ_RETURN_OS_ERROR(WSAGetLastError());

-    }

-

-    /* Init this thread's TLS. */

-    if ((rc=pj_thread_init()) != PJ_SUCCESS) {

-	return rc;

-    }

-    

-    /* Init random seed. */

-    pj_srand( GetCurrentProcessId() );

-

-    /* Startup GUID. */

-    guid.ptr = dummy_guid;

-    pj_generate_unique_string( &guid );

-

-    /* Initialize critical section. */

-    if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != 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;

-

-    /* Startup timestamp */

-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

-    {

-	pj_timestamp dummy_ts;

-	if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {

-	    PJ_LOG(1, ("pj_init", "Unable to initialize timestamp"));

-	    return rc;

-	}

-    }

-#endif   

-

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_getpid(void)

- */

-PJ_DEF(pj_uint32_t) pj_getpid(void)

-{

-    PJ_CHECK_STACK();

-    return GetCurrentProcessId();

-}

-

-/*

- * pj_thread_register(..)

- */

-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,

-					 pj_thread_desc desc,

-                                         pj_thread_t **thread_ptr)

-{

-    char stack_ptr;

-    pj_status_t rc;

-    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) {

-	*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);

-        return PJ_SUCCESS;

-    }

-

-    /* Initialize and set the thread entry. */

-    pj_memset(desc, 0, sizeof(struct pj_thread_t));

-    thread->hthread = GetCurrentThread();

-    thread->idthread = GetCurrentThreadId();

-

-#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

-

-    if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)

-	pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread);

-    else

-	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread);

-    

-    rc = pj_thread_local_set(thread_tls_id, thread);

-    if (rc != PJ_SUCCESS)

-	return rc;

-

-    *thread_ptr = thread;

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_thread_init(void)

- */

-pj_status_t pj_thread_init(void)

-{

-    pj_status_t rc;

-    pj_thread_t *thread;

-

-    rc = pj_thread_local_alloc(&thread_tls_id);

-    if (rc != PJ_SUCCESS)

-	return rc;

-

-    return pj_thread_register("thr%p", main_thread, &thread);

-}

-

-static DWORD WINAPI thread_main(void *param)

-{

-    pj_thread_t *rec = param;

-    DWORD result;

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-    rec->stk_start = (char*)&rec;

-#endif

-

-    PJ_LOG(6,(rec->obj_name, "Thread started"));

-

-    if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {

-	pj_assert(!"TLS is not set (pj_init() error?)");

-    }

-

-    result = (*rec->proc)(rec->arg);

-

-    PJ_LOG(6,(rec->obj_name, "Thread quitting"));

-    return (DWORD)result;

-}

-

-/*

- * pj_thread_create(...)

- */

-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 **thread_ptr)

-{

-    DWORD dwflags = 0;

-    pj_thread_t *rec;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);

-

-    /* Set flags */

-    if (flags & PJ_THREAD_SUSPENDED)

-	dwflags |= CREATE_SUSPENDED;

-

-    /* Create thread record and assign name for the thread */

-    rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));

-    if (!rec)

-	return PJ_ENOMEM;

-

-    /* Set name. */

-    if (!thread_name)

-	thread_name = "thr%p";

-

-    if (strchr(thread_name, '%')) {

-	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);

-    } else {

-	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);

-	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

-    }

-

-    PJ_LOG(6, (rec->obj_name, "Thread created"));

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

-    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;

-    rec->stk_max_usage = 0;

-#endif

-

-    /* Create the thread. */

-    rec->proc = proc;

-    rec->arg = arg;

-    rec->hthread = CreateThread(NULL, stack_size, 

-				thread_main, rec,

-				dwflags, &rec->idthread);

-    if (rec->hthread == NULL)

-	return PJ_RETURN_OS_ERROR(GetLastError());

-

-    /* Success! */

-    *thread_ptr = rec;

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_thread-get_name()

- */

-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)

-{

-    pj_thread_t *rec = (pj_thread_t*)p;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(p, "");

-

-    return rec->obj_name;

-}

-

-/*

- * pj_thread_resume()

- */

-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)

-{

-    pj_thread_t *rec = (pj_thread_t*)p;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(p, PJ_EINVAL);

-

-    if (ResumeThread(rec->hthread) == (DWORD)-1)

-        return PJ_RETURN_OS_ERROR(GetLastError());

-    else

-        return PJ_SUCCESS;

-}

-

-/*

- * pj_thread_this()

- */

-PJ_DEF(pj_thread_t*) pj_thread_this(void)

-{

-    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);

-    pj_assert(rec != NULL);

-

-    /*

-     * MUST NOT check stack because this function is called

-     * by PJ_CHECK_STACK() itself!!!

-     *

-     */

-

-    return rec;

-}

-

-/*

- * pj_thread_join()

- */

-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)

-{

-    pj_thread_t *rec = (pj_thread_t *)p;

-    DWORD rc;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(p, PJ_EINVAL);

-

-    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));

-

-    rc = WaitForSingleObject(rec->hthread, INFINITE);

-

-    if (rc==WAIT_OBJECT_0)

-        return PJ_SUCCESS;

-    else if (rc==WAIT_TIMEOUT)

-        return PJ_ETIMEDOUT;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_thread_destroy()

- */

-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)

-{

-    pj_thread_t *rec = (pj_thread_t *)p;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(p, PJ_EINVAL);

-

-    if (CloseHandle(rec->hthread) == TRUE)

-        return PJ_SUCCESS;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_thread_sleep()

- */

-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)

-{

-    PJ_CHECK_STACK();

-    Sleep(msec);

-    return PJ_SUCCESS;

-}

-

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0

-/*

- * pj_thread_check_stack()

- * Implementation for PJ_CHECK_STACK()

- */

-PJ_DEF(void) pj_thread_check_stack(const char *file, int line)

-{

-    char stk_ptr;

-    pj_uint32_t usage;

-    pj_thread_t *thread = pj_thread_this();

-

-    pj_assert(thread);

-

-    /* Calculate current usage. */

-    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :

-		thread->stk_start - &stk_ptr;

-

-    /* Assert if stack usage is dangerously high. */

-    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));

-

-    /* Keep statistic. */

-    if (usage > thread->stk_max_usage) {

-	thread->stk_max_usage = usage;

-	thread->caller_file = file;

-	thread->caller_line = line;

-    }

-

-}

-

-/*

- * pj_thread_get_stack_max_usage()

- */

-PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)

-{

-    return thread->stk_max_usage;

-}

-

-/*

- * pj_thread_get_stack_info()

- */

-PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,

-					      const char **file,

-					      int *line )

-{

-    pj_assert(thread);

-

-    *file = thread->caller_file;

-    *line = thread->caller_line;

-    return 0;

-}

-

-#endif	/* PJ_OS_HAS_CHECK_STACK */

-

-

-///////////////////////////////////////////////////////////////////////////////

-

-/*

- * pj_atomic_create()

- */

-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 

-                                      pj_atomic_value_t initial,

-                                      pj_atomic_t **atomic_ptr)

-{

-    pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));

-    if (!atomic_var)

-	return PJ_ENOMEM;

-

-    atomic_var->value = initial;

-    *atomic_ptr = atomic_var;

-

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_atomic_destroy()

- */

-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )

-{

-    PJ_UNUSED_ARG(var);

-    PJ_ASSERT_RETURN(var, PJ_EINVAL);

-

-    return 0;

-}

-

-/*

- * pj_atomic_set()

- */

-PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)

-{

-    PJ_CHECK_STACK();

-

-    InterlockedExchange(&atomic_var->value, value);

-}

-

-/*

- * pj_atomic_get()

- */

-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(atomic_var, 0);

-

-    return atomic_var->value;

-}

-

-/*

- * pj_atomic_inc_and_get()

- */

-PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)

-{

-    PJ_CHECK_STACK();

-

-#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400

-    return InterlockedIncrement(&atomic_var->value);

-#else

-#   error Fix Me

-#endif

-}

-

-/*

- * pj_atomic_inc()

- */

-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)

-{

-    pj_atomic_inc_and_get(atomic_var);

-}

-

-/*

- * pj_atomic_dec_and_get()

- */

-PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)

-{

-    PJ_CHECK_STACK();

-

-#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400

-    return InterlockedDecrement(&atomic_var->value);

-#else

-#   error Fix me

-#endif

-}

-

-/*

- * pj_atomic_dec()

- */

-PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)

-{

-    pj_atomic_dec_and_get(atomic_var);

-}

-

-/*

- * pj_atomic_add()

- */

-PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,

-			    pj_atomic_value_t value )

-{

-#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400

-    InterlockedExchangeAdd( &atomic_var->value, value );

-#else

-#   error Fix me

-#endif

-}

-

-/*

- * pj_atomic_add_and_get()

- */

-PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,

-			                         pj_atomic_value_t value)

-{

-#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400

-    long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);

-    return oldValue + value;

-#else

-#   error Fix me

-#endif

-}

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * pj_thread_local_alloc()

- */

-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)

-{

-    PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);

-

-    //Can't check stack because this function is called in the

-    //beginning before main thread is initialized.

-    //PJ_CHECK_STACK();

-

-    *index = TlsAlloc();

-

-    if (*index == TLS_OUT_OF_INDEXES)

-        return PJ_RETURN_OS_ERROR(GetLastError());

-    else

-        return PJ_SUCCESS;

-}

-

-/*

- * pj_thread_local_free()

- */

-PJ_DEF(void) pj_thread_local_free(long index)

-{

-    PJ_CHECK_STACK();

-    TlsFree(index);

-}

-

-/*

- * pj_thread_local_set()

- */

-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)

-{

-    BOOL rc;

-

-    //Can't check stack because this function is called in the

-    //beginning before main thread is initialized.

-    //PJ_CHECK_STACK();

-    rc = TlsSetValue(index, value);

-    return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_thread_local_get()

- */

-PJ_DEF(void*) pj_thread_local_get(long index)

-{

-    //Can't check stack because this function is called

-    //by PJ_CHECK_STACK() itself!!!

-    //PJ_CHECK_STACK();

-    return TlsGetValue(index);

-}

-

-///////////////////////////////////////////////////////////////////////////////

-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)

-{

-

-    PJ_CHECK_STACK();

-

-#if PJ_WIN32_WINNT >= 0x0400

-    InitializeCriticalSection(&mutex->crit);

-#else

-    mutex->hMutex = CreateMutex(NULL, FALSE, NULL);

-    if (!mutex->hMutex) {

-	return PJ_RETURN_OS_ERROR(GetLastError());

-    }

-#endif

-

-#if PJ_DEBUG

-    /* Set owner. */

-    mutex->nesting_level = 0;

-    mutex->owner = NULL;

-#endif

-

-    /* Set name. */

-    if (!name) {

-	name = "mtx%p";

-    }

-    if (strchr(name, '%')) {

-	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);

-    } else {

-	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);

-	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

-    }

-

-    PJ_LOG(6, (mutex->obj_name, "Mutex created"));

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_mutex_create()

- */

-PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 

-                                    const char *name, 

-                                    int type,

-                                    pj_mutex_t **mutex_ptr)

-{

-    pj_status_t rc;

-    pj_mutex_t *mutex;

-

-    PJ_UNUSED_ARG(type);

-    PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);

-

-    mutex = pj_pool_alloc(pool, sizeof(*mutex));

-    if (!mutex)

-        return PJ_ENOMEM;

-

-    rc = init_mutex(mutex, name);

-    if (rc != PJ_SUCCESS)

-        return rc;

-

-    *mutex_ptr = mutex;

-

-    return PJ_SUCCESS;

-}

-

-/*

- * pj_mutex_create_simple()

- */

-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_mutex_create_recursive()

- */

-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_mutex_lock()

- */

-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)

-{

-    pj_status_t status;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 

-				pj_thread_this()->obj_name));

-

-#if PJ_WIN32_WINNT >= 0x0400

-    EnterCriticalSection(&mutex->crit);

-    status=PJ_SUCCESS;

-#else

-    if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)

-        status = PJ_SUCCESS;

-    else

-        status = PJ_STATUS_FROM_OS(GetLastError());

-

-#endif

-    PJ_LOG(6,(mutex->obj_name, 

-	      (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),

-	      pj_thread_this()->obj_name));

-

-#if PJ_DEBUG

-    if (status == PJ_SUCCESS) {

-	mutex->owner = pj_thread_this();

-	++mutex->nesting_level;

-    }

-#endif

-

-    return status;

-}

-

-/*

- * pj_mutex_unlock()

- */

-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)

-{

-    pj_status_t status;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-#if PJ_DEBUG

-    pj_assert(mutex->owner == pj_thread_this());

-    if (--mutex->nesting_level == 0) {

-	mutex->owner = NULL;

-    }

-#endif

-

-    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 

-				pj_thread_this()->obj_name));

-

-#if PJ_WIN32_WINNT >= 0x0400

-    LeaveCriticalSection(&mutex->crit);

-    status=PJ_SUCCESS;

-#else

-    status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : 

-                PJ_STATUS_FROM_OS(GetLastError());

-#endif

-    return status;

-}

-

-/*

- * pj_mutex_trylock()

- */

-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)

-{

-    pj_status_t status;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-#if PJ_WIN32_WINNT >= 0x0400

-    status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;

-#else

-    status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? 

-                PJ_SUCCESS : PJ_ETIMEDOUT;

-#endif

-    if (status==PJ_SUCCESS) {

-	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 

-				  pj_thread_this()->obj_name));

-

-#if PJ_DEBUG

-	mutex->owner = pj_thread_this();

-	++mutex->nesting_level;

-#endif

-    }

-    return status;

-}

-

-/*

- * pj_mutex_destroy()

- */

-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

-

-    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));

-

-#if PJ_WIN32_WINNT >= 0x0400

-    DeleteCriticalSection(&mutex->crit);

-    return PJ_SUCCESS;

-#else

-    return CloseHandle(mutex->hMutex) ? PJ_SUCCESS : 

-            PJ_RETURN_OS_ERROR(GetLastError());

-#endif

-}

-

-#if PJ_DEBUG

-/*

- * pj_mutex_is_locked()

- */

-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)

-{

-    return mutex->owner == pj_thread_this();

-}

-#endif

-

-///////////////////////////////////////////////////////////////////////////////

-/*

- * pj_enter_critical_section()

- */

-PJ_DEF(void) pj_enter_critical_section(void)

-{

-    pj_mutex_lock(&critical_section_mutex);

-}

-

-

-/*

- * pj_leave_critical_section()

- */

-PJ_DEF(void) pj_leave_critical_section(void)

-{

-    pj_mutex_unlock(&critical_section_mutex);

-}

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-

-/*

- * pj_sem_create()

- */

-PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 

-                                   const char *name,

-				   unsigned initial, 

-                                   unsigned max,

-                                   pj_sem_t **sem_ptr)

-{

-    pj_sem_t *sem;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);

-

-    sem = pj_pool_alloc(pool, sizeof(*sem));    

-    sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);

-    if (!sem->hSemaphore)

-	return PJ_RETURN_OS_ERROR(GetLastError());

-

-    /* Set name. */

-    if (!name) {

-	name = "sem%p";

-    }

-    if (strchr(name, '%')) {

-	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);

-    } else {

-	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);

-	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

-    }

-

-    PJ_LOG(6, (sem->obj_name, "Semaphore created"));

-

-    *sem_ptr = sem;

-    return PJ_SUCCESS;

-}

-

-static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)

-{

-    DWORD result;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 

-			      pj_thread_this()->obj_name));

-

-    result = WaitForSingleObject(sem->hSemaphore, timeout);

-    if (result == WAIT_OBJECT_0) {

-	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 

-				  pj_thread_this()->obj_name));

-    } else {

-	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 

-				  pj_thread_this()->obj_name));

-    }

-

-    if (result==WAIT_OBJECT_0)

-        return PJ_SUCCESS;

-    else if (result==WAIT_TIMEOUT)

-        return PJ_ETIMEDOUT;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_sem_wait()

- */

-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    return pj_sem_wait_for(sem, INFINITE);

-}

-

-/*

- * pj_sem_trywait()

- */

-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    return pj_sem_wait_for(sem, 0);

-}

-

-/*

- * pj_sem_post()

- */

-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",

-			      pj_thread_this()->obj_name));

-

-    if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))

-        return PJ_SUCCESS;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_sem_destroy()

- */

-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

-

-    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",

-			      pj_thread_this()->obj_name));

-

-    if (CloseHandle(sem->hSemaphore))

-        return PJ_SUCCESS;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-#endif	/* PJ_HAS_SEMAPHORE */

-///////////////////////////////////////////////////////////////////////////////

-

-

-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

-

-/*

- * pj_event_create()

- */

-PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool, 

-                                     const char *name,

-				     pj_bool_t manual_reset, 

-                                     pj_bool_t initial,

-                                     pj_event_t **event_ptr)

-{

-    pj_event_t *event;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);

-

-    event = pj_pool_alloc(pool, sizeof(*event));

-    if (!event)

-        return PJ_ENOMEM;

-

-    event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE, 

-				initial?TRUE:FALSE, NULL);

-

-    if (!event->hEvent)

-	return PJ_RETURN_OS_ERROR(GetLastError());

-

-    /* Set name. */

-    if (!name) {

-	name = "evt%p";

-    }

-    if (strchr(name, '%')) {

-	pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);

-    } else {

-	strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);

-	event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

-    }

-

-    PJ_LOG(6, (event->obj_name, "Event created"));

-

-    *event_ptr = event;

-    return PJ_SUCCESS;

-}

-

-static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)

-{

-    DWORD result;

-

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(event, PJ_EINVAL);

-

-    PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", 

-			        pj_thread_this()->obj_name));

-

-    result = WaitForSingleObject(event->hEvent, timeout);

-    if (result == WAIT_OBJECT_0) {

-	PJ_LOG(6, (event->obj_name, "Event: thread %s is released", 

-				    pj_thread_this()->obj_name));

-    } else {

-	PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", 

-				    pj_thread_this()->obj_name));

-    }

-

-    if (result==WAIT_OBJECT_0)

-        return PJ_SUCCESS;

-    else if (result==WAIT_TIMEOUT)

-        return PJ_ETIMEDOUT;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_event_wait()

- */

-PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)

-{

-    PJ_ASSERT_RETURN(event, PJ_EINVAL);

-

-    return pj_event_wait_for(event, INFINITE);

-}

-

-/*

- * pj_event_trywait()

- */

-PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)

-{

-    PJ_ASSERT_RETURN(event, PJ_EINVAL);

-

-    return pj_event_wait_for(event, 0);

-}

-

-/*

- * pj_event_set()

- */

-PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(event, PJ_EINVAL);

-

-    PJ_LOG(6, (event->obj_name, "Setting event"));

-

-    if (SetEvent(event->hEvent))

-        return PJ_SUCCESS;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_event_pulse()

- */

-PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(event, PJ_EINVAL);

-

-    PJ_LOG(6, (event->obj_name, "Pulsing event"));

-

-    if (PulseEvent(event->hEvent))

-        return PJ_SUCCESS;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_event_reset()

- */

-PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(event, PJ_EINVAL);

-

-    PJ_LOG(6, (event->obj_name, "Event is reset"));

-

-    if (ResetEvent(event->hEvent))

-        return PJ_SUCCESS;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_event_destroy()

- */

-PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(event, PJ_EINVAL);

-

-    PJ_LOG(6, (event->obj_name, "Event is destroying"));

-

-    if (CloseHandle(event->hEvent))

-        return PJ_SUCCESS;

-    else

-        return PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-#endif	/* PJ_HAS_EVENT_OBJ */

-

-///////////////////////////////////////////////////////////////////////////////

-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

-/*

- * Terminal color

- */

-

-static WORD pj_color_to_os_attr(pj_color_t color)

-{

-    WORD attr = 0;

-

-    if (color & PJ_TERM_COLOR_R)

-	attr |= FOREGROUND_RED;

-    if (color & PJ_TERM_COLOR_G)

-	attr |= FOREGROUND_GREEN;

-    if (color & PJ_TERM_COLOR_B)

-	attr |= FOREGROUND_BLUE;

-    if (color & PJ_TERM_COLOR_BRIGHT)

-	attr |= FOREGROUND_INTENSITY;

-

-    return attr;

-}

-

-static pj_color_t os_attr_to_pj_color(WORD attr)

-{

-    int color = 0;

-

-    if (attr & FOREGROUND_RED)

-	color |= PJ_TERM_COLOR_R;

-    if (attr & FOREGROUND_GREEN)

-	color |= PJ_TERM_COLOR_G;

-    if (attr & FOREGROUND_BLUE)

-	color |= PJ_TERM_COLOR_B;

-    if (attr & FOREGROUND_INTENSITY)

-	color |= PJ_TERM_COLOR_BRIGHT;

-

-    return color;

-}

-

-

-/*

- * pj_term_set_color()

- */

-PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)

-{

-    BOOL rc;

-    WORD attr = 0;

-

-    PJ_CHECK_STACK();

-

-    attr = pj_color_to_os_attr(color);

-    rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);

-    return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());

-}

-

-/*

- * pj_term_get_color()

- * Get current terminal foreground color.

- */

-PJ_DEF(pj_color_t) pj_term_get_color(void)

-{

-    CONSOLE_SCREEN_BUFFER_INFO info;

-

-    PJ_CHECK_STACK();

-

-    GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);

-    return os_attr_to_pj_color(info.wAttributes);

-}

-

-#endif	/* PJ_TERM_HAS_COLOR */

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/pool.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/guid.h>
+#include <pj/rand.h>
+#include <pj/assert.h>
+#include <pj/compat/vsprintf.h>
+#include <pj/compat/sprintf.h>
+#include <pj/errno.h>
+#include <pj/except.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
+#  include <winsock.h>
+#endif
+
+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
+#  include <winsock2.h>
+#endif
+
+/*
+ * Implementation of pj_thread_t.
+ */
+struct pj_thread_t
+{
+    char	    obj_name[PJ_MAX_OBJ_NAME];
+    HANDLE	    hthread;
+    DWORD	    idthread;
+    pj_thread_proc *proc;
+    void	   *arg;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+    pj_uint32_t	    stk_size;
+    pj_uint32_t	    stk_max_usage;
+    char	   *stk_start;
+    const char	   *caller_file;
+    int		    caller_line;
+#endif
+};
+
+
+/*
+ * Implementation of pj_mutex_t.
+ */
+struct pj_mutex_t
+{
+#if PJ_WIN32_WINNT >= 0x0400
+    CRITICAL_SECTION	crit;
+#else
+    HANDLE		hMutex;
+#endif
+    char		obj_name[PJ_MAX_OBJ_NAME];
+#if PJ_DEBUG
+    int		        nesting_level;
+    pj_thread_t	       *owner;
+#endif
+};
+
+/*
+ * Implementation of pj_sem_t.
+ */
+typedef struct pj_sem_t
+{
+    HANDLE		hSemaphore;
+    char		obj_name[PJ_MAX_OBJ_NAME];
+} pj_mem_t;
+
+
+/*
+ * Implementation of pj_event_t.
+ */
+struct pj_event_t
+{
+    HANDLE		hEvent;
+    char		obj_name[PJ_MAX_OBJ_NAME];
+};
+
+/*
+ * Implementation of pj_atomic_t.
+ */
+struct pj_atomic_t
+{
+    long value;
+};
+
+/*
+ * Static global variables.
+ */
+static pj_thread_desc main_thread;
+static long thread_tls_id;
+static pj_mutex_t critical_section_mutex;
+
+
+/*
+ * Some static prototypes.
+ */
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);
+
+
+/*
+ * pj_init(void).
+ * Init PJLIB!
+ */
+PJ_DEF(pj_status_t) pj_init(void)
+{
+    WSADATA wsa;
+    char dummy_guid[32]; /* use maximum GUID length */
+    pj_str_t guid;
+    pj_status_t rc;
+
+    /* Init Winsock.. */
+    if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
+	return PJ_RETURN_OS_ERROR(WSAGetLastError());
+    }
+
+    /* Init this thread's TLS. */
+    if ((rc=pj_thread_init()) != PJ_SUCCESS) {
+	return rc;
+    }
+    
+    /* Init random seed. */
+    pj_srand( GetCurrentProcessId() );
+
+    /* Startup GUID. */
+    guid.ptr = dummy_guid;
+    pj_generate_unique_string( &guid );
+
+    /* Initialize critical section. */
+    if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != 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;
+
+    /* Startup timestamp */
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+    {
+	pj_timestamp dummy_ts;
+	if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
+	    PJ_LOG(1, ("pj_init", "Unable to initialize timestamp"));
+	    return rc;
+	}
+    }
+#endif   
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_getpid(void)
+ */
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+    PJ_CHECK_STACK();
+    return GetCurrentProcessId();
+}
+
+/*
+ * pj_thread_register(..)
+ */
+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
+					 pj_thread_desc desc,
+                                         pj_thread_t **thread_ptr)
+{
+    char stack_ptr;
+    pj_status_t rc;
+    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) {
+	*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+        return PJ_SUCCESS;
+    }
+
+    /* Initialize and set the thread entry. */
+    pj_memset(desc, 0, sizeof(struct pj_thread_t));
+    thread->hthread = GetCurrentThread();
+    thread->idthread = GetCurrentThreadId();
+
+#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
+
+    if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
+	pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread);
+    else
+	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread);
+    
+    rc = pj_thread_local_set(thread_tls_id, thread);
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+    *thread_ptr = thread;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_init(void)
+ */
+pj_status_t pj_thread_init(void)
+{
+    pj_status_t rc;
+    pj_thread_t *thread;
+
+    rc = pj_thread_local_alloc(&thread_tls_id);
+    if (rc != PJ_SUCCESS)
+	return rc;
+
+    return pj_thread_register("thr%p", main_thread, &thread);
+}
+
+static DWORD WINAPI thread_main(void *param)
+{
+    pj_thread_t *rec = param;
+    DWORD result;
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+    rec->stk_start = (char*)&rec;
+#endif
+
+    PJ_LOG(6,(rec->obj_name, "Thread started"));
+
+    if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {
+	pj_assert(!"TLS is not set (pj_init() error?)");
+    }
+
+    result = (*rec->proc)(rec->arg);
+
+    PJ_LOG(6,(rec->obj_name, "Thread quitting"));
+    return (DWORD)result;
+}
+
+/*
+ * pj_thread_create(...)
+ */
+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 **thread_ptr)
+{
+    DWORD dwflags = 0;
+    pj_thread_t *rec;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);
+
+    /* Set flags */
+    if (flags & PJ_THREAD_SUSPENDED)
+	dwflags |= CREATE_SUSPENDED;
+
+    /* Create thread record and assign name for the thread */
+    rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));
+    if (!rec)
+	return PJ_ENOMEM;
+
+    /* Set name. */
+    if (!thread_name)
+	thread_name = "thr%p";
+
+    if (strchr(thread_name, '%')) {
+	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
+    } else {
+	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
+	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+
+    PJ_LOG(6, (rec->obj_name, "Thread created"));
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
+    rec->stk_max_usage = 0;
+#endif
+
+    /* Create the thread. */
+    rec->proc = proc;
+    rec->arg = arg;
+    rec->hthread = CreateThread(NULL, stack_size, 
+				thread_main, rec,
+				dwflags, &rec->idthread);
+    if (rec->hthread == NULL)
+	return PJ_RETURN_OS_ERROR(GetLastError());
+
+    /* Success! */
+    *thread_ptr = rec;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread-get_name()
+ */
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
+{
+    pj_thread_t *rec = (pj_thread_t*)p;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(p, "");
+
+    return rec->obj_name;
+}
+
+/*
+ * pj_thread_resume()
+ */
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
+{
+    pj_thread_t *rec = (pj_thread_t*)p;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+    if (ResumeThread(rec->hthread) == (DWORD)-1)
+        return PJ_RETURN_OS_ERROR(GetLastError());
+    else
+        return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_this()
+ */
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
+    pj_assert(rec != NULL);
+
+    /*
+     * MUST NOT check stack because this function is called
+     * by PJ_CHECK_STACK() itself!!!
+     *
+     */
+
+    return rec;
+}
+
+/*
+ * pj_thread_join()
+ */
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
+{
+    pj_thread_t *rec = (pj_thread_t *)p;
+    DWORD rc;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
+
+    rc = WaitForSingleObject(rec->hthread, INFINITE);
+
+    if (rc==WAIT_OBJECT_0)
+        return PJ_SUCCESS;
+    else if (rc==WAIT_TIMEOUT)
+        return PJ_ETIMEDOUT;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_thread_destroy()
+ */
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
+{
+    pj_thread_t *rec = (pj_thread_t *)p;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(p, PJ_EINVAL);
+
+    if (CloseHandle(rec->hthread) == TRUE)
+        return PJ_SUCCESS;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_thread_sleep()
+ */
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+    PJ_CHECK_STACK();
+    Sleep(msec);
+    return PJ_SUCCESS;
+}
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
+/*
+ * pj_thread_check_stack()
+ * Implementation for PJ_CHECK_STACK()
+ */
+PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
+{
+    char stk_ptr;
+    pj_uint32_t usage;
+    pj_thread_t *thread = pj_thread_this();
+
+    pj_assert(thread);
+
+    /* Calculate current usage. */
+    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
+		thread->stk_start - &stk_ptr;
+
+    /* Assert if stack usage is dangerously high. */
+    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
+
+    /* Keep statistic. */
+    if (usage > thread->stk_max_usage) {
+	thread->stk_max_usage = usage;
+	thread->caller_file = file;
+	thread->caller_line = line;
+    }
+
+}
+
+/*
+ * pj_thread_get_stack_max_usage()
+ */
+PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
+{
+    return thread->stk_max_usage;
+}
+
+/*
+ * pj_thread_get_stack_info()
+ */
+PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
+					      const char **file,
+					      int *line )
+{
+    pj_assert(thread);
+
+    *file = thread->caller_file;
+    *line = thread->caller_line;
+    return 0;
+}
+
+#endif	/* PJ_OS_HAS_CHECK_STACK */
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * pj_atomic_create()
+ */
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
+                                      pj_atomic_value_t initial,
+                                      pj_atomic_t **atomic_ptr)
+{
+    pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));
+    if (!atomic_var)
+	return PJ_ENOMEM;
+
+    atomic_var->value = initial;
+    *atomic_ptr = atomic_var;
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_atomic_destroy()
+ */
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
+{
+    PJ_UNUSED_ARG(var);
+    PJ_ASSERT_RETURN(var, PJ_EINVAL);
+
+    return 0;
+}
+
+/*
+ * pj_atomic_set()
+ */
+PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)
+{
+    PJ_CHECK_STACK();
+
+    InterlockedExchange(&atomic_var->value, value);
+}
+
+/*
+ * pj_atomic_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(atomic_var, 0);
+
+    return atomic_var->value;
+}
+
+/*
+ * pj_atomic_inc_and_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
+{
+    PJ_CHECK_STACK();
+
+#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
+    return InterlockedIncrement(&atomic_var->value);
+#else
+#   error Fix Me
+#endif
+}
+
+/*
+ * pj_atomic_inc()
+ */
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
+{
+    pj_atomic_inc_and_get(atomic_var);
+}
+
+/*
+ * pj_atomic_dec_and_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
+{
+    PJ_CHECK_STACK();
+
+#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
+    return InterlockedDecrement(&atomic_var->value);
+#else
+#   error Fix me
+#endif
+}
+
+/*
+ * pj_atomic_dec()
+ */
+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
+{
+    pj_atomic_dec_and_get(atomic_var);
+}
+
+/*
+ * pj_atomic_add()
+ */
+PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
+			    pj_atomic_value_t value )
+{
+#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
+    InterlockedExchangeAdd( &atomic_var->value, value );
+#else
+#   error Fix me
+#endif
+}
+
+/*
+ * pj_atomic_add_and_get()
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
+			                         pj_atomic_value_t value)
+{
+#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
+    long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
+    return oldValue + value;
+#else
+#   error Fix me
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_thread_local_alloc()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
+{
+    PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);
+
+    //Can't check stack because this function is called in the
+    //beginning before main thread is initialized.
+    //PJ_CHECK_STACK();
+
+    *index = TlsAlloc();
+
+    if (*index == TLS_OUT_OF_INDEXES)
+        return PJ_RETURN_OS_ERROR(GetLastError());
+    else
+        return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_local_free()
+ */
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+    PJ_CHECK_STACK();
+    TlsFree(index);
+}
+
+/*
+ * pj_thread_local_set()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+    BOOL rc;
+
+    //Can't check stack because this function is called in the
+    //beginning before main thread is initialized.
+    //PJ_CHECK_STACK();
+    rc = TlsSetValue(index, value);
+    return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_thread_local_get()
+ */
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+    //Can't check stack because this function is called
+    //by PJ_CHECK_STACK() itself!!!
+    //PJ_CHECK_STACK();
+    return TlsGetValue(index);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)
+{
+
+    PJ_CHECK_STACK();
+
+#if PJ_WIN32_WINNT >= 0x0400
+    InitializeCriticalSection(&mutex->crit);
+#else
+    mutex->hMutex = CreateMutex(NULL, FALSE, NULL);
+    if (!mutex->hMutex) {
+	return PJ_RETURN_OS_ERROR(GetLastError());
+    }
+#endif
+
+#if PJ_DEBUG
+    /* Set owner. */
+    mutex->nesting_level = 0;
+    mutex->owner = NULL;
+#endif
+
+    /* Set name. */
+    if (!name) {
+	name = "mtx%p";
+    }
+    if (strchr(name, '%')) {
+	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
+    } else {
+	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
+	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+
+    PJ_LOG(6, (mutex->obj_name, "Mutex created"));
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_mutex_create()
+ */
+PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
+                                    const char *name, 
+                                    int type,
+                                    pj_mutex_t **mutex_ptr)
+{
+    pj_status_t rc;
+    pj_mutex_t *mutex;
+
+    PJ_UNUSED_ARG(type);
+    PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);
+
+    mutex = pj_pool_alloc(pool, sizeof(*mutex));
+    if (!mutex)
+        return PJ_ENOMEM;
+
+    rc = init_mutex(mutex, name);
+    if (rc != PJ_SUCCESS)
+        return rc;
+
+    *mutex_ptr = mutex;
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_mutex_create_simple()
+ */
+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_mutex_create_recursive()
+ */
+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_mutex_lock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
+{
+    pj_status_t status;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 
+				pj_thread_this()->obj_name));
+
+#if PJ_WIN32_WINNT >= 0x0400
+    EnterCriticalSection(&mutex->crit);
+    status=PJ_SUCCESS;
+#else
+    if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)
+        status = PJ_SUCCESS;
+    else
+        status = PJ_STATUS_FROM_OS(GetLastError());
+
+#endif
+    PJ_LOG(6,(mutex->obj_name, 
+	      (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),
+	      pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+    if (status == PJ_SUCCESS) {
+	mutex->owner = pj_thread_this();
+	++mutex->nesting_level;
+    }
+#endif
+
+    return status;
+}
+
+/*
+ * pj_mutex_unlock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+    pj_status_t status;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_DEBUG
+    pj_assert(mutex->owner == pj_thread_this());
+    if (--mutex->nesting_level == 0) {
+	mutex->owner = NULL;
+    }
+#endif
+
+    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 
+				pj_thread_this()->obj_name));
+
+#if PJ_WIN32_WINNT >= 0x0400
+    LeaveCriticalSection(&mutex->crit);
+    status=PJ_SUCCESS;
+#else
+    status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : 
+                PJ_STATUS_FROM_OS(GetLastError());
+#endif
+    return status;
+}
+
+/*
+ * pj_mutex_trylock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+    pj_status_t status;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+#if PJ_WIN32_WINNT >= 0x0400
+    status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;
+#else
+    status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? 
+                PJ_SUCCESS : PJ_ETIMEDOUT;
+#endif
+    if (status==PJ_SUCCESS) {
+	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 
+				  pj_thread_this()->obj_name));
+
+#if PJ_DEBUG
+	mutex->owner = pj_thread_this();
+	++mutex->nesting_level;
+#endif
+    }
+    return status;
+}
+
+/*
+ * pj_mutex_destroy()
+ */
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
+
+#if PJ_WIN32_WINNT >= 0x0400
+    DeleteCriticalSection(&mutex->crit);
+    return PJ_SUCCESS;
+#else
+    return CloseHandle(mutex->hMutex) ? PJ_SUCCESS : 
+            PJ_RETURN_OS_ERROR(GetLastError());
+#endif
+}
+
+#if PJ_DEBUG
+/*
+ * pj_mutex_is_locked()
+ */
+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
+{
+    return mutex->owner == pj_thread_this();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_enter_critical_section()
+ */
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+    pj_mutex_lock(&critical_section_mutex);
+}
+
+
+/*
+ * pj_leave_critical_section()
+ */
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+    pj_mutex_unlock(&critical_section_mutex);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+/*
+ * pj_sem_create()
+ */
+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 
+                                   const char *name,
+				   unsigned initial, 
+                                   unsigned max,
+                                   pj_sem_t **sem_ptr)
+{
+    pj_sem_t *sem;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);
+
+    sem = pj_pool_alloc(pool, sizeof(*sem));    
+    sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);
+    if (!sem->hSemaphore)
+	return PJ_RETURN_OS_ERROR(GetLastError());
+
+    /* Set name. */
+    if (!name) {
+	name = "sem%p";
+    }
+    if (strchr(name, '%')) {
+	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
+    } else {
+	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
+	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+
+    PJ_LOG(6, (sem->obj_name, "Semaphore created"));
+
+    *sem_ptr = sem;
+    return PJ_SUCCESS;
+}
+
+static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)
+{
+    DWORD result;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 
+			      pj_thread_this()->obj_name));
+
+    result = WaitForSingleObject(sem->hSemaphore, timeout);
+    if (result == WAIT_OBJECT_0) {
+	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
+				  pj_thread_this()->obj_name));
+    } else {
+	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 
+				  pj_thread_this()->obj_name));
+    }
+
+    if (result==WAIT_OBJECT_0)
+        return PJ_SUCCESS;
+    else if (result==WAIT_TIMEOUT)
+        return PJ_ETIMEDOUT;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_sem_wait()
+ */
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    return pj_sem_wait_for(sem, INFINITE);
+}
+
+/*
+ * pj_sem_trywait()
+ */
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    return pj_sem_wait_for(sem, 0);
+}
+
+/*
+ * pj_sem_post()
+ */
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
+			      pj_thread_this()->obj_name));
+
+    if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))
+        return PJ_SUCCESS;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_sem_destroy()
+ */
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
+
+    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
+			      pj_thread_this()->obj_name));
+
+    if (CloseHandle(sem->hSemaphore))
+        return PJ_SUCCESS;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+#endif	/* PJ_HAS_SEMAPHORE */
+///////////////////////////////////////////////////////////////////////////////
+
+
+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
+
+/*
+ * pj_event_create()
+ */
+PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool, 
+                                     const char *name,
+				     pj_bool_t manual_reset, 
+                                     pj_bool_t initial,
+                                     pj_event_t **event_ptr)
+{
+    pj_event_t *event;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);
+
+    event = pj_pool_alloc(pool, sizeof(*event));
+    if (!event)
+        return PJ_ENOMEM;
+
+    event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE, 
+				initial?TRUE:FALSE, NULL);
+
+    if (!event->hEvent)
+	return PJ_RETURN_OS_ERROR(GetLastError());
+
+    /* Set name. */
+    if (!name) {
+	name = "evt%p";
+    }
+    if (strchr(name, '%')) {
+	pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);
+    } else {
+	strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);
+	event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+    }
+
+    PJ_LOG(6, (event->obj_name, "Event created"));
+
+    *event_ptr = event;
+    return PJ_SUCCESS;
+}
+
+static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)
+{
+    DWORD result;
+
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+    PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", 
+			        pj_thread_this()->obj_name));
+
+    result = WaitForSingleObject(event->hEvent, timeout);
+    if (result == WAIT_OBJECT_0) {
+	PJ_LOG(6, (event->obj_name, "Event: thread %s is released", 
+				    pj_thread_this()->obj_name));
+    } else {
+	PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", 
+				    pj_thread_this()->obj_name));
+    }
+
+    if (result==WAIT_OBJECT_0)
+        return PJ_SUCCESS;
+    else if (result==WAIT_TIMEOUT)
+        return PJ_ETIMEDOUT;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_wait()
+ */
+PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
+{
+    PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+    return pj_event_wait_for(event, INFINITE);
+}
+
+/*
+ * pj_event_trywait()
+ */
+PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
+{
+    PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+    return pj_event_wait_for(event, 0);
+}
+
+/*
+ * pj_event_set()
+ */
+PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+    PJ_LOG(6, (event->obj_name, "Setting event"));
+
+    if (SetEvent(event->hEvent))
+        return PJ_SUCCESS;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_pulse()
+ */
+PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+    PJ_LOG(6, (event->obj_name, "Pulsing event"));
+
+    if (PulseEvent(event->hEvent))
+        return PJ_SUCCESS;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_reset()
+ */
+PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+    PJ_LOG(6, (event->obj_name, "Event is reset"));
+
+    if (ResetEvent(event->hEvent))
+        return PJ_SUCCESS;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_event_destroy()
+ */
+PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(event, PJ_EINVAL);
+
+    PJ_LOG(6, (event->obj_name, "Event is destroying"));
+
+    if (CloseHandle(event->hEvent))
+        return PJ_SUCCESS;
+    else
+        return PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+#endif	/* PJ_HAS_EVENT_OBJ */
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
+/*
+ * Terminal color
+ */
+
+static WORD pj_color_to_os_attr(pj_color_t color)
+{
+    WORD attr = 0;
+
+    if (color & PJ_TERM_COLOR_R)
+	attr |= FOREGROUND_RED;
+    if (color & PJ_TERM_COLOR_G)
+	attr |= FOREGROUND_GREEN;
+    if (color & PJ_TERM_COLOR_B)
+	attr |= FOREGROUND_BLUE;
+    if (color & PJ_TERM_COLOR_BRIGHT)
+	attr |= FOREGROUND_INTENSITY;
+
+    return attr;
+}
+
+static pj_color_t os_attr_to_pj_color(WORD attr)
+{
+    int color = 0;
+
+    if (attr & FOREGROUND_RED)
+	color |= PJ_TERM_COLOR_R;
+    if (attr & FOREGROUND_GREEN)
+	color |= PJ_TERM_COLOR_G;
+    if (attr & FOREGROUND_BLUE)
+	color |= PJ_TERM_COLOR_B;
+    if (attr & FOREGROUND_INTENSITY)
+	color |= PJ_TERM_COLOR_BRIGHT;
+
+    return color;
+}
+
+
+/*
+ * pj_term_set_color()
+ */
+PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
+{
+    BOOL rc;
+    WORD attr = 0;
+
+    PJ_CHECK_STACK();
+
+    attr = pj_color_to_os_attr(color);
+    rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);
+    return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
+}
+
+/*
+ * pj_term_get_color()
+ * Get current terminal foreground color.
+ */
+PJ_DEF(pj_color_t) pj_term_get_color(void)
+{
+    CONSOLE_SCREEN_BUFFER_INFO info;
+
+    PJ_CHECK_STACK();
+
+    GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);
+    return os_attr_to_pj_color(info.wAttributes);
+}
+
+#endif	/* PJ_TERM_HAS_COLOR */
diff --git a/pjlib/src/pj/os_error_linux_kernel.c b/pjlib/src/pj/os_error_linux_kernel.c
index b4f661e..e9c7e2a 100644
--- a/pjlib/src/pj/os_error_linux_kernel.c
+++ b/pjlib/src/pj/os_error_linux_kernel.c
@@ -1,80 +1,80 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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[32];

-    int len;

-    

-    /* Handle EINVAL as special case so that it'll pass errno test. */

-    if (os_errcode==EINVAL)

-	strcpy(errmsg, "Invalid value");

-    else

-	sprintf(errmsg, "errno=%d", os_errcode);

-    

-    len = strlen(errmsg);

-

-    if (len >= bufsize)

-	len = bufsize-1;

-

-    pj_memcpy(buf, errmsg, len);

-    buf[len] = '\0';

-

-    return len;

-}

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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[32];
+    int len;
+    
+    /* Handle EINVAL as special case so that it'll pass errno test. */
+    if (os_errcode==EINVAL)
+	strcpy(errmsg, "Invalid value");
+    else
+	sprintf(errmsg, "errno=%d", os_errcode);
+    
+    len = strlen(errmsg);
+
+    if (len >= bufsize)
+	len = bufsize-1;
+
+    pj_memcpy(buf, errmsg, len);
+    buf[len] = '\0';
+
+    return len;
+}
+
+
diff --git a/pjlib/src/pj/os_error_unix.c b/pjlib/src/pj/os_error_unix.c
index 5eee776..0f4fbe5 100644
--- a/pjlib/src/pj/os_error_unix.c
+++ b/pjlib/src/pj/os_error_unix.c
@@ -1,62 +1,62 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/errno.h>

-#include <pj/string.h>

-#include <errno.h>

-

-PJ_DEF(pj_status_t) pj_get_os_error(void)

-{

-    return PJ_STATUS_FROM_OS(errno);

-}

-

-PJ_DEF(void) pj_set_os_error(pj_status_t code)

-{

-    errno = PJ_STATUS_TO_OS(code);

-}

-

-PJ_DEF(pj_status_t) pj_get_netos_error(void)

-{

-    return PJ_STATUS_FROM_OS(errno);

-}

-

-PJ_DEF(void) pj_set_netos_error(pj_status_t code)

-{

-    errno = PJ_STATUS_TO_OS(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)

-{

-    const char *syserr = strerror(os_errcode);

-    pj_size_t len = syserr ? strlen(syserr) : 0;

-

-    if (len >= bufsize) len = bufsize - 1;

-    if (len > 0)

-	pj_memcpy(buf, syserr, len);

-    buf[len] = '\0';

-    return len;

-}

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/errno.h>
+#include <pj/string.h>
+#include <errno.h>
+
+PJ_DEF(pj_status_t) pj_get_os_error(void)
+{
+    return PJ_STATUS_FROM_OS(errno);
+}
+
+PJ_DEF(void) pj_set_os_error(pj_status_t code)
+{
+    errno = PJ_STATUS_TO_OS(code);
+}
+
+PJ_DEF(pj_status_t) pj_get_netos_error(void)
+{
+    return PJ_STATUS_FROM_OS(errno);
+}
+
+PJ_DEF(void) pj_set_netos_error(pj_status_t code)
+{
+    errno = PJ_STATUS_TO_OS(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)
+{
+    const char *syserr = strerror(os_errcode);
+    pj_size_t len = syserr ? strlen(syserr) : 0;
+
+    if (len >= bufsize) len = bufsize - 1;
+    if (len > 0)
+	pj_memcpy(buf, syserr, len);
+    buf[len] = '\0';
+    return len;
+}
+
+
diff --git a/pjlib/src/pj/os_error_win32.c b/pjlib/src/pj/os_error_win32.c
index 2714704..cbc87eb 100644
--- a/pjlib/src/pj/os_error_win32.c
+++ b/pjlib/src/pj/os_error_win32.c
@@ -1,165 +1,165 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/errno.h>

-#include <pj/assert.h>

-#include <pj/compat/stdarg.h>

-#include <pj/compat/sprintf.h>

-#include <pj/compat/vsprintf.h>

-#include <pj/string.h>

-

-

-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0

-#  include <winsock2.h>

-#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0

-#  include <winsock.h>

-#endif

-

-

-/*

- * From Apache's APR:

- */

-static const struct {

-    pj_os_err_type code;

-    const char *msg;

-} gaErrorList[] = {

-    {WSAEINTR,           "Interrupted system call"},

-    {WSAEBADF,           "Bad file number"},

-    {WSAEACCES,          "Permission denied"},

-    {WSAEFAULT,          "Bad address"},

-    {WSAEINVAL,          "Invalid argument"},

-    {WSAEMFILE,          "Too many open sockets"},

-    {WSAEWOULDBLOCK,     "Operation would block"},

-    {WSAEINPROGRESS,     "Operation now in progress"},

-    {WSAEALREADY,        "Operation already in progress"},

-    {WSAENOTSOCK,        "Socket operation on non-socket"},

-    {WSAEDESTADDRREQ,    "Destination address required"},

-    {WSAEMSGSIZE,        "Message too long"},

-    {WSAEPROTOTYPE,      "Protocol wrong type for socket"},

-    {WSAENOPROTOOPT,     "Bad protocol option"},

-    {WSAEPROTONOSUPPORT, "Protocol not supported"},

-    {WSAESOCKTNOSUPPORT, "Socket type not supported"},

-    {WSAEOPNOTSUPP,      "Operation not supported on socket"},

-    {WSAEPFNOSUPPORT,    "Protocol family not supported"},

-    {WSAEAFNOSUPPORT,    "Address family not supported"},

-    {WSAEADDRINUSE,      "Address already in use"},

-    {WSAEADDRNOTAVAIL,   "Can't assign requested address"},

-    {WSAENETDOWN,        "Network is down"},

-    {WSAENETUNREACH,     "Network is unreachable"},

-    {WSAENETRESET,       "Net connection reset"},

-    {WSAECONNABORTED,    "Software caused connection abort"},

-    {WSAECONNRESET,      "Connection reset by peer"},

-    {WSAENOBUFS,         "No buffer space available"},

-    {WSAEISCONN,         "Socket is already connected"},

-    {WSAENOTCONN,        "Socket is not connected"},

-    {WSAESHUTDOWN,       "Can't send after socket shutdown"},

-    {WSAETOOMANYREFS,    "Too many references, can't splice"},

-    {WSAETIMEDOUT,       "Connection timed out"},

-    {WSAECONNREFUSED,    "Connection refused"},

-    {WSAELOOP,           "Too many levels of symbolic links"},

-    {WSAENAMETOOLONG,    "File name too long"},

-    {WSAEHOSTDOWN,       "Host is down"},

-    {WSAEHOSTUNREACH,    "No route to host"},

-    {WSAENOTEMPTY,       "Directory not empty"},

-    {WSAEPROCLIM,        "Too many processes"},

-    {WSAEUSERS,          "Too many users"},

-    {WSAEDQUOT,          "Disc quota exceeded"},

-    {WSAESTALE,          "Stale NFS file handle"},

-    {WSAEREMOTE,         "Too many levels of remote in path"},

-    {WSASYSNOTREADY,     "Network system is unavailable"},

-    {WSAVERNOTSUPPORTED, "Winsock version out of range"},

-    {WSANOTINITIALISED,  "WSAStartup not yet called"},

-    {WSAEDISCON,         "Graceful shutdown in progress"},

-    {WSAHOST_NOT_FOUND,  "Host not found"},

-    {WSANO_DATA,         "No host data of that type was found"},

-    {0,                  NULL}

-};

-

-

-PJ_DEF(pj_status_t) pj_get_os_error(void)

-{

-    return PJ_STATUS_FROM_OS(GetLastError());

-}

-

-PJ_DEF(void) pj_set_os_error(pj_status_t code)

-{

-    SetLastError(PJ_STATUS_TO_OS(code));

-}

-

-PJ_DEF(pj_status_t) pj_get_netos_error(void)

-{

-    return PJ_STATUS_FROM_OS(WSAGetLastError());

-}

-

-PJ_DEF(void) pj_set_netos_error(pj_status_t code)

-{

-    WSASetLastError(PJ_STATUS_TO_OS(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)

-{

-    int len;

-

-    pj_assert(buf != NULL);

-    pj_assert(bufsize >= 0);

-

-    /*

-     * MUST NOT check stack here.

-     * This function might be called from PJ_CHECK_STACK() itself!

-       //PJ_CHECK_STACK();

-     */

-

-    len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM 

-			 | FORMAT_MESSAGE_IGNORE_INSERTS,

-			 NULL,

-			 os_errcode,

-			 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 

-			 (LPTSTR)buf,

-			 (DWORD)bufsize,

-			 NULL);

-

-    if (!len) {

-	int i;

-        for (i = 0; gaErrorList[i].msg; ++i) {

-            if (gaErrorList[i].code == os_errcode) {

-                len = strlen(gaErrorList[i].msg);

-		if ((pj_size_t)len >= bufsize) {

-		    len = bufsize-1;

-		}

-		pj_memcpy(buf, gaErrorList[i].msg, len);

-		buf[len] = '\0';

-                break;

-            }

-        }

-    }

-

-    if (!len) {

-	len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode);

-	buf[len] = '\0';

-    }

-

-    return len;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/errno.h>
+#include <pj/assert.h>
+#include <pj/compat/stdarg.h>
+#include <pj/compat/sprintf.h>
+#include <pj/compat/vsprintf.h>
+#include <pj/string.h>
+
+
+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
+#  include <winsock2.h>
+#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
+#  include <winsock.h>
+#endif
+
+
+/*
+ * From Apache's APR:
+ */
+static const struct {
+    pj_os_err_type code;
+    const char *msg;
+} gaErrorList[] = {
+    {WSAEINTR,           "Interrupted system call"},
+    {WSAEBADF,           "Bad file number"},
+    {WSAEACCES,          "Permission denied"},
+    {WSAEFAULT,          "Bad address"},
+    {WSAEINVAL,          "Invalid argument"},
+    {WSAEMFILE,          "Too many open sockets"},
+    {WSAEWOULDBLOCK,     "Operation would block"},
+    {WSAEINPROGRESS,     "Operation now in progress"},
+    {WSAEALREADY,        "Operation already in progress"},
+    {WSAENOTSOCK,        "Socket operation on non-socket"},
+    {WSAEDESTADDRREQ,    "Destination address required"},
+    {WSAEMSGSIZE,        "Message too long"},
+    {WSAEPROTOTYPE,      "Protocol wrong type for socket"},
+    {WSAENOPROTOOPT,     "Bad protocol option"},
+    {WSAEPROTONOSUPPORT, "Protocol not supported"},
+    {WSAESOCKTNOSUPPORT, "Socket type not supported"},
+    {WSAEOPNOTSUPP,      "Operation not supported on socket"},
+    {WSAEPFNOSUPPORT,    "Protocol family not supported"},
+    {WSAEAFNOSUPPORT,    "Address family not supported"},
+    {WSAEADDRINUSE,      "Address already in use"},
+    {WSAEADDRNOTAVAIL,   "Can't assign requested address"},
+    {WSAENETDOWN,        "Network is down"},
+    {WSAENETUNREACH,     "Network is unreachable"},
+    {WSAENETRESET,       "Net connection reset"},
+    {WSAECONNABORTED,    "Software caused connection abort"},
+    {WSAECONNRESET,      "Connection reset by peer"},
+    {WSAENOBUFS,         "No buffer space available"},
+    {WSAEISCONN,         "Socket is already connected"},
+    {WSAENOTCONN,        "Socket is not connected"},
+    {WSAESHUTDOWN,       "Can't send after socket shutdown"},
+    {WSAETOOMANYREFS,    "Too many references, can't splice"},
+    {WSAETIMEDOUT,       "Connection timed out"},
+    {WSAECONNREFUSED,    "Connection refused"},
+    {WSAELOOP,           "Too many levels of symbolic links"},
+    {WSAENAMETOOLONG,    "File name too long"},
+    {WSAEHOSTDOWN,       "Host is down"},
+    {WSAEHOSTUNREACH,    "No route to host"},
+    {WSAENOTEMPTY,       "Directory not empty"},
+    {WSAEPROCLIM,        "Too many processes"},
+    {WSAEUSERS,          "Too many users"},
+    {WSAEDQUOT,          "Disc quota exceeded"},
+    {WSAESTALE,          "Stale NFS file handle"},
+    {WSAEREMOTE,         "Too many levels of remote in path"},
+    {WSASYSNOTREADY,     "Network system is unavailable"},
+    {WSAVERNOTSUPPORTED, "Winsock version out of range"},
+    {WSANOTINITIALISED,  "WSAStartup not yet called"},
+    {WSAEDISCON,         "Graceful shutdown in progress"},
+    {WSAHOST_NOT_FOUND,  "Host not found"},
+    {WSANO_DATA,         "No host data of that type was found"},
+    {0,                  NULL}
+};
+
+
+PJ_DEF(pj_status_t) pj_get_os_error(void)
+{
+    return PJ_STATUS_FROM_OS(GetLastError());
+}
+
+PJ_DEF(void) pj_set_os_error(pj_status_t code)
+{
+    SetLastError(PJ_STATUS_TO_OS(code));
+}
+
+PJ_DEF(pj_status_t) pj_get_netos_error(void)
+{
+    return PJ_STATUS_FROM_OS(WSAGetLastError());
+}
+
+PJ_DEF(void) pj_set_netos_error(pj_status_t code)
+{
+    WSASetLastError(PJ_STATUS_TO_OS(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)
+{
+    int len;
+
+    pj_assert(buf != NULL);
+    pj_assert(bufsize >= 0);
+
+    /*
+     * MUST NOT check stack here.
+     * This function might be called from PJ_CHECK_STACK() itself!
+       //PJ_CHECK_STACK();
+     */
+
+    len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM 
+			 | FORMAT_MESSAGE_IGNORE_INSERTS,
+			 NULL,
+			 os_errcode,
+			 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
+			 (LPTSTR)buf,
+			 (DWORD)bufsize,
+			 NULL);
+
+    if (!len) {
+	int i;
+        for (i = 0; gaErrorList[i].msg; ++i) {
+            if (gaErrorList[i].code == os_errcode) {
+                len = strlen(gaErrorList[i].msg);
+		if ((pj_size_t)len >= bufsize) {
+		    len = bufsize-1;
+		}
+		pj_memcpy(buf, gaErrorList[i].msg, len);
+		buf[len] = '\0';
+                break;
+            }
+        }
+    }
+
+    if (!len) {
+	len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode);
+	buf[len] = '\0';
+    }
+
+    return len;
+}
+
diff --git a/pjlib/src/pj/os_time_ansi.c b/pjlib/src/pj/os_time_ansi.c
index 616095c..21a117a 100644
--- a/pjlib/src/pj/os_time_ansi.c
+++ b/pjlib/src/pj/os_time_ansi.c
@@ -1,72 +1,72 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/compat/time.h>

-

-///////////////////////////////////////////////////////////////////////////////

-

-PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)

-{

-    struct timeb tb;

-

-    PJ_CHECK_STACK();

-

-    ftime(&tb);

-    tv->sec = tb.time;

-    tv->msec = tb.millitm;

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)

-{

-    struct tm *local_time;

-

-    PJ_CHECK_STACK();

-

-    local_time = localtime((time_t*)&tv->sec);

-

-    pt->year = local_time->tm_year+1900;

-    pt->mon = local_time->tm_mon;

-    pt->day = local_time->tm_mday;

-    pt->hour = local_time->tm_hour;

-    pt->min = local_time->tm_min;

-    pt->sec = local_time->tm_sec;

-    pt->wday = local_time->tm_wday;

-    pt->yday = local_time->tm_yday;

-    pt->msec = tv->msec;

-

-    return PJ_SUCCESS;

-}

-

-/**

- * 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);

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/compat/time.h>
+
+///////////////////////////////////////////////////////////////////////////////
+
+PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
+{
+    struct timeb tb;
+
+    PJ_CHECK_STACK();
+
+    ftime(&tb);
+    tv->sec = tb.time;
+    tv->msec = tb.millitm;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
+{
+    struct tm *local_time;
+
+    PJ_CHECK_STACK();
+
+    local_time = localtime((time_t*)&tv->sec);
+
+    pt->year = local_time->tm_year+1900;
+    pt->mon = local_time->tm_mon;
+    pt->day = local_time->tm_mday;
+    pt->hour = local_time->tm_hour;
+    pt->min = local_time->tm_min;
+    pt->sec = local_time->tm_sec;
+    pt->wday = local_time->tm_wday;
+    pt->yday = local_time->tm_yday;
+    pt->msec = tv->msec;
+
+    return PJ_SUCCESS;
+}
+
+/**
+ * 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);
+
+
diff --git a/pjlib/src/pj/os_time_linux_kernel.c b/pjlib/src/pj/os_time_linux_kernel.c
index 7d695ad..de53216 100644
--- a/pjlib/src/pj/os_time_linux_kernel.c
+++ b/pjlib/src/pj/os_time_linux_kernel.c
@@ -1,65 +1,65 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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);

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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);
+
+
diff --git a/pjlib/src/pj/os_timestamp_common.c b/pjlib/src/pj/os_timestamp_common.c
index cab43f8..4dc410f 100644
--- a/pjlib/src/pj/os_timestamp_common.c
+++ b/pjlib/src/pj/os_timestamp_common.c
@@ -1,135 +1,135 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/compat/high_precision.h>

-

-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

-

-#define U32MAX  (0xFFFFFFFFUL)

-#define NANOSEC (1000000000UL)

-#define USEC    (1000000UL)

-#define MSEC    (1000)

-

-static pj_highprec_t get_elapsed( const pj_timestamp *start,

-                                  const pj_timestamp *stop )

-{

-    pj_highprec_t elapsed_hi, elapsed_lo;

-

-    elapsed_hi = stop->u32.hi - start->u32.hi;

-    elapsed_lo = stop->u32.lo - start->u32.lo;

-

-    /* elapsed_hi = elapsed_hi * U32MAX */

-    pj_highprec_mul(elapsed_hi, U32MAX);

-

-    return elapsed_hi + elapsed_lo;

-}

-

-static pj_highprec_t elapsed_usec( const pj_timestamp *start,

-                                   const pj_timestamp *stop )

-{

-    pj_timestamp ts_freq;

-    pj_highprec_t freq, elapsed;

-

-    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)

-        return 0;

-

-    /* Convert frequency timestamp */

-    freq = ts_freq.u32.hi;

-    pj_highprec_mul(freq, U32MAX);

-    freq += ts_freq.u32.lo;

-

-    /* Avoid division by zero. */

-    if (freq == 0) freq = 1;

-

-    /* Get elapsed time in cycles. */

-    elapsed = get_elapsed(start, stop);

-

-    /* usec = elapsed * USEC / freq */

-    pj_highprec_mul(elapsed, USEC);

-    pj_highprec_div(elapsed, freq);

-

-    return elapsed;

-}

-

-PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,

-                                        const pj_timestamp *stop )

-{

-    pj_timestamp ts_freq;

-    pj_highprec_t freq, elapsed;

-

-    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)

-        return 0;

-

-    /* Convert frequency timestamp */

-    freq = ts_freq.u32.hi;

-    pj_highprec_mul(freq, U32MAX);

-    freq += ts_freq.u32.lo;

-

-    /* Avoid division by zero. */

-    if (freq == 0) freq = 1;

-

-    /* Get elapsed time in cycles. */

-    elapsed = get_elapsed(start, stop);

-

-    /* usec = elapsed * USEC / freq */

-    pj_highprec_mul(elapsed, NANOSEC);

-    pj_highprec_div(elapsed, freq);

-

-    return (pj_uint32_t)elapsed;

-}

-

-PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,

-                                     const pj_timestamp *stop )

-{

-    return (pj_uint32_t)elapsed_usec(start, stop);

-}

-

-PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,

-                                     const pj_timestamp *stop )

-{

-    pj_highprec_t elapsed = elapsed_usec(start, stop);

-    pj_time_val tv_elapsed;

-

-    if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {

-        tv_elapsed.sec = tv_elapsed.msec = 0;

-        return tv_elapsed;

-    } else {

-        pj_highprec_t sec, msec;

-

-        sec = elapsed;

-        pj_highprec_div(sec, USEC);

-        tv_elapsed.sec = (long)sec;

-

-        msec = elapsed;

-        pj_highprec_mod(msec, USEC);

-        pj_highprec_div(msec, 1000);

-        tv_elapsed.msec = (long)msec;

-

-        return tv_elapsed;

-    }

-}

-

-PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,

-                                      const pj_timestamp *stop )

-{

-    return stop->u32.lo - start->u32.lo;

-}

-

-#endif  /* PJ_HAS_HIGH_RES_TIMER */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/compat/high_precision.h>
+
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+
+#define U32MAX  (0xFFFFFFFFUL)
+#define NANOSEC (1000000000UL)
+#define USEC    (1000000UL)
+#define MSEC    (1000)
+
+static pj_highprec_t get_elapsed( const pj_timestamp *start,
+                                  const pj_timestamp *stop )
+{
+    pj_highprec_t elapsed_hi, elapsed_lo;
+
+    elapsed_hi = stop->u32.hi - start->u32.hi;
+    elapsed_lo = stop->u32.lo - start->u32.lo;
+
+    /* elapsed_hi = elapsed_hi * U32MAX */
+    pj_highprec_mul(elapsed_hi, U32MAX);
+
+    return elapsed_hi + elapsed_lo;
+}
+
+static pj_highprec_t elapsed_usec( const pj_timestamp *start,
+                                   const pj_timestamp *stop )
+{
+    pj_timestamp ts_freq;
+    pj_highprec_t freq, elapsed;
+
+    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
+        return 0;
+
+    /* Convert frequency timestamp */
+    freq = ts_freq.u32.hi;
+    pj_highprec_mul(freq, U32MAX);
+    freq += ts_freq.u32.lo;
+
+    /* Avoid division by zero. */
+    if (freq == 0) freq = 1;
+
+    /* Get elapsed time in cycles. */
+    elapsed = get_elapsed(start, stop);
+
+    /* usec = elapsed * USEC / freq */
+    pj_highprec_mul(elapsed, USEC);
+    pj_highprec_div(elapsed, freq);
+
+    return elapsed;
+}
+
+PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
+                                        const pj_timestamp *stop )
+{
+    pj_timestamp ts_freq;
+    pj_highprec_t freq, elapsed;
+
+    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
+        return 0;
+
+    /* Convert frequency timestamp */
+    freq = ts_freq.u32.hi;
+    pj_highprec_mul(freq, U32MAX);
+    freq += ts_freq.u32.lo;
+
+    /* Avoid division by zero. */
+    if (freq == 0) freq = 1;
+
+    /* Get elapsed time in cycles. */
+    elapsed = get_elapsed(start, stop);
+
+    /* usec = elapsed * USEC / freq */
+    pj_highprec_mul(elapsed, NANOSEC);
+    pj_highprec_div(elapsed, freq);
+
+    return (pj_uint32_t)elapsed;
+}
+
+PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
+                                     const pj_timestamp *stop )
+{
+    return (pj_uint32_t)elapsed_usec(start, stop);
+}
+
+PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
+                                     const pj_timestamp *stop )
+{
+    pj_highprec_t elapsed = elapsed_usec(start, stop);
+    pj_time_val tv_elapsed;
+
+    if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {
+        tv_elapsed.sec = tv_elapsed.msec = 0;
+        return tv_elapsed;
+    } else {
+        pj_highprec_t sec, msec;
+
+        sec = elapsed;
+        pj_highprec_div(sec, USEC);
+        tv_elapsed.sec = (long)sec;
+
+        msec = elapsed;
+        pj_highprec_mod(msec, USEC);
+        pj_highprec_div(msec, 1000);
+        tv_elapsed.msec = (long)msec;
+
+        return tv_elapsed;
+    }
+}
+
+PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
+                                      const pj_timestamp *stop )
+{
+    return stop->u32.lo - start->u32.lo;
+}
+
+#endif  /* PJ_HAS_HIGH_RES_TIMER */
+
diff --git a/pjlib/src/pj/os_timestamp_linux.c b/pjlib/src/pj/os_timestamp_linux.c
index 7b7b11c..c78fdd6 100644
--- a/pjlib/src/pj/os_timestamp_linux.c
+++ b/pjlib/src/pj/os_timestamp_linux.c
@@ -1,139 +1,139 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/errno.h>

-#include <stdio.h>

-#include <string.h>

-#include <stdlib.h>

-#include <ctype.h>

-

-#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0

-static int machine_speed_mhz;

-static pj_timestamp machine_speed;

-

-static __inline__ unsigned long long int rdtsc()

-{

-    unsigned long long int x;

-    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));

-    return x;

-}

-

-/* Determine machine's CPU MHz to get the counter's frequency.

- */

-static int get_machine_speed_mhz()

-{

-    FILE *strm;

-    char buf[512];

-    int len;

-    char *pos, *end;

-	

-    PJ_CHECK_STACK();

-	

-    /* Open /proc/cpuinfo and read the file */

-    strm = fopen("/proc/cpuinfo", "r");

-    if (!strm)

-        return -1;

-    len = fread(buf, 1, sizeof(buf), strm);

-    fclose(strm);

-    if (len < 1) {

-        return -1;

-    }

-    buf[len] = '\0';

-

-    /* Locate the MHz digit. */

-    pos = strstr(buf, "cpu MHz");

-    if (!pos)

-        return -1;

-    pos = strchr(pos, ':');

-    if (!pos)

-        return -1;

-    end = (pos += 2);

-    while (isdigit(*end)) ++end;

-    *end = '\0';

-

-    /* Return the Mhz part, and give it a +1. */

-    return atoi(pos)+1;

-}

-

-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

-{

-    if (machine_speed_mhz == 0) {

-	machine_speed_mhz = get_machine_speed_mhz();

-	if (machine_speed_mhz > 0) {

-	    machine_speed.u64 = machine_speed_mhz * 1000000.0;

-	}

-    }

-    

-    if (machine_speed_mhz == -1) {

-	ts->u64 = 0;

-	return -1;

-    } 

-    ts->u64 = rdtsc();

-    return 0;

-}

-

-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

-{

-    if (machine_speed_mhz == 0) {

-	machine_speed_mhz = get_machine_speed_mhz();

-	if (machine_speed_mhz > 0) {

-	    machine_speed.u64 = machine_speed_mhz * 1000000.0;

-	}

-    }

-    

-    if (machine_speed_mhz == -1) {

-	freq->u64 = 1;	/* return 1 to prevent division by zero in apps. */

-	return -1;

-    } 

-

-    freq->u64 = machine_speed.u64;

-    return 0;

-}

-

-#else

-#include <sys/time.h>

-#include <errno.h>

-

-#define USEC_PER_SEC	1000000

-

-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

-{

-    struct timeval tv;

-

-    if (gettimeofday(&tv, NULL) != 0) {

-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

-    }

-

-    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 PJ_SUCCESS;

-}

-

-#endif

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0
+static int machine_speed_mhz;
+static pj_timestamp machine_speed;
+
+static __inline__ unsigned long long int rdtsc()
+{
+    unsigned long long int x;
+    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+    return x;
+}
+
+/* Determine machine's CPU MHz to get the counter's frequency.
+ */
+static int get_machine_speed_mhz()
+{
+    FILE *strm;
+    char buf[512];
+    int len;
+    char *pos, *end;
+	
+    PJ_CHECK_STACK();
+	
+    /* Open /proc/cpuinfo and read the file */
+    strm = fopen("/proc/cpuinfo", "r");
+    if (!strm)
+        return -1;
+    len = fread(buf, 1, sizeof(buf), strm);
+    fclose(strm);
+    if (len < 1) {
+        return -1;
+    }
+    buf[len] = '\0';
+
+    /* Locate the MHz digit. */
+    pos = strstr(buf, "cpu MHz");
+    if (!pos)
+        return -1;
+    pos = strchr(pos, ':');
+    if (!pos)
+        return -1;
+    end = (pos += 2);
+    while (isdigit(*end)) ++end;
+    *end = '\0';
+
+    /* Return the Mhz part, and give it a +1. */
+    return atoi(pos)+1;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+    if (machine_speed_mhz == 0) {
+	machine_speed_mhz = get_machine_speed_mhz();
+	if (machine_speed_mhz > 0) {
+	    machine_speed.u64 = machine_speed_mhz * 1000000.0;
+	}
+    }
+    
+    if (machine_speed_mhz == -1) {
+	ts->u64 = 0;
+	return -1;
+    } 
+    ts->u64 = rdtsc();
+    return 0;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+    if (machine_speed_mhz == 0) {
+	machine_speed_mhz = get_machine_speed_mhz();
+	if (machine_speed_mhz > 0) {
+	    machine_speed.u64 = machine_speed_mhz * 1000000.0;
+	}
+    }
+    
+    if (machine_speed_mhz == -1) {
+	freq->u64 = 1;	/* return 1 to prevent division by zero in apps. */
+	return -1;
+    } 
+
+    freq->u64 = machine_speed.u64;
+    return 0;
+}
+
+#else
+#include <sys/time.h>
+#include <errno.h>
+
+#define USEC_PER_SEC	1000000
+
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+    struct timeval tv;
+
+    if (gettimeofday(&tv, NULL) != 0) {
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+    }
+
+    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 PJ_SUCCESS;
+}
+
+#endif
+
diff --git a/pjlib/src/pj/os_timestamp_linux_kernel.c b/pjlib/src/pj/os_timestamp_linux_kernel.c
index ed21851..ebc6c1c 100644
--- a/pjlib/src/pj/os_timestamp_linux_kernel.c
+++ b/pjlib/src/pj/os_timestamp_linux_kernel.c
@@ -1,78 +1,78 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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
+
diff --git a/pjlib/src/pj/os_timestamp_win32.c b/pjlib/src/pj/os_timestamp_win32.c
index a56254f..eeff6c0 100644
--- a/pjlib/src/pj/os_timestamp_win32.c
+++ b/pjlib/src/pj/os_timestamp_win32.c
@@ -1,44 +1,44 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/errno.h>

-#include <windows.h>

-

-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

-{

-    LARGE_INTEGER val;

-

-    if (!QueryPerformanceCounter(&val))

-	return PJ_RETURN_OS_ERROR(GetLastError());

-

-    ts->u64 = val.QuadPart;

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

-{

-    LARGE_INTEGER val;

-

-    if (!QueryPerformanceFrequency(&val))

-	return PJ_RETURN_OS_ERROR(GetLastError());

-

-    freq->u64 = val.QuadPart;

-    return PJ_SUCCESS;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/errno.h>
+#include <windows.h>
+
+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
+{
+    LARGE_INTEGER val;
+
+    if (!QueryPerformanceCounter(&val))
+	return PJ_RETURN_OS_ERROR(GetLastError());
+
+    ts->u64 = val.QuadPart;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
+{
+    LARGE_INTEGER val;
+
+    if (!QueryPerformanceFrequency(&val))
+	return PJ_RETURN_OS_ERROR(GetLastError());
+
+    freq->u64 = val.QuadPart;
+    return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/pool.c b/pjlib/src/pj/pool.c
index 3ad9d1b..2996680 100644
--- a/pjlib/src/pj/pool.c
+++ b/pjlib/src/pj/pool.c
@@ -1,272 +1,272 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/pool.h>

-#include <pj/log.h>

-#include <pj/except.h>

-#include <pj/assert.h>

-#include <pj/os.h>

-#include <pj/compat/sprintf.h>

-

-/* Include inline definitions when inlining is disabled. */

-#if !PJ_FUNCTIONS_ARE_INLINED

-#  include <pj/pool_i.h>

-#endif

-

-#define LOG(expr)   PJ_LOG(5,expr)

-

-int PJ_NO_MEMORY_EXCEPTION;

-

-/*

- * Create new block.

- * Create a new big chunk of memory block, from which user allocation will be

- * taken from.

- */

-static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)

-{

-    pj_pool_block *block;

-

-    PJ_CHECK_STACK();

-    pj_assert(size >= sizeof(pj_pool_block));

-

-    LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", 

-	 size, pool->capacity, pool->used_size));

-

-    /* Request memory from allocator. */

-    block = (pj_pool_block*) 

-	(*pool->factory->policy.block_alloc)(pool->factory, size);

-    if (block == NULL) {

-	(*pool->callback)(pool, size);

-	return NULL;

-    }

-

-    /* Add capacity. */

-    pool->capacity += size;

-    pool->used_size += sizeof(pj_pool_block);

-

-    /* Set block attribytes. */

-    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);

-    block->end = ((unsigned char*)block) + size;

-

-    /* Insert in the front of the list. */

-    pj_list_insert_after(&pool->block_list, block);

-

-    LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));

-

-    return block;

-}

-

-/*

- * Allocate memory chunk for user from available blocks.

- * This will iterate through block list to find space to allocate the chunk.

- * If no space is available in all the blocks, a new block might be created

- * (depending on whether the pool is allowed to resize).

- */

-PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)

-{

-    pj_pool_block *block = pool->block_list.next;

-    void *p;

-    unsigned block_size;

-

-    PJ_CHECK_STACK();

-

-    while (block != &pool->block_list) {

-	p = pj_pool_alloc_from_block(pool, block, size);

-	if (p != NULL)

-	    return p;

-	block = block->next;

-    }

-    /* No available space in all blocks. */

-

-    /* If pool is configured NOT to expand, return error. */

-    if (pool->increment_size == 0) {

-	LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "

-	     "(used=%u, cap=%u)",

-	     size, pool->used_size, pool->capacity));

-	(*pool->callback)(pool, size);

-	return NULL;

-    }

-

-    /* If pool is configured to expand, but the increment size

-     * is less than the required size, expand the pool by multiple

-     * increment size

-     */

-    if (pool->increment_size < size + sizeof(pj_pool_block)) {

-        unsigned count;

-        count = (size + pool->increment_size + sizeof(pj_pool_block)) / 

-                pool->increment_size;

-        block_size = count * pool->increment_size;

-

-    } else {

-        block_size = pool->increment_size;

-    }

-

-    LOG((pool->obj_name, 

-	 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",

-	 size, block_size, pool->used_size, pool->capacity));

-

-    block = pj_pool_create_block(pool, block_size);

-    if (!block)

-	return NULL;

-

-    p = pj_pool_alloc_from_block(pool, block, size);

-    pj_assert(p != NULL);

-#if PJ_DEBUG

-    if (p == NULL) {

-	p = p;

-    }

-#endif

-    return p;

-}

-

-/*

- * Internal function to initialize pool.

- */

-PJ_DEF(void) pj_pool_init_int(  pj_pool_t *pool, 

-				const char *name,

-				pj_size_t increment_size,

-				pj_pool_callback *callback)

-{

-    pj_pool_block *block;

-

-    PJ_CHECK_STACK();

-

-    pool->increment_size = increment_size;

-    pool->callback = callback;

-    pool->used_size = sizeof(*pool);

-    block = pool->block_list.next;

-    while (block != &pool->block_list) {

-	pool->used_size += sizeof(pj_pool_block);

-	block = block->next;

-    }

-

-    if (name) {

-	if (strchr(name, '%') != NULL) {

-	    sprintf(pool->obj_name, name, pool);

-	} else {

-	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);

-	}

-    } else {

-	pool->obj_name[0] = '\0';

-    }

-}

-

-/*

- * Create new memory pool.

- */

-PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,

-				       pj_size_t initial_size, 

-				       pj_size_t increment_size,

-				       pj_pool_callback *callback)

-{

-    pj_pool_t *pool;

-    pj_pool_block *block;

-    unsigned char *buffer;

-

-    PJ_CHECK_STACK();

-

-    buffer = (*f->policy.block_alloc)(f, initial_size);

-    if (!buffer)

-	return NULL;

-

-    /* Set pool administrative data. */

-    pool = (pj_pool_t*)buffer;

-    pj_memset(pool, 0, sizeof(*pool));

-

-    pj_list_init(&pool->block_list);

-    pool->factory = f;

-

-    /* Create the first block from the memory. */

-    block = (pj_pool_block*) (buffer + sizeof(*pool));

-    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);

-    block->end = buffer + initial_size;

-    pj_list_insert_after(&pool->block_list, block);

-

-    pj_pool_init_int(pool, name, increment_size, callback);

-

-    /* Pool initial capacity and used size */

-    pool->capacity = initial_size;

-

-    LOG((pool->obj_name, "pool created, size=%u", pool->capacity));

-    return pool;

-}

-

-/*

- * Reset the pool to the state when it was created.

- * All blocks will be deallocated except the first block. All memory areas

- * are marked as free.

- */

-static void reset_pool(pj_pool_t *pool)

-{

-    pj_pool_block *block;

-

-    PJ_CHECK_STACK();

-

-    block = pool->block_list.prev;

-    if (block == &pool->block_list)

-	return;

-

-    /* Skip the first block because it is occupying the same memory

-       as the pool itself.

-    */

-    block = block->prev;

-    

-    while (block != &pool->block_list) {

-	pj_pool_block *prev = block->prev;

-	pj_list_erase(block);

-	(*pool->factory->policy.block_free)(pool->factory, block, 

-					    block->end - (unsigned char*)block);

-	block = prev;

-    }

-

-    block = pool->block_list.next;

-    block->cur = block->buf;

-    pool->capacity = block->end - (unsigned char*)pool;

-    pool->used_size = 0;

-}

-

-/*

- * The public function to reset pool.

- */

-PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)

-{

-    LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)", 

-	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));

-

-    reset_pool(pool);

-}

-

-/*

- * Destroy the pool.

- */

-PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)

-{

-    pj_size_t initial_size;

-

-    LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p", 

-	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity,

-	((pj_pool_block*)pool->block_list.next)->buf, 

-	((pj_pool_block*)pool->block_list.next)->end));

-

-    reset_pool(pool);

-    initial_size = ((pj_pool_block*)pool->block_list.next)->end - 

-		   (unsigned char*)pool;

-    (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);

-}

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/pool.h>
+#include <pj/log.h>
+#include <pj/except.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/compat/sprintf.h>
+
+/* Include inline definitions when inlining is disabled. */
+#if !PJ_FUNCTIONS_ARE_INLINED
+#  include <pj/pool_i.h>
+#endif
+
+#define LOG(expr)   PJ_LOG(5,expr)
+
+int PJ_NO_MEMORY_EXCEPTION;
+
+/*
+ * Create new block.
+ * Create a new big chunk of memory block, from which user allocation will be
+ * taken from.
+ */
+static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
+{
+    pj_pool_block *block;
+
+    PJ_CHECK_STACK();
+    pj_assert(size >= sizeof(pj_pool_block));
+
+    LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", 
+	 size, pool->capacity, pool->used_size));
+
+    /* Request memory from allocator. */
+    block = (pj_pool_block*) 
+	(*pool->factory->policy.block_alloc)(pool->factory, size);
+    if (block == NULL) {
+	(*pool->callback)(pool, size);
+	return NULL;
+    }
+
+    /* Add capacity. */
+    pool->capacity += size;
+    pool->used_size += sizeof(pj_pool_block);
+
+    /* Set block attribytes. */
+    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
+    block->end = ((unsigned char*)block) + size;
+
+    /* Insert in the front of the list. */
+    pj_list_insert_after(&pool->block_list, block);
+
+    LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
+
+    return block;
+}
+
+/*
+ * Allocate memory chunk for user from available blocks.
+ * This will iterate through block list to find space to allocate the chunk.
+ * If no space is available in all the blocks, a new block might be created
+ * (depending on whether the pool is allowed to resize).
+ */
+PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
+{
+    pj_pool_block *block = pool->block_list.next;
+    void *p;
+    unsigned block_size;
+
+    PJ_CHECK_STACK();
+
+    while (block != &pool->block_list) {
+	p = pj_pool_alloc_from_block(pool, block, size);
+	if (p != NULL)
+	    return p;
+	block = block->next;
+    }
+    /* No available space in all blocks. */
+
+    /* If pool is configured NOT to expand, return error. */
+    if (pool->increment_size == 0) {
+	LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
+	     "(used=%u, cap=%u)",
+	     size, pool->used_size, pool->capacity));
+	(*pool->callback)(pool, size);
+	return NULL;
+    }
+
+    /* If pool is configured to expand, but the increment size
+     * is less than the required size, expand the pool by multiple
+     * increment size
+     */
+    if (pool->increment_size < size + sizeof(pj_pool_block)) {
+        unsigned count;
+        count = (size + pool->increment_size + sizeof(pj_pool_block)) / 
+                pool->increment_size;
+        block_size = count * pool->increment_size;
+
+    } else {
+        block_size = pool->increment_size;
+    }
+
+    LOG((pool->obj_name, 
+	 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
+	 size, block_size, pool->used_size, pool->capacity));
+
+    block = pj_pool_create_block(pool, block_size);
+    if (!block)
+	return NULL;
+
+    p = pj_pool_alloc_from_block(pool, block, size);
+    pj_assert(p != NULL);
+#if PJ_DEBUG
+    if (p == NULL) {
+	p = p;
+    }
+#endif
+    return p;
+}
+
+/*
+ * Internal function to initialize pool.
+ */
+PJ_DEF(void) pj_pool_init_int(  pj_pool_t *pool, 
+				const char *name,
+				pj_size_t increment_size,
+				pj_pool_callback *callback)
+{
+    pj_pool_block *block;
+
+    PJ_CHECK_STACK();
+
+    pool->increment_size = increment_size;
+    pool->callback = callback;
+    pool->used_size = sizeof(*pool);
+    block = pool->block_list.next;
+    while (block != &pool->block_list) {
+	pool->used_size += sizeof(pj_pool_block);
+	block = block->next;
+    }
+
+    if (name) {
+	if (strchr(name, '%') != NULL) {
+	    sprintf(pool->obj_name, name, pool);
+	} else {
+	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
+	}
+    } else {
+	pool->obj_name[0] = '\0';
+    }
+}
+
+/*
+ * Create new memory pool.
+ */
+PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
+				       pj_size_t initial_size, 
+				       pj_size_t increment_size,
+				       pj_pool_callback *callback)
+{
+    pj_pool_t *pool;
+    pj_pool_block *block;
+    unsigned char *buffer;
+
+    PJ_CHECK_STACK();
+
+    buffer = (*f->policy.block_alloc)(f, initial_size);
+    if (!buffer)
+	return NULL;
+
+    /* Set pool administrative data. */
+    pool = (pj_pool_t*)buffer;
+    pj_memset(pool, 0, sizeof(*pool));
+
+    pj_list_init(&pool->block_list);
+    pool->factory = f;
+
+    /* Create the first block from the memory. */
+    block = (pj_pool_block*) (buffer + sizeof(*pool));
+    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
+    block->end = buffer + initial_size;
+    pj_list_insert_after(&pool->block_list, block);
+
+    pj_pool_init_int(pool, name, increment_size, callback);
+
+    /* Pool initial capacity and used size */
+    pool->capacity = initial_size;
+
+    LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
+    return pool;
+}
+
+/*
+ * Reset the pool to the state when it was created.
+ * All blocks will be deallocated except the first block. All memory areas
+ * are marked as free.
+ */
+static void reset_pool(pj_pool_t *pool)
+{
+    pj_pool_block *block;
+
+    PJ_CHECK_STACK();
+
+    block = pool->block_list.prev;
+    if (block == &pool->block_list)
+	return;
+
+    /* Skip the first block because it is occupying the same memory
+       as the pool itself.
+    */
+    block = block->prev;
+    
+    while (block != &pool->block_list) {
+	pj_pool_block *prev = block->prev;
+	pj_list_erase(block);
+	(*pool->factory->policy.block_free)(pool->factory, block, 
+					    block->end - (unsigned char*)block);
+	block = prev;
+    }
+
+    block = pool->block_list.next;
+    block->cur = block->buf;
+    pool->capacity = block->end - (unsigned char*)pool;
+    pool->used_size = 0;
+}
+
+/*
+ * The public function to reset pool.
+ */
+PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
+{
+    LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)", 
+	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
+
+    reset_pool(pool);
+}
+
+/*
+ * Destroy the pool.
+ */
+PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
+{
+    pj_size_t initial_size;
+
+    LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p", 
+	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity,
+	((pj_pool_block*)pool->block_list.next)->buf, 
+	((pj_pool_block*)pool->block_list.next)->end));
+
+    reset_pool(pool);
+    initial_size = ((pj_pool_block*)pool->block_list.next)->end - 
+		   (unsigned char*)pool;
+    (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
+}
+
+
diff --git a/pjlib/src/pj/pool_caching.c b/pjlib/src/pj/pool_caching.c
index afeadae..5fa5ff7 100644
--- a/pjlib/src/pj/pool_caching.c
+++ b/pjlib/src/pj/pool_caching.c
@@ -1,221 +1,221 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/pool.h>

-#include <pj/log.h>

-#include <pj/string.h>

-#include <pj/assert.h>

-#include <pj/os.h>

-

-static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 

-				    const char *name,

-				    pj_size_t initial_size, 

-				    pj_size_t increment_sz,

-				    pj_pool_callback *callback);

-static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);

-static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );

-

-static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = 

-{

-    256, 512, 1024, 2048, 4096, 8192, 12288, 16384, 

-    20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536

-};

-

-

-PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, 

-				   const pj_pool_factory_policy *policy,

-				   pj_size_t max_capacity)

-{

-    int i;

-

-    PJ_CHECK_STACK();

-

-    pj_memset(cp, 0, sizeof(*cp));

-    

-    cp->max_capacity = max_capacity;

-    pj_list_init(&cp->used_list);

-    for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)

-	pj_list_init(&cp->free_list[i]);

-

-    pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));

-    cp->factory.create_pool = &cpool_create_pool;

-    cp->factory.release_pool = &cpool_release_pool;

-    cp->factory.dump_status = &cpool_dump_status;

-}

-

-PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )

-{

-    int i;

-    pj_pool_t *pool;

-

-    PJ_CHECK_STACK();

-

-    /* Delete all pool in free list */

-    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {

-	pj_pool_t *pool = cp->free_list[i].next;

-	pj_pool_t *next;

-	for (; pool != (void*)&cp->free_list[i]; pool = next) {

-	    next = pool->next;

-	    pj_list_erase(pool);

-	    pj_pool_destroy_int(pool);

-	}

-    }

-

-    /* Delete all pools in used list */

-    pool = cp->used_list.next;

-    while (pool != (pj_pool_t*) &cp->used_list) {

-	pj_pool_t *next = pool->next;

-	pj_list_erase(pool);

-	pj_pool_destroy_int(pool);

-	pool = next;

-    }

-}

-

-static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 

-					      const char *name, 

-					      pj_size_t initial_size, 

-					      pj_size_t increment_sz, 

-					      pj_pool_callback *callback)

-{

-    pj_caching_pool *cp = (pj_caching_pool*)pf;

-    pj_pool_t *pool;

-    int idx;

-

-    PJ_CHECK_STACK();

-

-    /* Use pool factory's policy when callback is NULL */

-    if (callback == NULL) {

-	callback = pf->policy.callback;

-    }

-

-    /* Search the suitable size for the pool. 

-     * We'll just do linear search to the size array, as the array size itself

-     * is only a few elements. Binary search I suspect will be less efficient

-     * for this purpose.

-     */

-    for (idx=0; 

-	 idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size; 

-	 ++idx)

-	;

-

-    /* Check whether there's a pool in the list. */

-    if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {

-	/* No pool is available. */

-	/* Set minimum size. */

-	if (idx < PJ_CACHING_POOL_ARRAY_SIZE)

-	    initial_size =  pool_sizes[idx];

-

-	/* Create new pool */

-	pool = pj_pool_create_int(&cp->factory, name, initial_size, 

-				  increment_sz, callback);

-	if (!pool)

-	    return NULL;

-

-    } else {

-	/* Get one pool from the list. */

-	pool = cp->free_list[idx].next;

-	pj_list_erase(pool);

-

-	/* Initialize the pool. */

-	pj_pool_init_int(pool, name, increment_sz, callback);

-

-	/* Update pool manager's free capacity. */

-	cp->capacity -= pj_pool_get_capacity(pool);

-

-	PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity));

-    }

-

-    /* Put in used list. */

-    pj_list_insert_before( &cp->used_list, pool );

-

-    /* Increment used count. */

-    ++cp->used_count;

-    return pool;

-}

-

-static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)

-{

-    pj_caching_pool *cp = (pj_caching_pool*)pf;

-    int i;

-

-    PJ_CHECK_STACK();

-

-    /* Erase from the used list. */

-    pj_list_erase(pool);

-

-    /* Decrement used count. */

-    --cp->used_count;

-

-    /* Destroy the pool if the size is greater than our size or if the total

-     * capacity in our recycle list (plus the size of the pool) exceeds 

-     * maximum capacity.

-   . */

-    if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||

-	cp->capacity + pool->capacity > cp->max_capacity)

-    {

-	pj_pool_destroy_int(pool);

-	return;

-    }

-

-    /* Reset pool. */

-    PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", 

-	       pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));

-    pj_pool_reset(pool);

-

-    /*

-     * Otherwise put the pool in our recycle list.

-     */

-    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i)

-	;

-

-    pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE );

-    if (i == PJ_CACHING_POOL_ARRAY_SIZE) {

-	/* Something has gone wrong with the pool. */

-	pj_pool_destroy_int(pool);

-	return;

-    }

-

-    pj_list_insert_after(&cp->free_list[i], pool);

-    cp->capacity += pool->capacity;

-}

-

-static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )

-{

-#if PJ_LOG_MAX_LEVEL >= 3

-    pj_caching_pool *cp = (pj_caching_pool*)factory;

-    PJ_LOG(3,("cachpool", " Dumping caching pool:"));

-    PJ_LOG(3,("cachpool", "   Capacity=%u, max_capacity=%u, used_cnt=%u", \

-			     cp->capacity, cp->max_capacity, cp->used_count));

-    if (detail) {

-	pj_pool_t *pool = cp->used_list.next;

-	pj_uint32_t total_used = 0, total_capacity = 0;

-        PJ_LOG(3,("cachpool", "  Dumping all active pools:"));

-	while (pool != (void*)&cp->used_list) {

-	    PJ_LOG(3,("cachpool", "   %12s: %8d of %8d (%d%%) used", pool->obj_name, 

-				  pool->used_size, pool->capacity,

-				  pool->used_size*100/pool->capacity));

-	    total_used += pool->used_size;

-	    total_capacity += pool->capacity;

-	    pool = pool->next;

-	}

-	PJ_LOG(3,("cachpool", "  Total %9d of %9d (%d %%) used!",

-			      total_used, total_capacity,

-			      total_used * 100 / total_capacity));

-    }

-#endif

-}

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/pool.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+
+static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 
+				    const char *name,
+				    pj_size_t initial_size, 
+				    pj_size_t increment_sz,
+				    pj_pool_callback *callback);
+static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);
+static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );
+
+static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = 
+{
+    256, 512, 1024, 2048, 4096, 8192, 12288, 16384, 
+    20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
+};
+
+
+PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, 
+				   const pj_pool_factory_policy *policy,
+				   pj_size_t max_capacity)
+{
+    int i;
+
+    PJ_CHECK_STACK();
+
+    pj_memset(cp, 0, sizeof(*cp));
+    
+    cp->max_capacity = max_capacity;
+    pj_list_init(&cp->used_list);
+    for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)
+	pj_list_init(&cp->free_list[i]);
+
+    pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));
+    cp->factory.create_pool = &cpool_create_pool;
+    cp->factory.release_pool = &cpool_release_pool;
+    cp->factory.dump_status = &cpool_dump_status;
+}
+
+PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
+{
+    int i;
+    pj_pool_t *pool;
+
+    PJ_CHECK_STACK();
+
+    /* Delete all pool in free list */
+    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {
+	pj_pool_t *pool = cp->free_list[i].next;
+	pj_pool_t *next;
+	for (; pool != (void*)&cp->free_list[i]; pool = next) {
+	    next = pool->next;
+	    pj_list_erase(pool);
+	    pj_pool_destroy_int(pool);
+	}
+    }
+
+    /* Delete all pools in used list */
+    pool = cp->used_list.next;
+    while (pool != (pj_pool_t*) &cp->used_list) {
+	pj_pool_t *next = pool->next;
+	pj_list_erase(pool);
+	pj_pool_destroy_int(pool);
+	pool = next;
+    }
+}
+
+static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 
+					      const char *name, 
+					      pj_size_t initial_size, 
+					      pj_size_t increment_sz, 
+					      pj_pool_callback *callback)
+{
+    pj_caching_pool *cp = (pj_caching_pool*)pf;
+    pj_pool_t *pool;
+    int idx;
+
+    PJ_CHECK_STACK();
+
+    /* Use pool factory's policy when callback is NULL */
+    if (callback == NULL) {
+	callback = pf->policy.callback;
+    }
+
+    /* Search the suitable size for the pool. 
+     * We'll just do linear search to the size array, as the array size itself
+     * is only a few elements. Binary search I suspect will be less efficient
+     * for this purpose.
+     */
+    for (idx=0; 
+	 idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size; 
+	 ++idx)
+	;
+
+    /* Check whether there's a pool in the list. */
+    if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
+	/* No pool is available. */
+	/* Set minimum size. */
+	if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
+	    initial_size =  pool_sizes[idx];
+
+	/* Create new pool */
+	pool = pj_pool_create_int(&cp->factory, name, initial_size, 
+				  increment_sz, callback);
+	if (!pool)
+	    return NULL;
+
+    } else {
+	/* Get one pool from the list. */
+	pool = cp->free_list[idx].next;
+	pj_list_erase(pool);
+
+	/* Initialize the pool. */
+	pj_pool_init_int(pool, name, increment_sz, callback);
+
+	/* Update pool manager's free capacity. */
+	cp->capacity -= pj_pool_get_capacity(pool);
+
+	PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity));
+    }
+
+    /* Put in used list. */
+    pj_list_insert_before( &cp->used_list, pool );
+
+    /* Increment used count. */
+    ++cp->used_count;
+    return pool;
+}
+
+static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
+{
+    pj_caching_pool *cp = (pj_caching_pool*)pf;
+    int i;
+
+    PJ_CHECK_STACK();
+
+    /* Erase from the used list. */
+    pj_list_erase(pool);
+
+    /* Decrement used count. */
+    --cp->used_count;
+
+    /* Destroy the pool if the size is greater than our size or if the total
+     * capacity in our recycle list (plus the size of the pool) exceeds 
+     * maximum capacity.
+   . */
+    if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
+	cp->capacity + pool->capacity > cp->max_capacity)
+    {
+	pj_pool_destroy_int(pool);
+	return;
+    }
+
+    /* Reset pool. */
+    PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", 
+	       pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
+    pj_pool_reset(pool);
+
+    /*
+     * Otherwise put the pool in our recycle list.
+     */
+    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i)
+	;
+
+    pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE );
+    if (i == PJ_CACHING_POOL_ARRAY_SIZE) {
+	/* Something has gone wrong with the pool. */
+	pj_pool_destroy_int(pool);
+	return;
+    }
+
+    pj_list_insert_after(&cp->free_list[i], pool);
+    cp->capacity += pool->capacity;
+}
+
+static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
+{
+#if PJ_LOG_MAX_LEVEL >= 3
+    pj_caching_pool *cp = (pj_caching_pool*)factory;
+    PJ_LOG(3,("cachpool", " Dumping caching pool:"));
+    PJ_LOG(3,("cachpool", "   Capacity=%u, max_capacity=%u, used_cnt=%u", \
+			     cp->capacity, cp->max_capacity, cp->used_count));
+    if (detail) {
+	pj_pool_t *pool = cp->used_list.next;
+	pj_uint32_t total_used = 0, total_capacity = 0;
+        PJ_LOG(3,("cachpool", "  Dumping all active pools:"));
+	while (pool != (void*)&cp->used_list) {
+	    PJ_LOG(3,("cachpool", "   %12s: %8d of %8d (%d%%) used", pool->obj_name, 
+				  pool->used_size, pool->capacity,
+				  pool->used_size*100/pool->capacity));
+	    total_used += pool->used_size;
+	    total_capacity += pool->capacity;
+	    pool = pool->next;
+	}
+	PJ_LOG(3,("cachpool", "  Total %9d of %9d (%d %%) used!",
+			      total_used, total_capacity,
+			      total_used * 100 / total_capacity));
+    }
+#endif
+}
diff --git a/pjlib/src/pj/pool_dbg_win32.c b/pjlib/src/pj/pool_dbg_win32.c
index e354d37..a3ccf3e 100644
--- a/pjlib/src/pj/pool_dbg_win32.c
+++ b/pjlib/src/pj/pool_dbg_win32.c
@@ -1,237 +1,237 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/pool.h>

-

-/* Only if we ARE debugging memory allocations. */

-#if PJ_POOL_DEBUG

-

-#include <pj/list.h>

-#include <pj/log.h>

-

-#include <stdlib.h>

-#include <stdio.h>

-#define WIN32_LEAN_AND_MEAN

-#include <windows.h>

-

-typedef struct memory_entry

-{

-    PJ_DECL_LIST_MEMBER(struct memory_entry)

-    void *ptr;

-    char *file;

-    int   line;

-} memory_entry;

-

-struct pj_pool_t

-{

-    char	    obj_name[32];

-    HANDLE	    hHeap;

-    memory_entry    first;

-    pj_size_t	    initial_size;

-    pj_size_t	    increment;

-    pj_size_t	    used_size;

-    char	   *file;

-    int		    line;

-};

-

-PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t),

-				     void (*free_func)(void *ptr, pj_size_t))

-{

-    /* Ignored. */

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(malloc_func)

-    PJ_UNUSED_ARG(free_func)

-}

-

-PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name,

-				       pj_size_t initial_size, 

-				       pj_size_t increment_size,

-				       pj_pool_callback *callback,

-				       char *file, int line)

-{

-    pj_pool_t *pool;

-    HANDLE hHeap;

-

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(callback)

-

-    /* Create Win32 heap for the pool. */

-    hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,

-		       initial_size, 0);

-    if (!hHeap) {

-	return NULL;

-    }

-

-

-    /* Create and initialize the pool structure. */

-    pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, 

-		     sizeof(*pool));

-    memset(pool, 0, sizeof(*pool));

-    pool->file = file;

-    pool->line = line;

-    pool->hHeap = hHeap;

-    pool->initial_size = initial_size;

-    pool->increment = increment_size;

-    pool->used_size = 0;

-

-    /* Set name. */

-    if (name) {

-	if (strchr(name, '%') != NULL) {

-	    sprintf(pool->obj_name, name, pool);

-	} else {

-	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);

-	}

-    } else {

-	pool->obj_name[0] = '\0';

-    }

-

-    /* List pool's entry. */

-    pj_list_init(&pool->first);

-

-    PJ_LOG(3,(pool->obj_name, "Pool created"));

-    return pool;

-}

-

-PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool )

-{

-    memory_entry *entry;

-

-    PJ_CHECK_STACK();

-

-    PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u",

-			      pool->initial_size, pool->used_size));

-

-    if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) {

-	PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d", 

-		  pool->file, pool->line));

-    }

-

-    /* Validate all memory entries in the pool. */

-    for (entry=pool->first.next; entry != &pool->first; entry = entry->next) {

-	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) {

-	    PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d", 

-		      entry->file, entry->line));

-	}

-

-	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) {

-	    PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d", 

-		      entry->file, entry->line));

-	}

-    }

-

-    /* Destroy heap. */

-    HeapDestroy(pool->hHeap);

-}

-

-PJ_DEF(void) pj_pool_reset( pj_pool_t *pool )

-{

-    /* Do nothing. */

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool)

-}

-

-PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool)

-    return 0;

-}

-

-PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool)

-    return 0;

-}

-

-PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool )

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool)

-    return 0;

-}

-

-PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size, 

-				 char *file, int line)

-{

-    memory_entry *entry;

-    int entry_size;

-

-    PJ_CHECK_STACK();

-

-    entry_size = sizeof(*entry);

-    entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,

-		      entry_size);

-    entry->file = file;

-    entry->line = line;

-    entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,

-			   size);

-    pj_list_insert_before( &pool->first, entry);

-

-    pool->used_size += size;

-    return entry->ptr;

-}

-

-PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem,

-				  char *file, int line)

-{

-    void *ptr;

-

-    PJ_CHECK_STACK();

-

-    ptr = pj_pool_alloc_dbg(pool, count*elem, file, line);

-    memset(ptr, 0, count*elem);

-    return ptr;

-}

-

-

-PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool, 

-				 pj_size_t max_capacity)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool_pool)

-    PJ_UNUSED_ARG(max_capacity)

-}

-

-PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool )

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool_pool)

-}

-

-PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool,

-					      const char *name,

-					      pj_size_t initial_size, 

-					      pj_size_t increment_size,

-					      pj_pool_callback *callback)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool_pool)

-    return pj_pool_create(name, initial_size, increment_size, callback);

-}

-

-PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool,

-					pj_pool_t *pool )

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool_pool)

-    pj_pool_destroy(pool);

-}

-

-

-#endif	/* PJ_POOL_DEBUG */

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/pool.h>
+
+/* Only if we ARE debugging memory allocations. */
+#if PJ_POOL_DEBUG
+
+#include <pj/list.h>
+#include <pj/log.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct memory_entry
+{
+    PJ_DECL_LIST_MEMBER(struct memory_entry)
+    void *ptr;
+    char *file;
+    int   line;
+} memory_entry;
+
+struct pj_pool_t
+{
+    char	    obj_name[32];
+    HANDLE	    hHeap;
+    memory_entry    first;
+    pj_size_t	    initial_size;
+    pj_size_t	    increment;
+    pj_size_t	    used_size;
+    char	   *file;
+    int		    line;
+};
+
+PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t),
+				     void (*free_func)(void *ptr, pj_size_t))
+{
+    /* Ignored. */
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(malloc_func)
+    PJ_UNUSED_ARG(free_func)
+}
+
+PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name,
+				       pj_size_t initial_size, 
+				       pj_size_t increment_size,
+				       pj_pool_callback *callback,
+				       char *file, int line)
+{
+    pj_pool_t *pool;
+    HANDLE hHeap;
+
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(callback)
+
+    /* Create Win32 heap for the pool. */
+    hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
+		       initial_size, 0);
+    if (!hHeap) {
+	return NULL;
+    }
+
+
+    /* Create and initialize the pool structure. */
+    pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, 
+		     sizeof(*pool));
+    memset(pool, 0, sizeof(*pool));
+    pool->file = file;
+    pool->line = line;
+    pool->hHeap = hHeap;
+    pool->initial_size = initial_size;
+    pool->increment = increment_size;
+    pool->used_size = 0;
+
+    /* Set name. */
+    if (name) {
+	if (strchr(name, '%') != NULL) {
+	    sprintf(pool->obj_name, name, pool);
+	} else {
+	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
+	}
+    } else {
+	pool->obj_name[0] = '\0';
+    }
+
+    /* List pool's entry. */
+    pj_list_init(&pool->first);
+
+    PJ_LOG(3,(pool->obj_name, "Pool created"));
+    return pool;
+}
+
+PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool )
+{
+    memory_entry *entry;
+
+    PJ_CHECK_STACK();
+
+    PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u",
+			      pool->initial_size, pool->used_size));
+
+    if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) {
+	PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d", 
+		  pool->file, pool->line));
+    }
+
+    /* Validate all memory entries in the pool. */
+    for (entry=pool->first.next; entry != &pool->first; entry = entry->next) {
+	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) {
+	    PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d", 
+		      entry->file, entry->line));
+	}
+
+	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) {
+	    PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d", 
+		      entry->file, entry->line));
+	}
+    }
+
+    /* Destroy heap. */
+    HeapDestroy(pool->hHeap);
+}
+
+PJ_DEF(void) pj_pool_reset( pj_pool_t *pool )
+{
+    /* Do nothing. */
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool)
+}
+
+PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool)
+    return 0;
+}
+
+PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool)
+    return 0;
+}
+
+PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool )
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool)
+    return 0;
+}
+
+PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size, 
+				 char *file, int line)
+{
+    memory_entry *entry;
+    int entry_size;
+
+    PJ_CHECK_STACK();
+
+    entry_size = sizeof(*entry);
+    entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
+		      entry_size);
+    entry->file = file;
+    entry->line = line;
+    entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
+			   size);
+    pj_list_insert_before( &pool->first, entry);
+
+    pool->used_size += size;
+    return entry->ptr;
+}
+
+PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem,
+				  char *file, int line)
+{
+    void *ptr;
+
+    PJ_CHECK_STACK();
+
+    ptr = pj_pool_alloc_dbg(pool, count*elem, file, line);
+    memset(ptr, 0, count*elem);
+    return ptr;
+}
+
+
+PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool, 
+				 pj_size_t max_capacity)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool_pool)
+    PJ_UNUSED_ARG(max_capacity)
+}
+
+PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool )
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool_pool)
+}
+
+PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool,
+					      const char *name,
+					      pj_size_t initial_size, 
+					      pj_size_t increment_size,
+					      pj_pool_callback *callback)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool_pool)
+    return pj_pool_create(name, initial_size, increment_size, callback);
+}
+
+PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool,
+					pj_pool_t *pool )
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool_pool)
+    pj_pool_destroy(pool);
+}
+
+
+#endif	/* PJ_POOL_DEBUG */
diff --git a/pjlib/src/pj/pool_policy_kmalloc.c b/pjlib/src/pj/pool_policy_kmalloc.c
index 0b848d0..020ab1e 100644
--- a/pjlib/src/pj/pool_policy_kmalloc.c
+++ b/pjlib/src/pj/pool_policy_kmalloc.c
@@ -1,58 +1,58 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/pool.h>

-#include <pj/except.h>

-#include <pj/os.h>

-

-

-static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(factory);

-

-    return kmalloc(size, GFP_ATOMIC);

-}

-

-static void default_block_free(pj_pool_factory *factory, 

-			       void *mem, pj_size_t size)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(factory);

-    PJ_UNUSED_ARG(size);

-

-    kfree(mem);

-}

-

-static void default_pool_callback(pj_pool_t *pool, pj_size_t size)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool);

-    PJ_UNUSED_ARG(size);

-

-    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);

-}

-

-pj_pool_factory_policy pj_pool_factory_default_policy = 

-{

-    &default_block_alloc,

-    &default_block_free,

-    &default_pool_callback,

-    0

-};

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/pool.h>
+#include <pj/except.h>
+#include <pj/os.h>
+
+
+static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(factory);
+
+    return kmalloc(size, GFP_ATOMIC);
+}
+
+static void default_block_free(pj_pool_factory *factory, 
+			       void *mem, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(factory);
+    PJ_UNUSED_ARG(size);
+
+    kfree(mem);
+}
+
+static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool);
+    PJ_UNUSED_ARG(size);
+
+    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
+}
+
+pj_pool_factory_policy pj_pool_factory_default_policy = 
+{
+    &default_block_alloc,
+    &default_block_free,
+    &default_pool_callback,
+    0
+};
+
diff --git a/pjlib/src/pj/pool_policy_malloc.c b/pjlib/src/pj/pool_policy_malloc.c
index 4a80708..05aca5b 100644
--- a/pjlib/src/pj/pool_policy_malloc.c
+++ b/pjlib/src/pj/pool_policy_malloc.c
@@ -1,62 +1,62 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/pool.h>

-#include <pj/except.h>

-#include <pj/os.h>

-#include <pj/compat/malloc.h>

-

-/*

- * This file contains pool default policy definition and implementation.

- */

-

-

-static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(factory);

-    PJ_UNUSED_ARG(size);

-

-    return malloc(size);

-}

-

-static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(factory);

-    PJ_UNUSED_ARG(size);

-

-    free(mem);

-}

-

-static void default_pool_callback(pj_pool_t *pool, pj_size_t size)

-{

-    PJ_CHECK_STACK();

-    PJ_UNUSED_ARG(pool);

-    PJ_UNUSED_ARG(size);

-

-    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);

-}

-

-pj_pool_factory_policy pj_pool_factory_default_policy = 

-{

-    &default_block_alloc,

-    &default_block_free,

-    &default_pool_callback,

-    0

-};

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/pool.h>
+#include <pj/except.h>
+#include <pj/os.h>
+#include <pj/compat/malloc.h>
+
+/*
+ * This file contains pool default policy definition and implementation.
+ */
+
+
+static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(factory);
+    PJ_UNUSED_ARG(size);
+
+    return malloc(size);
+}
+
+static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(factory);
+    PJ_UNUSED_ARG(size);
+
+    free(mem);
+}
+
+static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(pool);
+    PJ_UNUSED_ARG(size);
+
+    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
+}
+
+pj_pool_factory_policy pj_pool_factory_default_policy = 
+{
+    &default_block_alloc,
+    &default_block_free,
+    &default_pool_callback,
+    0
+};
diff --git a/pjlib/src/pj/rand.c b/pjlib/src/pj/rand.c
index 87704ed..a3a4b88 100644
--- a/pjlib/src/pj/rand.c
+++ b/pjlib/src/pj/rand.c
@@ -1,34 +1,34 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/rand.h>

-#include <pj/os.h>

-#include <pj/compat/rand.h>

-

-PJ_DEF(void) pj_srand(unsigned int seed)

-{

-    PJ_CHECK_STACK();

-    platform_srand(seed);

-}

-

-PJ_DEF(int) pj_rand(void)

-{

-    PJ_CHECK_STACK();

-    return platform_rand();

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/rand.h>
+#include <pj/os.h>
+#include <pj/compat/rand.h>
+
+PJ_DEF(void) pj_srand(unsigned int seed)
+{
+    PJ_CHECK_STACK();
+    platform_srand(seed);
+}
+
+PJ_DEF(int) pj_rand(void)
+{
+    PJ_CHECK_STACK();
+    return platform_rand();
+}
+
diff --git a/pjlib/src/pj/rbtree.c b/pjlib/src/pj/rbtree.c
index fa9f85a..af5d7e5 100644
--- a/pjlib/src/pj/rbtree.c
+++ b/pjlib/src/pj/rbtree.c
@@ -1,427 +1,427 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/rbtree.h>

-#include <pj/os.h>

-

-static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 

-{

-    pj_rbtree_node *rnode, *parent;

-

-    PJ_CHECK_STACK();

-

-    rnode = node->right;

-    if (rnode == tree->null)

-        return;

-    

-    node->right = rnode->left;

-    if (rnode->left != tree->null)

-        rnode->left->parent = node;

-    parent = node->parent;

-    rnode->parent = parent;

-    if (parent != tree->null) {

-        if (parent->left == node)

-	   parent->left = rnode;

-        else

-	   parent->right = rnode;

-    } else {

-        tree->root = rnode;

-    }

-    rnode->left = node;

-    node->parent = rnode;

-}

-

-static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 

-{

-    pj_rbtree_node *lnode, *parent;

-

-    PJ_CHECK_STACK();

-

-    lnode = node->left;

-    if (lnode == tree->null)

-        return;

-

-    node->left = lnode->right;

-    if (lnode->right != tree->null)

-	lnode->right->parent = node;

-    parent = node->parent;

-    lnode->parent = parent;

-

-    if (parent != tree->null) {

-        if (parent->left == node)

-	    parent->left = lnode;

-	else

-	    parent->right = lnode;

-    } else {

-        tree->root = lnode;

-    }

-    lnode->right = node;

-    node->parent = lnode;

-}

-

-static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node ) 

-{

-    pj_rbtree_node *temp, *parent;

-

-    PJ_CHECK_STACK();

-

-    while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) {

-        parent = node->parent;

-        if (parent == parent->parent->left) {

-	    temp = parent->parent->right;

-	    if (temp->color == PJ_RBCOLOR_RED) {

-	        temp->color = PJ_RBCOLOR_BLACK;

-	        node = parent;

-	        node->color = PJ_RBCOLOR_BLACK;

-	        node = node->parent;

-	        node->color = PJ_RBCOLOR_RED;

-	    } else {

-	        if (node == parent->right) {

-		   node = parent;

-		   left_rotate(tree, node);

-	        }

-	        temp = node->parent;

-	        temp->color = PJ_RBCOLOR_BLACK;

-	        temp = temp->parent;

-	        temp->color = PJ_RBCOLOR_RED;

-	        right_rotate( tree, temp);

-	    }

-        } else {

-	    temp = parent->parent->left;

-	    if (temp->color == PJ_RBCOLOR_RED) {

-	        temp->color = PJ_RBCOLOR_BLACK;

-	        node = parent;

-	        node->color = PJ_RBCOLOR_BLACK;

-	        node = node->parent;

-	        node->color = PJ_RBCOLOR_RED;

-	    } else {

-	        if (node == parent->left) {

-		    node = parent;

-		    right_rotate(tree, node);

-	        }

-	        temp = node->parent;

-	        temp->color = PJ_RBCOLOR_BLACK;

-	        temp = temp->parent;

-	        temp->color = PJ_RBCOLOR_RED;

-	        left_rotate(tree, temp);

-	   }

-        }

-    }

-	

-    tree->root->color = PJ_RBCOLOR_BLACK;

-}

-

-

-static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node )

-{

-    pj_rbtree_node *temp;

-

-    PJ_CHECK_STACK();

-

-    while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) {

-        if (node->parent->left == node) {

-	    temp = node->parent->right;

-	    if (temp->color == PJ_RBCOLOR_RED) {

-	        temp->color = PJ_RBCOLOR_BLACK;

-	        node->parent->color = PJ_RBCOLOR_RED;

-	        left_rotate(tree, node->parent);

-	        temp = node->parent->right;

-	    }

-	    if (temp->left->color == PJ_RBCOLOR_BLACK && 

-	        temp->right->color == PJ_RBCOLOR_BLACK) 

-	    {

-	        temp->color = PJ_RBCOLOR_RED;

-	        node = node->parent;

-	    } else {

-	        if (temp->right->color == PJ_RBCOLOR_BLACK) {

-		    temp->left->color = PJ_RBCOLOR_BLACK;

-		    temp->color = PJ_RBCOLOR_RED;

-		    right_rotate( tree, temp);

-		    temp = node->parent->right;

-	        }

-	        temp->color = node->parent->color;

-	        temp->right->color = PJ_RBCOLOR_BLACK;

-	        node->parent->color = PJ_RBCOLOR_BLACK;

-	        left_rotate(tree, node->parent);

-	        node = tree->root;

-	    }

-        } else {

-	    temp = node->parent->left;

-	    if (temp->color == PJ_RBCOLOR_RED) {

-	        temp->color = PJ_RBCOLOR_BLACK;

-	        node->parent->color = PJ_RBCOLOR_RED;

-	        right_rotate( tree, node->parent);

-	        temp = node->parent->left;

-	    }

-	    if (temp->right->color == PJ_RBCOLOR_BLACK && 

-		temp->left->color == PJ_RBCOLOR_BLACK) 

-	    {

-	        temp->color = PJ_RBCOLOR_RED;

-	        node = node->parent;

-	    } else {

-	        if (temp->left->color == PJ_RBCOLOR_BLACK) {

-		    temp->right->color = PJ_RBCOLOR_BLACK;

-		    temp->color = PJ_RBCOLOR_RED;

-		    left_rotate( tree, temp);

-		    temp = node->parent->left;

-	        }

-	        temp->color = node->parent->color;

-	        node->parent->color = PJ_RBCOLOR_BLACK;

-	        temp->left->color = PJ_RBCOLOR_BLACK;

-	        right_rotate(tree, node->parent);

-	        node = tree->root;

-	    }

-        }

-    }

-	

-    node->color = PJ_RBCOLOR_BLACK;

-}

-

-

-PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp )

-{

-    PJ_CHECK_STACK();

-

-    tree->null = tree->root = &tree->null_node;

-    tree->null->key = NULL;

-    tree->null->user_data = NULL;

-    tree->size = 0;

-    tree->null->left = tree->null->right = tree->null->parent = tree->null;

-    tree->null->color = PJ_RBCOLOR_BLACK;

-    tree->comp = comp;

-}

-

-PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree )

-{

-    register pj_rbtree_node *node = tree->root;

-    register pj_rbtree_node *null = tree->null;

-    

-    PJ_CHECK_STACK();

-

-    while (node->left != null)

-	node = node->left;

-    return node != null ? node : NULL;

-}

-

-PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree )

-{

-    register pj_rbtree_node *node = tree->root;

-    register pj_rbtree_node *null = tree->null;

-    

-    PJ_CHECK_STACK();

-

-    while (node->right != null)

-	node = node->right;

-    return node != null ? node : NULL;

-}

-

-PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 

-					register pj_rbtree_node *node )

-{

-    register pj_rbtree_node *null = tree->null;

-    

-    PJ_CHECK_STACK();

-

-    if (node->right != null) {

-	for (node=node->right; node->left!=null; node = node->left)

-	    /* void */;

-    } else {

-        register pj_rbtree_node *temp = node->parent;

-        while (temp!=null && temp->right==node) {

-	    node = temp;

-	    temp = temp->parent;

-	}

-	node = temp;

-    }    

-    return node != null ? node : NULL;

-}

-

-PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 

-					register pj_rbtree_node *node )

-{

-    register pj_rbtree_node *null = tree->null;

-    

-    PJ_CHECK_STACK();

-

-    if (node->left != null) {

-        for (node=node->left; node->right!=null; node=node->right)

-	   /* void */;

-    } else {

-        register pj_rbtree_node *temp = node->parent;

-        while (temp!=null && temp->left==node) {

-	    node = temp;

-	    temp = temp->parent;

-        }

-        node = temp;

-    }    

-    return node != null ? node : NULL;

-}

-

-PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree, 

-			      pj_rbtree_node *element )

-{

-    int rv = 0;

-    pj_rbtree_node *node, *parent = tree->null, 

-		   *null = tree->null;

-    pj_rbtree_comp *comp = tree->comp;

-	

-    PJ_CHECK_STACK();

-

-    node = tree->root;	

-    while (node != null) {

-        rv = (*comp)(element->key, node->key);

-        if (rv == 0) {

-	    /* found match, i.e. entry with equal key already exist */

-	    return -1;

-	}    

-	parent = node;

-        node = rv < 0 ? node->left : node->right;

-    }

-

-    element->color = PJ_RBCOLOR_RED;

-    element->left = element->right = null;

-

-    node = element;

-    if (parent != null) {

-        node->parent = parent;

-        if (rv < 0)

-	   parent->left = node;

-        else

-	   parent->right = node;

-        insert_fixup( tree, node);

-    } else {

-        tree->root = node;

-        node->parent = null;

-        node->color = PJ_RBCOLOR_BLACK;

-    }

-	

-    ++tree->size;

-    return 0;

-}

-

-

-PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,

-					const void *key )

-{

-    int rv;

-    pj_rbtree_node *node = tree->root;

-    pj_rbtree_node *null = tree->null;

-    pj_rbtree_comp *comp = tree->comp;

-    

-    while (node != null) {

-        rv = (*comp)(key, node->key);

-        if (rv == 0)

-	    return node;

-        node = rv < 0 ? node->left : node->right;

-    }

-    return node != null ? node : NULL;

-}

-

-PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,

-					 pj_rbtree_node *node )

-{

-    pj_rbtree_node *succ;

-    pj_rbtree_node *null = tree->null;

-    pj_rbtree_node *child;

-    pj_rbtree_node *parent;

-    

-    PJ_CHECK_STACK();

-

-    if (node->left == null || node->right == null) {

-        succ = node;

-    } else {

-        for (succ=node->right; succ->left!=null; succ=succ->left)

-	   /* void */;

-    }

-

-    child = succ->left != null ? succ->left : succ->right;

-    parent = succ->parent;

-    child->parent = parent;

-    

-    if (parent != null) {

-	if (parent->left == succ)

-	    parent->left = child;

-        else

-	   parent->right = child;

-    } else

-        tree->root = child;

-

-    if (succ != node) {

-        succ->parent = node->parent;

-        succ->left = node->left;

-        succ->right = node->right;

-        succ->color = node->color;

-

-        parent = node->parent;

-        if (parent != null) {

-	   if (parent->left==node)

-	        parent->left=succ;

-	   else

-		parent->right=succ;

-        }

-        if (node->left != null)

-	   node->left->parent = succ;;

-        if (node->right != null)

-	    node->right->parent = succ;

-

-        if (tree->root == node)

-	   tree->root = succ;

-    }

-

-    if (succ->color == PJ_RBCOLOR_BLACK) {

-	if (child != null) 

-	    delete_fixup(tree, child);

-        tree->null->color = PJ_RBCOLOR_BLACK;

-    }

-

-    --tree->size;

-    return node;

-}

-

-

-PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree,

-				       pj_rbtree_node *node )

-{

-    unsigned l, r;

-    

-    PJ_CHECK_STACK();

-

-    if (node==NULL) 

-	node = tree->root;

-    

-    l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0;

-    r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0;

-    return l > r ? l : r;

-}

-

-PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree,

-				       pj_rbtree_node *node )

-{

-    unsigned l, r;

-    

-    PJ_CHECK_STACK();

-

-    if (node==NULL) 

-	node=tree->root;

-    

-    l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0;

-    r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0;

-    return l > r ? r : l;

-}

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/rbtree.h>
+#include <pj/os.h>
+
+static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 
+{
+    pj_rbtree_node *rnode, *parent;
+
+    PJ_CHECK_STACK();
+
+    rnode = node->right;
+    if (rnode == tree->null)
+        return;
+    
+    node->right = rnode->left;
+    if (rnode->left != tree->null)
+        rnode->left->parent = node;
+    parent = node->parent;
+    rnode->parent = parent;
+    if (parent != tree->null) {
+        if (parent->left == node)
+	   parent->left = rnode;
+        else
+	   parent->right = rnode;
+    } else {
+        tree->root = rnode;
+    }
+    rnode->left = node;
+    node->parent = rnode;
+}
+
+static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 
+{
+    pj_rbtree_node *lnode, *parent;
+
+    PJ_CHECK_STACK();
+
+    lnode = node->left;
+    if (lnode == tree->null)
+        return;
+
+    node->left = lnode->right;
+    if (lnode->right != tree->null)
+	lnode->right->parent = node;
+    parent = node->parent;
+    lnode->parent = parent;
+
+    if (parent != tree->null) {
+        if (parent->left == node)
+	    parent->left = lnode;
+	else
+	    parent->right = lnode;
+    } else {
+        tree->root = lnode;
+    }
+    lnode->right = node;
+    node->parent = lnode;
+}
+
+static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node ) 
+{
+    pj_rbtree_node *temp, *parent;
+
+    PJ_CHECK_STACK();
+
+    while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) {
+        parent = node->parent;
+        if (parent == parent->parent->left) {
+	    temp = parent->parent->right;
+	    if (temp->color == PJ_RBCOLOR_RED) {
+	        temp->color = PJ_RBCOLOR_BLACK;
+	        node = parent;
+	        node->color = PJ_RBCOLOR_BLACK;
+	        node = node->parent;
+	        node->color = PJ_RBCOLOR_RED;
+	    } else {
+	        if (node == parent->right) {
+		   node = parent;
+		   left_rotate(tree, node);
+	        }
+	        temp = node->parent;
+	        temp->color = PJ_RBCOLOR_BLACK;
+	        temp = temp->parent;
+	        temp->color = PJ_RBCOLOR_RED;
+	        right_rotate( tree, temp);
+	    }
+        } else {
+	    temp = parent->parent->left;
+	    if (temp->color == PJ_RBCOLOR_RED) {
+	        temp->color = PJ_RBCOLOR_BLACK;
+	        node = parent;
+	        node->color = PJ_RBCOLOR_BLACK;
+	        node = node->parent;
+	        node->color = PJ_RBCOLOR_RED;
+	    } else {
+	        if (node == parent->left) {
+		    node = parent;
+		    right_rotate(tree, node);
+	        }
+	        temp = node->parent;
+	        temp->color = PJ_RBCOLOR_BLACK;
+	        temp = temp->parent;
+	        temp->color = PJ_RBCOLOR_RED;
+	        left_rotate(tree, temp);
+	   }
+        }
+    }
+	
+    tree->root->color = PJ_RBCOLOR_BLACK;
+}
+
+
+static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node )
+{
+    pj_rbtree_node *temp;
+
+    PJ_CHECK_STACK();
+
+    while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) {
+        if (node->parent->left == node) {
+	    temp = node->parent->right;
+	    if (temp->color == PJ_RBCOLOR_RED) {
+	        temp->color = PJ_RBCOLOR_BLACK;
+	        node->parent->color = PJ_RBCOLOR_RED;
+	        left_rotate(tree, node->parent);
+	        temp = node->parent->right;
+	    }
+	    if (temp->left->color == PJ_RBCOLOR_BLACK && 
+	        temp->right->color == PJ_RBCOLOR_BLACK) 
+	    {
+	        temp->color = PJ_RBCOLOR_RED;
+	        node = node->parent;
+	    } else {
+	        if (temp->right->color == PJ_RBCOLOR_BLACK) {
+		    temp->left->color = PJ_RBCOLOR_BLACK;
+		    temp->color = PJ_RBCOLOR_RED;
+		    right_rotate( tree, temp);
+		    temp = node->parent->right;
+	        }
+	        temp->color = node->parent->color;
+	        temp->right->color = PJ_RBCOLOR_BLACK;
+	        node->parent->color = PJ_RBCOLOR_BLACK;
+	        left_rotate(tree, node->parent);
+	        node = tree->root;
+	    }
+        } else {
+	    temp = node->parent->left;
+	    if (temp->color == PJ_RBCOLOR_RED) {
+	        temp->color = PJ_RBCOLOR_BLACK;
+	        node->parent->color = PJ_RBCOLOR_RED;
+	        right_rotate( tree, node->parent);
+	        temp = node->parent->left;
+	    }
+	    if (temp->right->color == PJ_RBCOLOR_BLACK && 
+		temp->left->color == PJ_RBCOLOR_BLACK) 
+	    {
+	        temp->color = PJ_RBCOLOR_RED;
+	        node = node->parent;
+	    } else {
+	        if (temp->left->color == PJ_RBCOLOR_BLACK) {
+		    temp->right->color = PJ_RBCOLOR_BLACK;
+		    temp->color = PJ_RBCOLOR_RED;
+		    left_rotate( tree, temp);
+		    temp = node->parent->left;
+	        }
+	        temp->color = node->parent->color;
+	        node->parent->color = PJ_RBCOLOR_BLACK;
+	        temp->left->color = PJ_RBCOLOR_BLACK;
+	        right_rotate(tree, node->parent);
+	        node = tree->root;
+	    }
+        }
+    }
+	
+    node->color = PJ_RBCOLOR_BLACK;
+}
+
+
+PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp )
+{
+    PJ_CHECK_STACK();
+
+    tree->null = tree->root = &tree->null_node;
+    tree->null->key = NULL;
+    tree->null->user_data = NULL;
+    tree->size = 0;
+    tree->null->left = tree->null->right = tree->null->parent = tree->null;
+    tree->null->color = PJ_RBCOLOR_BLACK;
+    tree->comp = comp;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree )
+{
+    register pj_rbtree_node *node = tree->root;
+    register pj_rbtree_node *null = tree->null;
+    
+    PJ_CHECK_STACK();
+
+    while (node->left != null)
+	node = node->left;
+    return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree )
+{
+    register pj_rbtree_node *node = tree->root;
+    register pj_rbtree_node *null = tree->null;
+    
+    PJ_CHECK_STACK();
+
+    while (node->right != null)
+	node = node->right;
+    return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 
+					register pj_rbtree_node *node )
+{
+    register pj_rbtree_node *null = tree->null;
+    
+    PJ_CHECK_STACK();
+
+    if (node->right != null) {
+	for (node=node->right; node->left!=null; node = node->left)
+	    /* void */;
+    } else {
+        register pj_rbtree_node *temp = node->parent;
+        while (temp!=null && temp->right==node) {
+	    node = temp;
+	    temp = temp->parent;
+	}
+	node = temp;
+    }    
+    return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 
+					register pj_rbtree_node *node )
+{
+    register pj_rbtree_node *null = tree->null;
+    
+    PJ_CHECK_STACK();
+
+    if (node->left != null) {
+        for (node=node->left; node->right!=null; node=node->right)
+	   /* void */;
+    } else {
+        register pj_rbtree_node *temp = node->parent;
+        while (temp!=null && temp->left==node) {
+	    node = temp;
+	    temp = temp->parent;
+        }
+        node = temp;
+    }    
+    return node != null ? node : NULL;
+}
+
+PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree, 
+			      pj_rbtree_node *element )
+{
+    int rv = 0;
+    pj_rbtree_node *node, *parent = tree->null, 
+		   *null = tree->null;
+    pj_rbtree_comp *comp = tree->comp;
+	
+    PJ_CHECK_STACK();
+
+    node = tree->root;	
+    while (node != null) {
+        rv = (*comp)(element->key, node->key);
+        if (rv == 0) {
+	    /* found match, i.e. entry with equal key already exist */
+	    return -1;
+	}    
+	parent = node;
+        node = rv < 0 ? node->left : node->right;
+    }
+
+    element->color = PJ_RBCOLOR_RED;
+    element->left = element->right = null;
+
+    node = element;
+    if (parent != null) {
+        node->parent = parent;
+        if (rv < 0)
+	   parent->left = node;
+        else
+	   parent->right = node;
+        insert_fixup( tree, node);
+    } else {
+        tree->root = node;
+        node->parent = null;
+        node->color = PJ_RBCOLOR_BLACK;
+    }
+	
+    ++tree->size;
+    return 0;
+}
+
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,
+					const void *key )
+{
+    int rv;
+    pj_rbtree_node *node = tree->root;
+    pj_rbtree_node *null = tree->null;
+    pj_rbtree_comp *comp = tree->comp;
+    
+    while (node != null) {
+        rv = (*comp)(key, node->key);
+        if (rv == 0)
+	    return node;
+        node = rv < 0 ? node->left : node->right;
+    }
+    return node != null ? node : NULL;
+}
+
+PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,
+					 pj_rbtree_node *node )
+{
+    pj_rbtree_node *succ;
+    pj_rbtree_node *null = tree->null;
+    pj_rbtree_node *child;
+    pj_rbtree_node *parent;
+    
+    PJ_CHECK_STACK();
+
+    if (node->left == null || node->right == null) {
+        succ = node;
+    } else {
+        for (succ=node->right; succ->left!=null; succ=succ->left)
+	   /* void */;
+    }
+
+    child = succ->left != null ? succ->left : succ->right;
+    parent = succ->parent;
+    child->parent = parent;
+    
+    if (parent != null) {
+	if (parent->left == succ)
+	    parent->left = child;
+        else
+	   parent->right = child;
+    } else
+        tree->root = child;
+
+    if (succ != node) {
+        succ->parent = node->parent;
+        succ->left = node->left;
+        succ->right = node->right;
+        succ->color = node->color;
+
+        parent = node->parent;
+        if (parent != null) {
+	   if (parent->left==node)
+	        parent->left=succ;
+	   else
+		parent->right=succ;
+        }
+        if (node->left != null)
+	   node->left->parent = succ;;
+        if (node->right != null)
+	    node->right->parent = succ;
+
+        if (tree->root == node)
+	   tree->root = succ;
+    }
+
+    if (succ->color == PJ_RBCOLOR_BLACK) {
+	if (child != null) 
+	    delete_fixup(tree, child);
+        tree->null->color = PJ_RBCOLOR_BLACK;
+    }
+
+    --tree->size;
+    return node;
+}
+
+
+PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree,
+				       pj_rbtree_node *node )
+{
+    unsigned l, r;
+    
+    PJ_CHECK_STACK();
+
+    if (node==NULL) 
+	node = tree->root;
+    
+    l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0;
+    r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0;
+    return l > r ? l : r;
+}
+
+PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree,
+				       pj_rbtree_node *node )
+{
+    unsigned l, r;
+    
+    PJ_CHECK_STACK();
+
+    if (node==NULL) 
+	node=tree->root;
+    
+    l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0;
+    r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0;
+    return l > r ? r : l;
+}
+
+
diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
index 4db8e9c..5a09693 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -1,584 +1,584 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/os.h>

-#include <pj/assert.h>

-#include <pj/string.h>

-#include <pj/compat/socket.h>

-#include <pj/addr_resolv.h>

-#include <pj/errno.h>

-

-/*

- * 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

-const pj_uint16_t PJ_AF_PACKET	= 0xFFFF;

-#endif

-#ifdef AF_IRDA

-const pj_uint16_t PJ_AF_IRDA	= AF_IRDA;

-#else

-const pj_uint16_t PJ_AF_IRDA	= 0xFFFF;

-#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

-const pj_uint16_t PJ_SOL_IP	= 0xFFFF;

-#endif /* SOL_IP */

-#if defined(SOL_TCP)

-const pj_uint16_t PJ_SOL_TCP	= SOL_TCP;

-#elif defined(IPPROTO_TCP)

-const pj_uint16_t PJ_SOL_TCP	= IPPROTO_TCP;

-#endif /* SOL_TCP */

-#ifdef SOL_UDP

-const pj_uint16_t PJ_SOL_UDP	= SOL_UDP;

-#else

-const pj_uint16_t PJ_SOL_UDP	= 0xFFFF;

-#endif

-#ifdef SOL_IPV6

-const pj_uint16_t PJ_SOL_IPV6	= SOL_IPV6;

-#else

-const pj_uint16_t PJ_SOL_IPV6	= 0xFFFF;

-#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 inaddr)

-{

-#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)

-    return inet_ntoa(*(struct in_addr*)&inaddr);

-#else

-    struct in_addr addr;

-    addr.s_addr = inaddr.s_addr;

-    return inet_ntoa(addr);

-#endif

-}

-

-/*

- * This function converts the Internet host address cp 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 *cp, struct pj_in_addr *inp)

-{

-    char tempaddr[16];

-

-    /* Initialize output with PJ_INADDR_NONE.

-     * Some apps relies on this instead of the return value

-     * (and anyway the return value is quite confusing!)

-     */

-    inp->s_addr = PJ_INADDR_NONE;

-

-    /* Caution:

-     *	this function might be called with cp->slen >= 16

-     *  (i.e. when called with hostname to check if it's an IP addr).

-     */

-    PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);

-    if (cp->slen >= 16) {

-	return 0;

-    }

-

-    pj_memcpy(tempaddr, cp->ptr, cp->slen);

-    tempaddr[cp->slen] = '\0';

-

-#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0

-    return inet_aton(tempaddr, (struct in_addr*)inp);

-#else

-    inp->s_addr = inet_addr(tempaddr);

-    return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;

-#endif

-}

-

-/*

- * 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_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME, 

-                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));

-

-    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;

-	    pj_status_t rc;

-

-	    rc = pj_gethostbyname(str_addr, &he);

-	    if (rc == 0) {

-		addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;

-	    } else {

-		addr->sin_addr.s_addr = PJ_INADDR_NONE;

-		return rc;

-	    }

-	}

-

-    } 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_RETURN(addr && str_addr, 

-                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));

-

-    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;

-	if (gethostname(buf, sizeof(buf)) != 0) {

-	    hostname.ptr[0] = '\0';

-	    hostname.slen = 0;

-	} else {

-	   hostname.slen = strlen(buf);

-	}

-    }

-    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;

-}

-

-

-#if defined(PJ_WIN32)

-/*

- * 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)

-{

-    PJ_CHECK_STACK();

-

-    /* Sanity checks. */

-    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);

-    PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET, 

-                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));

-

-    *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);

-

-    if (*sock == PJ_INVALID_SOCKET) 

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-#else

-/*

- * 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)

-{

-

-    PJ_CHECK_STACK();

-

-    /* Sanity checks. */

-    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);

-    PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1, 

-                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));

-

-    *sock = socket(af, type, proto);

-    if (*sock == PJ_INVALID_SOCKET)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else 

-	return PJ_SUCCESS;

-}

-#endif

-

-

-/*

- * Bind socket.

- */

-PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, 

-				  const pj_sockaddr_t *addr,

-				  int len)

-{

-    PJ_CHECK_STACK();

-

-    PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);

-

-    if (bind(sock, (struct sockaddr*)addr, len) != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-

-/*

- * Bind socket.

- */

-PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, 

-				     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(sock, &addr, sizeof(pj_sockaddr_in));

-}

-

-

-/*

- * Close socket.

- */

-PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)

-{

-    int rc;

-

-    PJ_CHECK_STACK();

-#if defined(PJ_WIN32) && PJ_WIN32==1

-    rc = closesocket(sock);

-#else

-    rc = close(sock);

-#endif

-

-    if (rc != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Get remote's name.

- */

-PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,

-					 pj_sockaddr_t *addr,

-					 int *namelen)

-{

-    PJ_CHECK_STACK();

-    if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Get socket name.

- */

-PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,

-					 pj_sockaddr_t *addr,

-					 int *namelen)

-{

-    PJ_CHECK_STACK();

-    if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Send data

- */

-PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,

-				 const void *buf,

-				 pj_ssize_t *len,

-				 unsigned flags)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(len, PJ_EINVAL);

-

-    *len = send(sock, (const char*)buf, *len, flags);

-

-    if (*len < 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-

-/*

- * Send data.

- */

-PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,

-				   const void *buf,

-				   pj_ssize_t *len,

-				   unsigned flags,

-				   const pj_sockaddr_t *to,

-				   int tolen)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(len, PJ_EINVAL);

-

-    *len = sendto(sock, (const char*)buf, *len, flags, 

-		  (const struct sockaddr*)to, tolen);

-

-    if (*len < 0) 

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else 

-	return PJ_SUCCESS;

-}

-

-/*

- * Receive data.

- */

-PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,

-				 void *buf,

-				 pj_ssize_t *len,

-				 unsigned flags)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);

-

-    *len = recv(sock, (char*)buf, *len, flags);

-

-    if (*len < 0) 

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Receive data.

- */

-PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,

-				     void *buf,

-				     pj_ssize_t *len,

-				     unsigned flags,

-				     pj_sockaddr_t *from,

-				     int *fromlen)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);

-    PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));

-

-    *len = recvfrom(sock, (char*)buf, *len, flags, 

-		    (struct sockaddr*)from, (socklen_t*)fromlen);

-

-    if (*len < 0) 

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Get socket option.

- */

-PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,

-					pj_uint16_t level,

-					pj_uint16_t optname,

-					void *optval,

-					int *optlen)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);

-

-    if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Set socket option.

- */

-PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,

-					pj_uint16_t level,

-					pj_uint16_t optname,

-					const void *optval,

-					int optlen)

-{

-    PJ_CHECK_STACK();

-    if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Shutdown socket.

- */

-#if PJ_HAS_TCP

-PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,

-				      int how)

-{

-    PJ_CHECK_STACK();

-    if (shutdown(sock, how) != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Start listening to incoming connections.

- */

-PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,

-				    int backlog)

-{

-    PJ_CHECK_STACK();

-    if (listen(sock, backlog) != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Connect socket.

- */

-PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,

-				     const pj_sockaddr_t *addr,

-				     int namelen)

-{

-    PJ_CHECK_STACK();

-    if (connect(sock, (struct sockaddr*)addr, namelen) != 0)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-

-/*

- * Accept incoming connections

- */

-PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,

-				    pj_sock_t *newsock,

-				    pj_sockaddr_t *addr,

-				    int *addrlen)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);

-

-    *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);

-    if (*newsock==PJ_INVALID_SOCKET)

-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

-    else

-	return PJ_SUCCESS;

-}

-#endif	/* PJ_HAS_TCP */

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/os.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+#include <pj/addr_resolv.h>
+#include <pj/errno.h>
+
+/*
+ * 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
+const pj_uint16_t PJ_AF_PACKET	= 0xFFFF;
+#endif
+#ifdef AF_IRDA
+const pj_uint16_t PJ_AF_IRDA	= AF_IRDA;
+#else
+const pj_uint16_t PJ_AF_IRDA	= 0xFFFF;
+#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
+const pj_uint16_t PJ_SOL_IP	= 0xFFFF;
+#endif /* SOL_IP */
+#if defined(SOL_TCP)
+const pj_uint16_t PJ_SOL_TCP	= SOL_TCP;
+#elif defined(IPPROTO_TCP)
+const pj_uint16_t PJ_SOL_TCP	= IPPROTO_TCP;
+#endif /* SOL_TCP */
+#ifdef SOL_UDP
+const pj_uint16_t PJ_SOL_UDP	= SOL_UDP;
+#else
+const pj_uint16_t PJ_SOL_UDP	= 0xFFFF;
+#endif
+#ifdef SOL_IPV6
+const pj_uint16_t PJ_SOL_IPV6	= SOL_IPV6;
+#else
+const pj_uint16_t PJ_SOL_IPV6	= 0xFFFF;
+#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 inaddr)
+{
+#if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)
+    return inet_ntoa(*(struct in_addr*)&inaddr);
+#else
+    struct in_addr addr;
+    addr.s_addr = inaddr.s_addr;
+    return inet_ntoa(addr);
+#endif
+}
+
+/*
+ * This function converts the Internet host address cp 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 *cp, struct pj_in_addr *inp)
+{
+    char tempaddr[16];
+
+    /* Initialize output with PJ_INADDR_NONE.
+     * Some apps relies on this instead of the return value
+     * (and anyway the return value is quite confusing!)
+     */
+    inp->s_addr = PJ_INADDR_NONE;
+
+    /* Caution:
+     *	this function might be called with cp->slen >= 16
+     *  (i.e. when called with hostname to check if it's an IP addr).
+     */
+    PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
+    if (cp->slen >= 16) {
+	return 0;
+    }
+
+    pj_memcpy(tempaddr, cp->ptr, cp->slen);
+    tempaddr[cp->slen] = '\0';
+
+#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
+    return inet_aton(tempaddr, (struct in_addr*)inp);
+#else
+    inp->s_addr = inet_addr(tempaddr);
+    return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
+#endif
+}
+
+/*
+ * 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_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME, 
+                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
+
+    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;
+	    pj_status_t rc;
+
+	    rc = pj_gethostbyname(str_addr, &he);
+	    if (rc == 0) {
+		addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
+	    } else {
+		addr->sin_addr.s_addr = PJ_INADDR_NONE;
+		return rc;
+	    }
+	}
+
+    } 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_RETURN(addr && str_addr, 
+                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
+
+    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;
+	if (gethostname(buf, sizeof(buf)) != 0) {
+	    hostname.ptr[0] = '\0';
+	    hostname.slen = 0;
+	} else {
+	   hostname.slen = strlen(buf);
+	}
+    }
+    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;
+}
+
+
+#if defined(PJ_WIN32)
+/*
+ * 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)
+{
+    PJ_CHECK_STACK();
+
+    /* Sanity checks. */
+    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
+    PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET, 
+                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
+
+    *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
+
+    if (*sock == PJ_INVALID_SOCKET) 
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+#else
+/*
+ * 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)
+{
+
+    PJ_CHECK_STACK();
+
+    /* Sanity checks. */
+    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
+    PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1, 
+                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
+
+    *sock = socket(af, type, proto);
+    if (*sock == PJ_INVALID_SOCKET)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else 
+	return PJ_SUCCESS;
+}
+#endif
+
+
+/*
+ * Bind socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, 
+				  const pj_sockaddr_t *addr,
+				  int len)
+{
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);
+
+    if (bind(sock, (struct sockaddr*)addr, len) != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+
+/*
+ * Bind socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, 
+				     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(sock, &addr, sizeof(pj_sockaddr_in));
+}
+
+
+/*
+ * Close socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
+{
+    int rc;
+
+    PJ_CHECK_STACK();
+#if defined(PJ_WIN32) && PJ_WIN32==1
+    rc = closesocket(sock);
+#else
+    rc = close(sock);
+#endif
+
+    if (rc != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Get remote's name.
+ */
+PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
+					 pj_sockaddr_t *addr,
+					 int *namelen)
+{
+    PJ_CHECK_STACK();
+    if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Get socket name.
+ */
+PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
+					 pj_sockaddr_t *addr,
+					 int *namelen)
+{
+    PJ_CHECK_STACK();
+    if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Send data
+ */
+PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
+				 const void *buf,
+				 pj_ssize_t *len,
+				 unsigned flags)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(len, PJ_EINVAL);
+
+    *len = send(sock, (const char*)buf, *len, flags);
+
+    if (*len < 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+
+/*
+ * Send data.
+ */
+PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
+				   const void *buf,
+				   pj_ssize_t *len,
+				   unsigned flags,
+				   const pj_sockaddr_t *to,
+				   int tolen)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(len, PJ_EINVAL);
+
+    *len = sendto(sock, (const char*)buf, *len, flags, 
+		  (const struct sockaddr*)to, tolen);
+
+    if (*len < 0) 
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else 
+	return PJ_SUCCESS;
+}
+
+/*
+ * Receive data.
+ */
+PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
+				 void *buf,
+				 pj_ssize_t *len,
+				 unsigned flags)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
+
+    *len = recv(sock, (char*)buf, *len, flags);
+
+    if (*len < 0) 
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Receive data.
+ */
+PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
+				     void *buf,
+				     pj_ssize_t *len,
+				     unsigned flags,
+				     pj_sockaddr_t *from,
+				     int *fromlen)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
+    PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
+
+    *len = recvfrom(sock, (char*)buf, *len, flags, 
+		    (struct sockaddr*)from, (socklen_t*)fromlen);
+
+    if (*len < 0) 
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Get socket option.
+ */
+PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
+					pj_uint16_t level,
+					pj_uint16_t optname,
+					void *optval,
+					int *optlen)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
+
+    if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Set socket option.
+ */
+PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
+					pj_uint16_t level,
+					pj_uint16_t optname,
+					const void *optval,
+					int optlen)
+{
+    PJ_CHECK_STACK();
+    if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Shutdown socket.
+ */
+#if PJ_HAS_TCP
+PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
+				      int how)
+{
+    PJ_CHECK_STACK();
+    if (shutdown(sock, how) != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Start listening to incoming connections.
+ */
+PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
+				    int backlog)
+{
+    PJ_CHECK_STACK();
+    if (listen(sock, backlog) != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Connect socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
+				     const pj_sockaddr_t *addr,
+				     int namelen)
+{
+    PJ_CHECK_STACK();
+    if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+
+/*
+ * Accept incoming connections
+ */
+PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
+				    pj_sock_t *newsock,
+				    pj_sockaddr_t *addr,
+				    int *addrlen)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
+
+    *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
+    if (*newsock==PJ_INVALID_SOCKET)
+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
+    else
+	return PJ_SUCCESS;
+}
+#endif	/* PJ_HAS_TCP */
+
+
diff --git a/pjlib/src/pj/sock_linux_kernel.c b/pjlib/src/pj/sock_linux_kernel.c
index d0778eb..27fc334 100644
--- a/pjlib/src/pj/sock_linux_kernel.c
+++ b/pjlib/src/pj/sock_linux_kernel.c
@@ -1,754 +1,754 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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() */

-

-/*

- * 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;

-}

-

-/*

- * 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.

- */

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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() */
+
+/*
+ * 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;
+}
+
+/*
+ * 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.
+ */
+
diff --git a/pjlib/src/pj/sock_select.c b/pjlib/src/pj/sock_select.c
index ba3d799..c2d0fcf 100644
--- a/pjlib/src/pj/sock_select.c
+++ b/pjlib/src/pj/sock_select.c
@@ -1,108 +1,108 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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_select.h>

-#include <pj/compat/socket.h>

-#include <pj/os.h>

-#include <pj/assert.h>

-#include <pj/errno.h>

-

-#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H!=0

-#   include <string.h>

-#endif

-

-#ifdef _MSC_VER

-#   pragma warning(disable: 4018)    // Signed/unsigned mismatch in FD_*

-#   pragma warning(disable: 4389)    // Signed/unsigned mismatch in FD_*

-#endif

-

-#define PART_FDSET(ps)		((fd_set*)&ps->data[1])

-#define PART_FDSET_OR_NULL(ps)	(ps ? PART_FDSET(ps) : NULL)

-#define PART_COUNT(ps)		(ps->data[0])

-

-PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)

-{

-    PJ_CHECK_STACK();

-    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));

-

-    FD_ZERO(PART_FDSET(fdsetp));

-    PART_COUNT(fdsetp) = 0;

-}

-

-

-PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp)

-{

-    PJ_CHECK_STACK();

-    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));

-

-    if (!PJ_FD_ISSET(fd, fdsetp))

-        ++PART_COUNT(fdsetp);

-    FD_SET(fd, PART_FDSET(fdsetp));

-}

-

-

-PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp)

-{

-    PJ_CHECK_STACK();

-    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));

-

-    if (PJ_FD_ISSET(fd, fdsetp))

-        --PART_COUNT(fdsetp);

-    FD_CLR(fd, PART_FDSET(fdsetp));

-}

-

-

-PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp)

-{

-    PJ_CHECK_STACK();

-    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),

-                     0);

-

-    return FD_ISSET(fd, PART_FDSET(fdsetp));

-}

-

-PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp)

-{

-    return PART_COUNT(fdsetp);

-}

-

-PJ_DEF(int) pj_sock_select( int n, 

-			    pj_fd_set_t *readfds, 

-			    pj_fd_set_t *writefds,

-			    pj_fd_set_t *exceptfds, 

-			    const pj_time_val *timeout)

-{

-    struct timeval os_timeout, *p_os_timeout;

-

-    PJ_CHECK_STACK();

-

-    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),

-                     PJ_EBUG);

-

-    if (timeout) {

-	os_timeout.tv_sec = timeout->sec;

-	os_timeout.tv_usec = timeout->msec * 1000;

-	p_os_timeout = &os_timeout;

-    } else {

-	p_os_timeout = NULL;

-    }

-

-    return select(n, PART_FDSET_OR_NULL(readfds), PART_FDSET_OR_NULL(writefds),

-		  PART_FDSET_OR_NULL(exceptfds), p_os_timeout);

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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_select.h>
+#include <pj/compat/socket.h>
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H!=0
+#   include <string.h>
+#endif
+
+#ifdef _MSC_VER
+#   pragma warning(disable: 4018)    // Signed/unsigned mismatch in FD_*
+#   pragma warning(disable: 4389)    // Signed/unsigned mismatch in FD_*
+#endif
+
+#define PART_FDSET(ps)		((fd_set*)&ps->data[1])
+#define PART_FDSET_OR_NULL(ps)	(ps ? PART_FDSET(ps) : NULL)
+#define PART_COUNT(ps)		(ps->data[0])
+
+PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)
+{
+    PJ_CHECK_STACK();
+    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
+
+    FD_ZERO(PART_FDSET(fdsetp));
+    PART_COUNT(fdsetp) = 0;
+}
+
+
+PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp)
+{
+    PJ_CHECK_STACK();
+    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
+
+    if (!PJ_FD_ISSET(fd, fdsetp))
+        ++PART_COUNT(fdsetp);
+    FD_SET(fd, PART_FDSET(fdsetp));
+}
+
+
+PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp)
+{
+    PJ_CHECK_STACK();
+    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
+
+    if (PJ_FD_ISSET(fd, fdsetp))
+        --PART_COUNT(fdsetp);
+    FD_CLR(fd, PART_FDSET(fdsetp));
+}
+
+
+PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp)
+{
+    PJ_CHECK_STACK();
+    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
+                     0);
+
+    return FD_ISSET(fd, PART_FDSET(fdsetp));
+}
+
+PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp)
+{
+    return PART_COUNT(fdsetp);
+}
+
+PJ_DEF(int) pj_sock_select( int n, 
+			    pj_fd_set_t *readfds, 
+			    pj_fd_set_t *writefds,
+			    pj_fd_set_t *exceptfds, 
+			    const pj_time_val *timeout)
+{
+    struct timeval os_timeout, *p_os_timeout;
+
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
+                     PJ_EBUG);
+
+    if (timeout) {
+	os_timeout.tv_sec = timeout->sec;
+	os_timeout.tv_usec = timeout->msec * 1000;
+	p_os_timeout = &os_timeout;
+    } else {
+	p_os_timeout = NULL;
+    }
+
+    return select(n, PART_FDSET_OR_NULL(readfds), PART_FDSET_OR_NULL(writefds),
+		  PART_FDSET_OR_NULL(exceptfds), p_os_timeout);
+}
+
diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c
index 5c152fb..00728f1 100644
--- a/pjlib/src/pj/string.c
+++ b/pjlib/src/pj/string.c
@@ -1,123 +1,123 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/pool.h>

-#include <pj/ctype.h>

-#include <pj/rand.h>

-#include <pj/os.h>

-

-#if PJ_FUNCTIONS_ARE_INLINED==0

-#  include <pj/string_i.h>

-#endif

-

-

-PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str )

-{

-    register char *p = str->ptr;

-    while (pj_isspace(*p))

-	++p;

-    str->slen -= (p - str->ptr);

-    str->ptr = p;

-    return str;

-}

-

-PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str )

-{

-    char *end = str->ptr + str->slen;

-    register char *p = end - 1;

-    while (p >= str->ptr && pj_isspace(*p))

-        --p;

-    str->slen -= ((end - p) - 1);

-    return str;

-}

-

-PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len)

-{

-    unsigned i;

-    char *p = str;

-

-    PJ_CHECK_STACK();

-

-    for (i=0; i<len/8; ++i) {

-	unsigned val = pj_rand();

-	pj_val_to_hex_digit( (val & 0xFF000000) >> 24, p+0 );

-	pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 );

-	pj_val_to_hex_digit( (val & 0x0000FF00) >>  8, p+4 );

-	pj_val_to_hex_digit( (val & 0x000000FF) >>  0, p+6 );

-	p += 8;

-    }

-    for (i=i * 8; i<len; ++i) {

-	*p++ = pj_hex_digits[ pj_rand() & 0x0F ];

-    }

-    return str;

-}

-

-

-PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)

-{

-    unsigned long value;

-    unsigned i;

-

-    PJ_CHECK_STACK();

-

-    value = 0;

-    for (i=0; i<(unsigned)str->slen; ++i) {

-	value = value * 10 + (str->ptr[i] - '0');

-    }

-    return value;

-}

-

-PJ_DEF(int) pj_utoa(unsigned long val, char *buf)

-{

-    return pj_utoa_pad(val, buf, 0, 0);

-}

-

-PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)

-{

-    char *p;

-    int len;

-

-    PJ_CHECK_STACK();

-

-    p = buf;

-    do {

-        unsigned long digval = (unsigned long) (val % 10);

-        val /= 10;

-        *p++ = (char) (digval + '0');

-    } while (val > 0);

-

-    len = p-buf;

-    while (len < min_dig) {

-	*p++ = (char)pad;

-	++len;

-    }

-    *p-- = '\0';

-

-    do {

-        char temp = *p;

-        *p = *buf;

-        *buf = temp;

-        --p;

-        ++buf;

-    } while (buf < p);

-

-    return len;

-}

-

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/pool.h>
+#include <pj/ctype.h>
+#include <pj/rand.h>
+#include <pj/os.h>
+
+#if PJ_FUNCTIONS_ARE_INLINED==0
+#  include <pj/string_i.h>
+#endif
+
+
+PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str )
+{
+    register char *p = str->ptr;
+    while (pj_isspace(*p))
+	++p;
+    str->slen -= (p - str->ptr);
+    str->ptr = p;
+    return str;
+}
+
+PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str )
+{
+    char *end = str->ptr + str->slen;
+    register char *p = end - 1;
+    while (p >= str->ptr && pj_isspace(*p))
+        --p;
+    str->slen -= ((end - p) - 1);
+    return str;
+}
+
+PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len)
+{
+    unsigned i;
+    char *p = str;
+
+    PJ_CHECK_STACK();
+
+    for (i=0; i<len/8; ++i) {
+	unsigned val = pj_rand();
+	pj_val_to_hex_digit( (val & 0xFF000000) >> 24, p+0 );
+	pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 );
+	pj_val_to_hex_digit( (val & 0x0000FF00) >>  8, p+4 );
+	pj_val_to_hex_digit( (val & 0x000000FF) >>  0, p+6 );
+	p += 8;
+    }
+    for (i=i * 8; i<len; ++i) {
+	*p++ = pj_hex_digits[ pj_rand() & 0x0F ];
+    }
+    return str;
+}
+
+
+PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)
+{
+    unsigned long value;
+    unsigned i;
+
+    PJ_CHECK_STACK();
+
+    value = 0;
+    for (i=0; i<(unsigned)str->slen; ++i) {
+	value = value * 10 + (str->ptr[i] - '0');
+    }
+    return value;
+}
+
+PJ_DEF(int) pj_utoa(unsigned long val, char *buf)
+{
+    return pj_utoa_pad(val, buf, 0, 0);
+}
+
+PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
+{
+    char *p;
+    int len;
+
+    PJ_CHECK_STACK();
+
+    p = buf;
+    do {
+        unsigned long digval = (unsigned long) (val % 10);
+        val /= 10;
+        *p++ = (char) (digval + '0');
+    } while (val > 0);
+
+    len = p-buf;
+    while (len < min_dig) {
+	*p++ = (char)pad;
+	++len;
+    }
+    *p-- = '\0';
+
+    do {
+        char temp = *p;
+        *p = *buf;
+        *buf = temp;
+        --p;
+        ++buf;
+    } while (buf < p);
+
+    return len;
+}
+
+
diff --git a/pjlib/src/pj/symbols.c b/pjlib/src/pj/symbols.c
index 4d2cbfb..4a78557 100644
--- a/pjlib/src/pj/symbols.c
+++ b/pjlib/src/pj/symbols.c
@@ -1,346 +1,346 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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 <pjlib.h>

-

-/*

- * addr_resolv.h

- */

-PJ_EXPORT_SYMBOL(pj_gethostbyname)

-

-/*

- * array.h

- */

-PJ_EXPORT_SYMBOL(pj_array_insert)

-PJ_EXPORT_SYMBOL(pj_array_erase)

-PJ_EXPORT_SYMBOL(pj_array_find)

-

-/*

- * config.h

- */

-PJ_EXPORT_SYMBOL(pj_dump_config)

-	

-/*

- * errno.h

- */

-PJ_EXPORT_SYMBOL(pj_get_os_error)

-PJ_EXPORT_SYMBOL(pj_set_os_error)

-PJ_EXPORT_SYMBOL(pj_get_netos_error)

-PJ_EXPORT_SYMBOL(pj_set_netos_error)

-PJ_EXPORT_SYMBOL(pj_strerror)

-

-/*

- * except.h

- */

-PJ_EXPORT_SYMBOL(pj_throw_exception_)

-PJ_EXPORT_SYMBOL(pj_push_exception_handler_)

-PJ_EXPORT_SYMBOL(pj_pop_exception_handler_)

-PJ_EXPORT_SYMBOL(pj_setjmp)

-PJ_EXPORT_SYMBOL(pj_longjmp)

-PJ_EXPORT_SYMBOL(pj_exception_id_alloc)

-PJ_EXPORT_SYMBOL(pj_exception_id_free)

-PJ_EXPORT_SYMBOL(pj_exception_id_name)

-

-

-/*

- * fifobuf.h

- */

-PJ_EXPORT_SYMBOL(pj_fifobuf_init)

-PJ_EXPORT_SYMBOL(pj_fifobuf_max_size)

-PJ_EXPORT_SYMBOL(pj_fifobuf_alloc)

-PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc)

-PJ_EXPORT_SYMBOL(pj_fifobuf_free)

-

-/*

- * guid.h

- */

-PJ_EXPORT_SYMBOL(pj_generate_unique_string)

-PJ_EXPORT_SYMBOL(pj_create_unique_string)

-

-/*

- * hash.h

- */

-PJ_EXPORT_SYMBOL(pj_hash_calc)

-PJ_EXPORT_SYMBOL(pj_hash_create)

-PJ_EXPORT_SYMBOL(pj_hash_get)

-PJ_EXPORT_SYMBOL(pj_hash_set)

-PJ_EXPORT_SYMBOL(pj_hash_count)

-PJ_EXPORT_SYMBOL(pj_hash_first)

-PJ_EXPORT_SYMBOL(pj_hash_next)

-PJ_EXPORT_SYMBOL(pj_hash_this)

-

-/*

- * ioqueue.h

- */

-PJ_EXPORT_SYMBOL(pj_ioqueue_create)

-PJ_EXPORT_SYMBOL(pj_ioqueue_destroy)

-PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock)

-PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock)

-PJ_EXPORT_SYMBOL(pj_ioqueue_unregister)

-PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data)

-PJ_EXPORT_SYMBOL(pj_ioqueue_poll)

-PJ_EXPORT_SYMBOL(pj_ioqueue_read)

-PJ_EXPORT_SYMBOL(pj_ioqueue_recv)

-PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom)

-PJ_EXPORT_SYMBOL(pj_ioqueue_write)

-PJ_EXPORT_SYMBOL(pj_ioqueue_send)

-PJ_EXPORT_SYMBOL(pj_ioqueue_sendto)

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-PJ_EXPORT_SYMBOL(pj_ioqueue_accept)

-PJ_EXPORT_SYMBOL(pj_ioqueue_connect)

-#endif

-

-/*

- * list.h

- */

-PJ_EXPORT_SYMBOL(pj_list_insert_before)

-PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before)

-PJ_EXPORT_SYMBOL(pj_list_insert_after)

-PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after)

-PJ_EXPORT_SYMBOL(pj_list_merge_first)

-PJ_EXPORT_SYMBOL(pj_list_merge_last)

-PJ_EXPORT_SYMBOL(pj_list_erase)

-PJ_EXPORT_SYMBOL(pj_list_find_node)

-PJ_EXPORT_SYMBOL(pj_list_search)

-

-

-/*

- * log.h

- */

-PJ_EXPORT_SYMBOL(pj_log_write)

-#if PJ_LOG_MAX_LEVEL >= 1

-PJ_EXPORT_SYMBOL(pj_log_set_log_func)

-PJ_EXPORT_SYMBOL(pj_log_get_log_func)

-PJ_EXPORT_SYMBOL(pj_log_set_level)

-PJ_EXPORT_SYMBOL(pj_log_get_level)

-PJ_EXPORT_SYMBOL(pj_log_set_decor)

-PJ_EXPORT_SYMBOL(pj_log_get_decor)

-PJ_EXPORT_SYMBOL(pj_log_1)

-#endif

-#if PJ_LOG_MAX_LEVEL >= 2

-PJ_EXPORT_SYMBOL(pj_log_2)

-#endif

-#if PJ_LOG_MAX_LEVEL >= 3

-PJ_EXPORT_SYMBOL(pj_log_3)

-#endif

-#if PJ_LOG_MAX_LEVEL >= 4

-PJ_EXPORT_SYMBOL(pj_log_4)

-#endif

-#if PJ_LOG_MAX_LEVEL >= 5

-PJ_EXPORT_SYMBOL(pj_log_5)

-#endif

-#if PJ_LOG_MAX_LEVEL >= 6

-PJ_EXPORT_SYMBOL(pj_log_6)

-#endif

-

-/*

- * os.h

- */

-PJ_EXPORT_SYMBOL(pj_init)

-PJ_EXPORT_SYMBOL(pj_getpid)

-PJ_EXPORT_SYMBOL(pj_thread_register)

-PJ_EXPORT_SYMBOL(pj_thread_create)

-PJ_EXPORT_SYMBOL(pj_thread_get_name)

-PJ_EXPORT_SYMBOL(pj_thread_resume)

-PJ_EXPORT_SYMBOL(pj_thread_this)

-PJ_EXPORT_SYMBOL(pj_thread_join)

-PJ_EXPORT_SYMBOL(pj_thread_destroy)

-PJ_EXPORT_SYMBOL(pj_thread_sleep)

-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0

-PJ_EXPORT_SYMBOL(pj_thread_check_stack)

-PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage)

-PJ_EXPORT_SYMBOL(pj_thread_get_stack_info)

-#endif

-PJ_EXPORT_SYMBOL(pj_atomic_create)

-PJ_EXPORT_SYMBOL(pj_atomic_destroy)

-PJ_EXPORT_SYMBOL(pj_atomic_set)

-PJ_EXPORT_SYMBOL(pj_atomic_get)

-PJ_EXPORT_SYMBOL(pj_atomic_inc)

-PJ_EXPORT_SYMBOL(pj_atomic_dec)

-PJ_EXPORT_SYMBOL(pj_thread_local_alloc)

-PJ_EXPORT_SYMBOL(pj_thread_local_free)

-PJ_EXPORT_SYMBOL(pj_thread_local_set)

-PJ_EXPORT_SYMBOL(pj_thread_local_get)

-PJ_EXPORT_SYMBOL(pj_enter_critical_section)

-PJ_EXPORT_SYMBOL(pj_leave_critical_section)

-PJ_EXPORT_SYMBOL(pj_mutex_create)

-PJ_EXPORT_SYMBOL(pj_mutex_lock)

-PJ_EXPORT_SYMBOL(pj_mutex_unlock)

-PJ_EXPORT_SYMBOL(pj_mutex_trylock)

-PJ_EXPORT_SYMBOL(pj_mutex_destroy)

-#if defined(PJ_DEBUG) && PJ_DEBUG != 0

-PJ_EXPORT_SYMBOL(pj_mutex_is_locked)

-#endif

-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

-PJ_EXPORT_SYMBOL(pj_sem_create)

-PJ_EXPORT_SYMBOL(pj_sem_wait)

-PJ_EXPORT_SYMBOL(pj_sem_trywait)

-PJ_EXPORT_SYMBOL(pj_sem_post)

-PJ_EXPORT_SYMBOL(pj_sem_destroy)

-#endif

-PJ_EXPORT_SYMBOL(pj_gettimeofday)

-PJ_EXPORT_SYMBOL(pj_time_decode)

-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

-PJ_EXPORT_SYMBOL(pj_get_timestamp)

-PJ_EXPORT_SYMBOL(pj_get_timestamp_freq)

-PJ_EXPORT_SYMBOL(pj_elapsed_time)

-PJ_EXPORT_SYMBOL(pj_elapsed_usec)

-PJ_EXPORT_SYMBOL(pj_elapsed_nanosec)

-PJ_EXPORT_SYMBOL(pj_elapsed_cycle)

-#endif

-

-	

-/*

- * pool.h

- */

-PJ_EXPORT_SYMBOL(pj_pool_create)

-PJ_EXPORT_SYMBOL(pj_pool_release)

-PJ_EXPORT_SYMBOL(pj_pool_getobjname)

-PJ_EXPORT_SYMBOL(pj_pool_reset)

-PJ_EXPORT_SYMBOL(pj_pool_get_capacity)

-PJ_EXPORT_SYMBOL(pj_pool_get_used_size)

-PJ_EXPORT_SYMBOL(pj_pool_alloc)

-PJ_EXPORT_SYMBOL(pj_pool_calloc)

-PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy)

-PJ_EXPORT_SYMBOL(pj_pool_create_int)

-PJ_EXPORT_SYMBOL(pj_pool_init_int)

-PJ_EXPORT_SYMBOL(pj_pool_destroy_int)

-PJ_EXPORT_SYMBOL(pj_caching_pool_init)

-PJ_EXPORT_SYMBOL(pj_caching_pool_destroy)

-

-/*

- * rand.h

- */

-PJ_EXPORT_SYMBOL(pj_rand)

-PJ_EXPORT_SYMBOL(pj_srand)

-

-/*

- * rbtree.h

- */

-PJ_EXPORT_SYMBOL(pj_rbtree_init)

-PJ_EXPORT_SYMBOL(pj_rbtree_first)

-PJ_EXPORT_SYMBOL(pj_rbtree_last)

-PJ_EXPORT_SYMBOL(pj_rbtree_next)

-PJ_EXPORT_SYMBOL(pj_rbtree_prev)

-PJ_EXPORT_SYMBOL(pj_rbtree_insert)

-PJ_EXPORT_SYMBOL(pj_rbtree_find)

-PJ_EXPORT_SYMBOL(pj_rbtree_erase)

-PJ_EXPORT_SYMBOL(pj_rbtree_max_height)

-PJ_EXPORT_SYMBOL(pj_rbtree_min_height)

-

-/*

- * sock.h

- */

-PJ_EXPORT_SYMBOL(PJ_AF_UNIX)

-PJ_EXPORT_SYMBOL(PJ_AF_INET)

-PJ_EXPORT_SYMBOL(PJ_AF_INET6)

-PJ_EXPORT_SYMBOL(PJ_AF_PACKET)

-PJ_EXPORT_SYMBOL(PJ_AF_IRDA)

-PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM)

-PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM)

-PJ_EXPORT_SYMBOL(PJ_SOCK_RAW)

-PJ_EXPORT_SYMBOL(PJ_SOCK_RDM)

-PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET)

-PJ_EXPORT_SYMBOL(PJ_SOL_IP)

-PJ_EXPORT_SYMBOL(PJ_SOL_TCP)

-PJ_EXPORT_SYMBOL(PJ_SOL_UDP)

-PJ_EXPORT_SYMBOL(PJ_SOL_IPV6)

-PJ_EXPORT_SYMBOL(pj_ntohs)

-PJ_EXPORT_SYMBOL(pj_htons)

-PJ_EXPORT_SYMBOL(pj_ntohl)

-PJ_EXPORT_SYMBOL(pj_htonl)

-PJ_EXPORT_SYMBOL(pj_inet_ntoa)

-PJ_EXPORT_SYMBOL(pj_inet_aton)

-PJ_EXPORT_SYMBOL(pj_inet_addr)

-PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr)

-PJ_EXPORT_SYMBOL(pj_sockaddr_in_init)

-PJ_EXPORT_SYMBOL(pj_gethostname)

-PJ_EXPORT_SYMBOL(pj_gethostaddr)

-PJ_EXPORT_SYMBOL(pj_sock_socket)

-PJ_EXPORT_SYMBOL(pj_sock_close)

-PJ_EXPORT_SYMBOL(pj_sock_bind)

-PJ_EXPORT_SYMBOL(pj_sock_bind_in)

-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

-PJ_EXPORT_SYMBOL(pj_sock_listen)

-PJ_EXPORT_SYMBOL(pj_sock_accept)

-PJ_EXPORT_SYMBOL(pj_sock_shutdown)

-#endif

-PJ_EXPORT_SYMBOL(pj_sock_connect)

-PJ_EXPORT_SYMBOL(pj_sock_getpeername)

-PJ_EXPORT_SYMBOL(pj_sock_getsockname)

-PJ_EXPORT_SYMBOL(pj_sock_getsockopt)

-PJ_EXPORT_SYMBOL(pj_sock_setsockopt)

-PJ_EXPORT_SYMBOL(pj_sock_recv)

-PJ_EXPORT_SYMBOL(pj_sock_recvfrom)

-PJ_EXPORT_SYMBOL(pj_sock_send)

-PJ_EXPORT_SYMBOL(pj_sock_sendto)

-

-/*

- * sock_select.h

- */

-PJ_EXPORT_SYMBOL(PJ_FD_ZERO)

-PJ_EXPORT_SYMBOL(PJ_FD_SET)

-PJ_EXPORT_SYMBOL(PJ_FD_CLR)

-PJ_EXPORT_SYMBOL(PJ_FD_ISSET)

-PJ_EXPORT_SYMBOL(pj_sock_select)

-

-/*

- * string.h

- */

-PJ_EXPORT_SYMBOL(pj_str)

-PJ_EXPORT_SYMBOL(pj_strassign)

-PJ_EXPORT_SYMBOL(pj_strcpy)

-PJ_EXPORT_SYMBOL(pj_strcpy2)

-PJ_EXPORT_SYMBOL(pj_strdup)

-PJ_EXPORT_SYMBOL(pj_strdup_with_null)

-PJ_EXPORT_SYMBOL(pj_strdup2)

-PJ_EXPORT_SYMBOL(pj_strdup3)

-PJ_EXPORT_SYMBOL(pj_strcmp)

-PJ_EXPORT_SYMBOL(pj_strcmp2)

-PJ_EXPORT_SYMBOL(pj_strncmp)

-PJ_EXPORT_SYMBOL(pj_strncmp2)

-PJ_EXPORT_SYMBOL(pj_stricmp)

-PJ_EXPORT_SYMBOL(pj_stricmp2)

-PJ_EXPORT_SYMBOL(pj_strnicmp)

-PJ_EXPORT_SYMBOL(pj_strnicmp2)

-PJ_EXPORT_SYMBOL(pj_strcat)

-PJ_EXPORT_SYMBOL(pj_strltrim)

-PJ_EXPORT_SYMBOL(pj_strrtrim)

-PJ_EXPORT_SYMBOL(pj_strtrim)

-PJ_EXPORT_SYMBOL(pj_create_random_string)

-PJ_EXPORT_SYMBOL(pj_strtoul)

-PJ_EXPORT_SYMBOL(pj_utoa)

-PJ_EXPORT_SYMBOL(pj_utoa_pad)

-

-/*

- * timer.h

- */

-PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size)

-PJ_EXPORT_SYMBOL(pj_timer_heap_create)

-PJ_EXPORT_SYMBOL(pj_timer_entry_init)

-PJ_EXPORT_SYMBOL(pj_timer_heap_schedule)

-PJ_EXPORT_SYMBOL(pj_timer_heap_cancel)

-PJ_EXPORT_SYMBOL(pj_timer_heap_count)

-PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time)

-PJ_EXPORT_SYMBOL(pj_timer_heap_poll)

-

-/*

- * types.h

- */

-PJ_EXPORT_SYMBOL(pj_time_val_normalize)

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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 <pjlib.h>
+
+/*
+ * addr_resolv.h
+ */
+PJ_EXPORT_SYMBOL(pj_gethostbyname)
+
+/*
+ * array.h
+ */
+PJ_EXPORT_SYMBOL(pj_array_insert)
+PJ_EXPORT_SYMBOL(pj_array_erase)
+PJ_EXPORT_SYMBOL(pj_array_find)
+
+/*
+ * config.h
+ */
+PJ_EXPORT_SYMBOL(pj_dump_config)
+	
+/*
+ * errno.h
+ */
+PJ_EXPORT_SYMBOL(pj_get_os_error)
+PJ_EXPORT_SYMBOL(pj_set_os_error)
+PJ_EXPORT_SYMBOL(pj_get_netos_error)
+PJ_EXPORT_SYMBOL(pj_set_netos_error)
+PJ_EXPORT_SYMBOL(pj_strerror)
+
+/*
+ * except.h
+ */
+PJ_EXPORT_SYMBOL(pj_throw_exception_)
+PJ_EXPORT_SYMBOL(pj_push_exception_handler_)
+PJ_EXPORT_SYMBOL(pj_pop_exception_handler_)
+PJ_EXPORT_SYMBOL(pj_setjmp)
+PJ_EXPORT_SYMBOL(pj_longjmp)
+PJ_EXPORT_SYMBOL(pj_exception_id_alloc)
+PJ_EXPORT_SYMBOL(pj_exception_id_free)
+PJ_EXPORT_SYMBOL(pj_exception_id_name)
+
+
+/*
+ * fifobuf.h
+ */
+PJ_EXPORT_SYMBOL(pj_fifobuf_init)
+PJ_EXPORT_SYMBOL(pj_fifobuf_max_size)
+PJ_EXPORT_SYMBOL(pj_fifobuf_alloc)
+PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc)
+PJ_EXPORT_SYMBOL(pj_fifobuf_free)
+
+/*
+ * guid.h
+ */
+PJ_EXPORT_SYMBOL(pj_generate_unique_string)
+PJ_EXPORT_SYMBOL(pj_create_unique_string)
+
+/*
+ * hash.h
+ */
+PJ_EXPORT_SYMBOL(pj_hash_calc)
+PJ_EXPORT_SYMBOL(pj_hash_create)
+PJ_EXPORT_SYMBOL(pj_hash_get)
+PJ_EXPORT_SYMBOL(pj_hash_set)
+PJ_EXPORT_SYMBOL(pj_hash_count)
+PJ_EXPORT_SYMBOL(pj_hash_first)
+PJ_EXPORT_SYMBOL(pj_hash_next)
+PJ_EXPORT_SYMBOL(pj_hash_this)
+
+/*
+ * ioqueue.h
+ */
+PJ_EXPORT_SYMBOL(pj_ioqueue_create)
+PJ_EXPORT_SYMBOL(pj_ioqueue_destroy)
+PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock)
+PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock)
+PJ_EXPORT_SYMBOL(pj_ioqueue_unregister)
+PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data)
+PJ_EXPORT_SYMBOL(pj_ioqueue_poll)
+PJ_EXPORT_SYMBOL(pj_ioqueue_read)
+PJ_EXPORT_SYMBOL(pj_ioqueue_recv)
+PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom)
+PJ_EXPORT_SYMBOL(pj_ioqueue_write)
+PJ_EXPORT_SYMBOL(pj_ioqueue_send)
+PJ_EXPORT_SYMBOL(pj_ioqueue_sendto)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+PJ_EXPORT_SYMBOL(pj_ioqueue_accept)
+PJ_EXPORT_SYMBOL(pj_ioqueue_connect)
+#endif
+
+/*
+ * list.h
+ */
+PJ_EXPORT_SYMBOL(pj_list_insert_before)
+PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before)
+PJ_EXPORT_SYMBOL(pj_list_insert_after)
+PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after)
+PJ_EXPORT_SYMBOL(pj_list_merge_first)
+PJ_EXPORT_SYMBOL(pj_list_merge_last)
+PJ_EXPORT_SYMBOL(pj_list_erase)
+PJ_EXPORT_SYMBOL(pj_list_find_node)
+PJ_EXPORT_SYMBOL(pj_list_search)
+
+
+/*
+ * log.h
+ */
+PJ_EXPORT_SYMBOL(pj_log_write)
+#if PJ_LOG_MAX_LEVEL >= 1
+PJ_EXPORT_SYMBOL(pj_log_set_log_func)
+PJ_EXPORT_SYMBOL(pj_log_get_log_func)
+PJ_EXPORT_SYMBOL(pj_log_set_level)
+PJ_EXPORT_SYMBOL(pj_log_get_level)
+PJ_EXPORT_SYMBOL(pj_log_set_decor)
+PJ_EXPORT_SYMBOL(pj_log_get_decor)
+PJ_EXPORT_SYMBOL(pj_log_1)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 2
+PJ_EXPORT_SYMBOL(pj_log_2)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 3
+PJ_EXPORT_SYMBOL(pj_log_3)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 4
+PJ_EXPORT_SYMBOL(pj_log_4)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 5
+PJ_EXPORT_SYMBOL(pj_log_5)
+#endif
+#if PJ_LOG_MAX_LEVEL >= 6
+PJ_EXPORT_SYMBOL(pj_log_6)
+#endif
+
+/*
+ * os.h
+ */
+PJ_EXPORT_SYMBOL(pj_init)
+PJ_EXPORT_SYMBOL(pj_getpid)
+PJ_EXPORT_SYMBOL(pj_thread_register)
+PJ_EXPORT_SYMBOL(pj_thread_create)
+PJ_EXPORT_SYMBOL(pj_thread_get_name)
+PJ_EXPORT_SYMBOL(pj_thread_resume)
+PJ_EXPORT_SYMBOL(pj_thread_this)
+PJ_EXPORT_SYMBOL(pj_thread_join)
+PJ_EXPORT_SYMBOL(pj_thread_destroy)
+PJ_EXPORT_SYMBOL(pj_thread_sleep)
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
+PJ_EXPORT_SYMBOL(pj_thread_check_stack)
+PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage)
+PJ_EXPORT_SYMBOL(pj_thread_get_stack_info)
+#endif
+PJ_EXPORT_SYMBOL(pj_atomic_create)
+PJ_EXPORT_SYMBOL(pj_atomic_destroy)
+PJ_EXPORT_SYMBOL(pj_atomic_set)
+PJ_EXPORT_SYMBOL(pj_atomic_get)
+PJ_EXPORT_SYMBOL(pj_atomic_inc)
+PJ_EXPORT_SYMBOL(pj_atomic_dec)
+PJ_EXPORT_SYMBOL(pj_thread_local_alloc)
+PJ_EXPORT_SYMBOL(pj_thread_local_free)
+PJ_EXPORT_SYMBOL(pj_thread_local_set)
+PJ_EXPORT_SYMBOL(pj_thread_local_get)
+PJ_EXPORT_SYMBOL(pj_enter_critical_section)
+PJ_EXPORT_SYMBOL(pj_leave_critical_section)
+PJ_EXPORT_SYMBOL(pj_mutex_create)
+PJ_EXPORT_SYMBOL(pj_mutex_lock)
+PJ_EXPORT_SYMBOL(pj_mutex_unlock)
+PJ_EXPORT_SYMBOL(pj_mutex_trylock)
+PJ_EXPORT_SYMBOL(pj_mutex_destroy)
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+PJ_EXPORT_SYMBOL(pj_mutex_is_locked)
+#endif
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+PJ_EXPORT_SYMBOL(pj_sem_create)
+PJ_EXPORT_SYMBOL(pj_sem_wait)
+PJ_EXPORT_SYMBOL(pj_sem_trywait)
+PJ_EXPORT_SYMBOL(pj_sem_post)
+PJ_EXPORT_SYMBOL(pj_sem_destroy)
+#endif
+PJ_EXPORT_SYMBOL(pj_gettimeofday)
+PJ_EXPORT_SYMBOL(pj_time_decode)
+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
+PJ_EXPORT_SYMBOL(pj_get_timestamp)
+PJ_EXPORT_SYMBOL(pj_get_timestamp_freq)
+PJ_EXPORT_SYMBOL(pj_elapsed_time)
+PJ_EXPORT_SYMBOL(pj_elapsed_usec)
+PJ_EXPORT_SYMBOL(pj_elapsed_nanosec)
+PJ_EXPORT_SYMBOL(pj_elapsed_cycle)
+#endif
+
+	
+/*
+ * pool.h
+ */
+PJ_EXPORT_SYMBOL(pj_pool_create)
+PJ_EXPORT_SYMBOL(pj_pool_release)
+PJ_EXPORT_SYMBOL(pj_pool_getobjname)
+PJ_EXPORT_SYMBOL(pj_pool_reset)
+PJ_EXPORT_SYMBOL(pj_pool_get_capacity)
+PJ_EXPORT_SYMBOL(pj_pool_get_used_size)
+PJ_EXPORT_SYMBOL(pj_pool_alloc)
+PJ_EXPORT_SYMBOL(pj_pool_calloc)
+PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy)
+PJ_EXPORT_SYMBOL(pj_pool_create_int)
+PJ_EXPORT_SYMBOL(pj_pool_init_int)
+PJ_EXPORT_SYMBOL(pj_pool_destroy_int)
+PJ_EXPORT_SYMBOL(pj_caching_pool_init)
+PJ_EXPORT_SYMBOL(pj_caching_pool_destroy)
+
+/*
+ * rand.h
+ */
+PJ_EXPORT_SYMBOL(pj_rand)
+PJ_EXPORT_SYMBOL(pj_srand)
+
+/*
+ * rbtree.h
+ */
+PJ_EXPORT_SYMBOL(pj_rbtree_init)
+PJ_EXPORT_SYMBOL(pj_rbtree_first)
+PJ_EXPORT_SYMBOL(pj_rbtree_last)
+PJ_EXPORT_SYMBOL(pj_rbtree_next)
+PJ_EXPORT_SYMBOL(pj_rbtree_prev)
+PJ_EXPORT_SYMBOL(pj_rbtree_insert)
+PJ_EXPORT_SYMBOL(pj_rbtree_find)
+PJ_EXPORT_SYMBOL(pj_rbtree_erase)
+PJ_EXPORT_SYMBOL(pj_rbtree_max_height)
+PJ_EXPORT_SYMBOL(pj_rbtree_min_height)
+
+/*
+ * sock.h
+ */
+PJ_EXPORT_SYMBOL(PJ_AF_UNIX)
+PJ_EXPORT_SYMBOL(PJ_AF_INET)
+PJ_EXPORT_SYMBOL(PJ_AF_INET6)
+PJ_EXPORT_SYMBOL(PJ_AF_PACKET)
+PJ_EXPORT_SYMBOL(PJ_AF_IRDA)
+PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM)
+PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM)
+PJ_EXPORT_SYMBOL(PJ_SOCK_RAW)
+PJ_EXPORT_SYMBOL(PJ_SOCK_RDM)
+PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET)
+PJ_EXPORT_SYMBOL(PJ_SOL_IP)
+PJ_EXPORT_SYMBOL(PJ_SOL_TCP)
+PJ_EXPORT_SYMBOL(PJ_SOL_UDP)
+PJ_EXPORT_SYMBOL(PJ_SOL_IPV6)
+PJ_EXPORT_SYMBOL(pj_ntohs)
+PJ_EXPORT_SYMBOL(pj_htons)
+PJ_EXPORT_SYMBOL(pj_ntohl)
+PJ_EXPORT_SYMBOL(pj_htonl)
+PJ_EXPORT_SYMBOL(pj_inet_ntoa)
+PJ_EXPORT_SYMBOL(pj_inet_aton)
+PJ_EXPORT_SYMBOL(pj_inet_addr)
+PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr)
+PJ_EXPORT_SYMBOL(pj_sockaddr_in_init)
+PJ_EXPORT_SYMBOL(pj_gethostname)
+PJ_EXPORT_SYMBOL(pj_gethostaddr)
+PJ_EXPORT_SYMBOL(pj_sock_socket)
+PJ_EXPORT_SYMBOL(pj_sock_close)
+PJ_EXPORT_SYMBOL(pj_sock_bind)
+PJ_EXPORT_SYMBOL(pj_sock_bind_in)
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+PJ_EXPORT_SYMBOL(pj_sock_listen)
+PJ_EXPORT_SYMBOL(pj_sock_accept)
+PJ_EXPORT_SYMBOL(pj_sock_shutdown)
+#endif
+PJ_EXPORT_SYMBOL(pj_sock_connect)
+PJ_EXPORT_SYMBOL(pj_sock_getpeername)
+PJ_EXPORT_SYMBOL(pj_sock_getsockname)
+PJ_EXPORT_SYMBOL(pj_sock_getsockopt)
+PJ_EXPORT_SYMBOL(pj_sock_setsockopt)
+PJ_EXPORT_SYMBOL(pj_sock_recv)
+PJ_EXPORT_SYMBOL(pj_sock_recvfrom)
+PJ_EXPORT_SYMBOL(pj_sock_send)
+PJ_EXPORT_SYMBOL(pj_sock_sendto)
+
+/*
+ * sock_select.h
+ */
+PJ_EXPORT_SYMBOL(PJ_FD_ZERO)
+PJ_EXPORT_SYMBOL(PJ_FD_SET)
+PJ_EXPORT_SYMBOL(PJ_FD_CLR)
+PJ_EXPORT_SYMBOL(PJ_FD_ISSET)
+PJ_EXPORT_SYMBOL(pj_sock_select)
+
+/*
+ * string.h
+ */
+PJ_EXPORT_SYMBOL(pj_str)
+PJ_EXPORT_SYMBOL(pj_strassign)
+PJ_EXPORT_SYMBOL(pj_strcpy)
+PJ_EXPORT_SYMBOL(pj_strcpy2)
+PJ_EXPORT_SYMBOL(pj_strdup)
+PJ_EXPORT_SYMBOL(pj_strdup_with_null)
+PJ_EXPORT_SYMBOL(pj_strdup2)
+PJ_EXPORT_SYMBOL(pj_strdup3)
+PJ_EXPORT_SYMBOL(pj_strcmp)
+PJ_EXPORT_SYMBOL(pj_strcmp2)
+PJ_EXPORT_SYMBOL(pj_strncmp)
+PJ_EXPORT_SYMBOL(pj_strncmp2)
+PJ_EXPORT_SYMBOL(pj_stricmp)
+PJ_EXPORT_SYMBOL(pj_stricmp2)
+PJ_EXPORT_SYMBOL(pj_strnicmp)
+PJ_EXPORT_SYMBOL(pj_strnicmp2)
+PJ_EXPORT_SYMBOL(pj_strcat)
+PJ_EXPORT_SYMBOL(pj_strltrim)
+PJ_EXPORT_SYMBOL(pj_strrtrim)
+PJ_EXPORT_SYMBOL(pj_strtrim)
+PJ_EXPORT_SYMBOL(pj_create_random_string)
+PJ_EXPORT_SYMBOL(pj_strtoul)
+PJ_EXPORT_SYMBOL(pj_utoa)
+PJ_EXPORT_SYMBOL(pj_utoa_pad)
+
+/*
+ * timer.h
+ */
+PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size)
+PJ_EXPORT_SYMBOL(pj_timer_heap_create)
+PJ_EXPORT_SYMBOL(pj_timer_entry_init)
+PJ_EXPORT_SYMBOL(pj_timer_heap_schedule)
+PJ_EXPORT_SYMBOL(pj_timer_heap_cancel)
+PJ_EXPORT_SYMBOL(pj_timer_heap_count)
+PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time)
+PJ_EXPORT_SYMBOL(pj_timer_heap_poll)
+
+/*
+ * types.h
+ */
+PJ_EXPORT_SYMBOL(pj_time_val_normalize)
+
diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c
index dfcccbf..212f04a 100644
--- a/pjlib/src/pj/timer.c
+++ b/pjlib/src/pj/timer.c
@@ -1,531 +1,531 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/timer.h>

-#include <pj/pool.h>

-#include <pj/os.h>

-#include <pj/string.h>

-#include <pj/assert.h>

-#include <pj/errno.h>

-#include <pj/lock.h>

-

-#define HEAP_PARENT(X)	(X == 0 ? 0 : (((X) - 1) / 2))

-#define HEAP_LEFT(X)	(((X)+(X))+1)

-

-

-#define DEFAULT_MAX_TIMED_OUT_PER_POLL  (64)

-

-

-/**

- * The implementation of timer heap.

- */

-struct pj_timer_heap_t

-{

-    /** Pool from which the timer heap resize will get the storage from */

-    pj_pool_t *pool;

-

-    /** Maximum size of the heap. */

-    pj_size_t max_size;

-

-    /** Current size of the heap. */

-    pj_size_t cur_size;

-

-    /** Max timed out entries to process per poll. */

-    unsigned max_entries_per_poll;

-

-    /** Lock object. */

-    pj_lock_t *lock;

-

-    /** Autodelete lock. */

-    pj_bool_t auto_delete_lock;

-

-    /**

-     * Current contents of the Heap, which is organized as a "heap" of

-     * pj_timer_entry *'s.  In this context, a heap is a "partially

-     * ordered, almost complete" binary tree, which is stored in an

-     * array.

-     */

-    pj_timer_entry **heap;

-

-    /**

-     * An array of "pointers" that allows each pj_timer_entry in the

-     * <heap_> to be located in O(1) time.  Basically, <timer_id_[i]>

-     * contains the slot in the <heap_> array where an pj_timer_entry

-     * with timer id <i> resides.  Thus, the timer id passed back from

-     * <schedule_entry> is really an slot into the <timer_ids> array.  The

-     * <timer_ids_> array serves two purposes: negative values are

-     * treated as "pointers" for the <freelist_>, whereas positive

-     * values are treated as "pointers" into the <heap_> array.

-     */

-    pj_timer_id_t *timer_ids;

-

-    /**

-     * "Pointer" to the first element in the freelist contained within

-     * the <timer_ids_> array, which is organized as a stack.

-     */

-    pj_timer_id_t timer_ids_freelist;

-

-    /** Callback to be called when a timer expires. */

-    pj_timer_heap_callback *callback;

-

-};

-

-

-

-PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht )

-{

-    if (ht->lock) {

-	pj_lock_acquire(ht->lock);

-    }

-}

-

-PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht )

-{

-    if (ht->lock) {

-	pj_lock_release(ht->lock);

-    }

-}

-

-

-static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node )

-{

-    PJ_CHECK_STACK();

-

-    // Insert <moved_node> into its new location in the heap.

-    ht->heap[slot] = moved_node;

-    

-    // Update the corresponding slot in the parallel <timer_ids_> array.

-    ht->timer_ids[moved_node->_timer_id] = slot;

-}

-

-static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht )

-{

-    // We need to truncate this to <int> for backwards compatibility.

-    pj_timer_id_t new_id = ht->timer_ids_freelist;

-    

-    PJ_CHECK_STACK();

-

-    // The freelist values in the <timer_ids_> are negative, so we need

-    // to negate them to get the next freelist "pointer."

-    ht->timer_ids_freelist =

-	-ht->timer_ids[ht->timer_ids_freelist];

-    

-    return new_id;

-    

-}

-

-static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id)

-{

-    PJ_CHECK_STACK();

-

-    // The freelist values in the <timer_ids_> are negative, so we need

-    // to negate them to get the next freelist "pointer."

-    ht->timer_ids[old_id] = -ht->timer_ids_freelist;

-    ht->timer_ids_freelist = old_id;

-}

-

-

-static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node,

-                        size_t slot, size_t child)

-{

-    PJ_CHECK_STACK();

-

-    // Restore the heap property after a deletion.

-    

-    while (child < ht->cur_size)

-    {

-	// Choose the smaller of the two children.

-	if (child + 1 < ht->cur_size

-	    && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value))

-	    child++;

-	

-	// Perform a <copy> if the child has a larger timeout value than

-	// the <moved_node>.

-	if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value))

-        {

-	    copy_node( ht, slot, ht->heap[child]);

-	    slot = child;

-	    child = HEAP_LEFT(child);

-        }

-	else

-	    // We've found our location in the heap.

-	    break;

-    }

-    

-    copy_node( ht, slot, moved_node);

-}

-

-static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node,

-		       size_t slot, size_t parent)

-{

-    // Restore the heap property after an insertion.

-    

-    while (slot > 0)

-    {

-	// If the parent node is greater than the <moved_node> we need

-	// to copy it down.

-	if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value))

-        {

-	    copy_node(ht, slot, ht->heap[parent]);

-	    slot = parent;

-	    parent = HEAP_PARENT(slot);

-        }

-	else

-	    break;

-    }

-    

-    // Insert the new node into its proper resting place in the heap and

-    // update the corresponding slot in the parallel <timer_ids> array.

-    copy_node(ht, slot, moved_node);

-}

-

-

-static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot)

-{

-    pj_timer_entry *removed_node = ht->heap[slot];

-    

-    // Return this timer id to the freelist.

-    push_freelist( ht, removed_node->_timer_id );

-    

-    // Decrement the size of the heap by one since we're removing the

-    // "slot"th node.

-    ht->cur_size--;

-    

-    // Set the ID

-    removed_node->_timer_id = -1;

-

-    // Only try to reheapify if we're not deleting the last entry.

-    

-    if (slot < ht->cur_size)

-    {

-	int parent;

-	pj_timer_entry *moved_node = ht->heap[ht->cur_size];

-	

-	// Move the end node to the location being removed and update

-	// the corresponding slot in the parallel <timer_ids> array.

-	copy_node( ht, slot, moved_node);

-	

-	// If the <moved_node->time_value_> is great than or equal its

-	// parent it needs be moved down the heap.

-	parent = HEAP_PARENT (slot);

-	

-	if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value))

-	    reheap_down( ht, moved_node, slot, HEAP_LEFT(slot));

-	else

-	    reheap_up( ht, moved_node, slot, parent);

-    }

-    

-    return removed_node;

-}

-

-static void grow_heap(pj_timer_heap_t *ht)

-{

-    // All the containers will double in size from max_size_

-    size_t new_size = ht->max_size * 2;

-    pj_timer_id_t *new_timer_ids;

-    pj_size_t i;

-    

-    // First grow the heap itself.

-    

-    pj_timer_entry **new_heap = 0;

-    

-    new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size);

-    memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*));

-    //delete [] this->heap_;

-    ht->heap = new_heap;

-    

-    // Grow the array of timer ids.

-    

-    new_timer_ids = 0;

-    new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t));

-    

-    memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t));

-    

-    //delete [] timer_ids_;

-    ht->timer_ids = new_timer_ids;

-    

-    // And add the new elements to the end of the "freelist".

-    for (i = ht->max_size; i < new_size; i++)

-	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));

-    

-    ht->max_size = new_size;

-}

-

-static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node)

-{

-    if (ht->cur_size + 2 >= ht->max_size)

-	grow_heap(ht);

-    

-    reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size));

-    ht->cur_size++;

-}

-

-

-static pj_status_t schedule_entry( pj_timer_heap_t *ht,

-				   pj_timer_entry *entry, 

-				   const pj_time_val *future_time )

-{

-    if (ht->cur_size < ht->max_size)

-    {

-	// Obtain the next unique sequence number.

-	// Set the entry

-	entry->_timer_id = pop_freelist(ht);

-	entry->_timer_value = *future_time;

-	insert_node( ht, entry);

-	return 0;

-    }

-    else

-	return -1;

-}

-

-

-static int cancel( pj_timer_heap_t *ht, 

-		   pj_timer_entry *entry, 

-		   int dont_call)

-{

-  long timer_node_slot;

-

-  PJ_CHECK_STACK();

-

-  // Check to see if the timer_id is out of range

-  if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size)

-    return 0;

-

-  timer_node_slot = ht->timer_ids[entry->_timer_id];

-

-  if (timer_node_slot < 0) // Check to see if timer_id is still valid.

-    return 0;

-

-  if (entry != ht->heap[timer_node_slot])

-    {

-      pj_assert(entry == ht->heap[timer_node_slot]);

-      return 0;

-    }

-  else

-    {

-      remove_node( ht, timer_node_slot);

-

-      if (dont_call == 0)

-        // Call the close hook.

-	(*ht->callback)(ht, entry);

-      return 1;

-    }

-}

-

-

-/*

- * Calculate memory size required to create a timer heap.

- */

-PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)

-{

-    return /* size of the timer heap itself: */

-           sizeof(pj_timer_heap_t) + 

-           /* size of each entry: */

-           (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +

-           /* lock, pool etc: */

-           132;

-}

-

-/*

- * Create a new timer heap.

- */

-PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,

-					  pj_size_t size,

-                                          pj_timer_heap_t **p_heap)

-{

-    pj_timer_heap_t *ht;

-    pj_size_t i;

-

-    PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);

-

-    *p_heap = NULL;

-

-    /* Magic? */

-    size += 2;

-

-    /* Allocate timer heap data structure from the pool */

-    ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t));

-    if (!ht)

-        return PJ_ENOMEM;

-

-    /* Initialize timer heap sizes */

-    ht->max_size = size;

-    ht->cur_size = 0;

-    ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;

-    ht->timer_ids_freelist = 1;

-    ht->pool = pool;

-

-    /* Lock. */

-    ht->lock = NULL;

-    ht->auto_delete_lock = 0;

-

-    // Create the heap array.

-    ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);

-    if (!ht->heap)

-        return PJ_ENOMEM;

-

-    // Create the parallel

-    ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size);

-    if (!ht->timer_ids)

-        return PJ_ENOMEM;

-

-    // Initialize the "freelist," which uses negative values to

-    // distinguish freelist elements from "pointers" into the <heap_>

-    // array.

-    for (i=0; i<size; ++i)

-	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));

-

-    *p_heap = ht;

-    return PJ_SUCCESS;

-}

-

-PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )

-{

-    if (ht->lock && ht->auto_delete_lock) {

-        pj_lock_destroy(ht->lock);

-        ht->lock = NULL;

-    }

-}

-

-PJ_DEF(void) pj_timer_heap_set_lock(  pj_timer_heap_t *ht,

-                                      pj_lock_t *lock,

-                                      pj_bool_t auto_del )

-{

-    if (ht->lock && ht->auto_delete_lock)

-        pj_lock_destroy(ht->lock);

-

-    ht->lock = lock;

-    ht->auto_delete_lock = auto_del;

-}

-

-

-PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,

-                                                          unsigned count )

-{

-    unsigned old_count = ht->max_entries_per_poll;

-    ht->max_entries_per_poll = count;

-    return old_count;

-}

-

-PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,

-                                             int id,

-                                             void *user_data,

-                                             pj_timer_heap_callback *cb )

-{

-    pj_assert(entry && cb);

-

-    entry->id = id;

-    entry->user_data = user_data;

-    entry->cb = cb;

-

-    return entry;

-}

-

-PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,

-					    pj_timer_entry *entry, 

-					    const pj_time_val *delay)

-{

-    pj_status_t status;

-    pj_time_val expires;

-

-    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);

-

-    pj_gettimeofday(&expires);

-    PJ_TIME_VAL_ADD(expires, *delay);

-    

-    lock_timer_heap(ht);

-    status = schedule_entry(ht, entry, &expires);

-    unlock_timer_heap(ht);

-

-    return status;

-}

-

-PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,

-				  pj_timer_entry *entry)

-{

-    int count;

-

-    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);

-

-    lock_timer_heap(ht);

-    count = cancel(ht, entry, 1);

-    unlock_timer_heap(ht);

-

-    return count;

-}

-

-PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 

-                                     pj_time_val *next_delay )

-{

-    pj_time_val now;

-    unsigned count;

-

-    PJ_ASSERT_RETURN(ht, 0);

-

-    if (!ht->cur_size && next_delay) {

-	next_delay->sec = next_delay->msec = PJ_MAXINT32;

-	return 0;

-    }

-

-    count = 0;

-    pj_gettimeofday(&now);

-

-    lock_timer_heap(ht);

-    while ( ht->cur_size && 

-	    PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) &&

-            count < ht->max_entries_per_poll ) 

-    {

-	pj_timer_entry *node = remove_node(ht, 0);

-	++count;

-

-	unlock_timer_heap(ht);

-	(*node->cb)(ht, node);

-	lock_timer_heap(ht);

-    }

-    if (ht->cur_size && next_delay) {

-	*next_delay = ht->heap[0]->_timer_value;

-	PJ_TIME_VAL_SUB(*next_delay, now);

-    } else if (next_delay) {

-	next_delay->sec = next_delay->msec = PJ_MAXINT32;

-    }

-    unlock_timer_heap(ht);

-

-    return count;

-}

-

-PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )

-{

-    PJ_ASSERT_RETURN(ht, 0);

-

-    return ht->cur_size;

-}

-

-PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,

-					         pj_time_val *timeval)

-{

-    pj_assert(ht->cur_size != 0);

-    if (ht->cur_size == 0)

-        return PJ_ENOTFOUND;

-

-    lock_timer_heap(ht);

-    *timeval = ht->heap[0]->_timer_value;

-    unlock_timer_heap(ht);

-

-    return PJ_SUCCESS;

-}

-

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/timer.h>
+#include <pj/pool.h>
+#include <pj/os.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/lock.h>
+
+#define HEAP_PARENT(X)	(X == 0 ? 0 : (((X) - 1) / 2))
+#define HEAP_LEFT(X)	(((X)+(X))+1)
+
+
+#define DEFAULT_MAX_TIMED_OUT_PER_POLL  (64)
+
+
+/**
+ * The implementation of timer heap.
+ */
+struct pj_timer_heap_t
+{
+    /** Pool from which the timer heap resize will get the storage from */
+    pj_pool_t *pool;
+
+    /** Maximum size of the heap. */
+    pj_size_t max_size;
+
+    /** Current size of the heap. */
+    pj_size_t cur_size;
+
+    /** Max timed out entries to process per poll. */
+    unsigned max_entries_per_poll;
+
+    /** Lock object. */
+    pj_lock_t *lock;
+
+    /** Autodelete lock. */
+    pj_bool_t auto_delete_lock;
+
+    /**
+     * Current contents of the Heap, which is organized as a "heap" of
+     * pj_timer_entry *'s.  In this context, a heap is a "partially
+     * ordered, almost complete" binary tree, which is stored in an
+     * array.
+     */
+    pj_timer_entry **heap;
+
+    /**
+     * An array of "pointers" that allows each pj_timer_entry in the
+     * <heap_> to be located in O(1) time.  Basically, <timer_id_[i]>
+     * contains the slot in the <heap_> array where an pj_timer_entry
+     * with timer id <i> resides.  Thus, the timer id passed back from
+     * <schedule_entry> is really an slot into the <timer_ids> array.  The
+     * <timer_ids_> array serves two purposes: negative values are
+     * treated as "pointers" for the <freelist_>, whereas positive
+     * values are treated as "pointers" into the <heap_> array.
+     */
+    pj_timer_id_t *timer_ids;
+
+    /**
+     * "Pointer" to the first element in the freelist contained within
+     * the <timer_ids_> array, which is organized as a stack.
+     */
+    pj_timer_id_t timer_ids_freelist;
+
+    /** Callback to be called when a timer expires. */
+    pj_timer_heap_callback *callback;
+
+};
+
+
+
+PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht )
+{
+    if (ht->lock) {
+	pj_lock_acquire(ht->lock);
+    }
+}
+
+PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht )
+{
+    if (ht->lock) {
+	pj_lock_release(ht->lock);
+    }
+}
+
+
+static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node )
+{
+    PJ_CHECK_STACK();
+
+    // Insert <moved_node> into its new location in the heap.
+    ht->heap[slot] = moved_node;
+    
+    // Update the corresponding slot in the parallel <timer_ids_> array.
+    ht->timer_ids[moved_node->_timer_id] = slot;
+}
+
+static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht )
+{
+    // We need to truncate this to <int> for backwards compatibility.
+    pj_timer_id_t new_id = ht->timer_ids_freelist;
+    
+    PJ_CHECK_STACK();
+
+    // The freelist values in the <timer_ids_> are negative, so we need
+    // to negate them to get the next freelist "pointer."
+    ht->timer_ids_freelist =
+	-ht->timer_ids[ht->timer_ids_freelist];
+    
+    return new_id;
+    
+}
+
+static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id)
+{
+    PJ_CHECK_STACK();
+
+    // The freelist values in the <timer_ids_> are negative, so we need
+    // to negate them to get the next freelist "pointer."
+    ht->timer_ids[old_id] = -ht->timer_ids_freelist;
+    ht->timer_ids_freelist = old_id;
+}
+
+
+static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node,
+                        size_t slot, size_t child)
+{
+    PJ_CHECK_STACK();
+
+    // Restore the heap property after a deletion.
+    
+    while (child < ht->cur_size)
+    {
+	// Choose the smaller of the two children.
+	if (child + 1 < ht->cur_size
+	    && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value))
+	    child++;
+	
+	// Perform a <copy> if the child has a larger timeout value than
+	// the <moved_node>.
+	if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value))
+        {
+	    copy_node( ht, slot, ht->heap[child]);
+	    slot = child;
+	    child = HEAP_LEFT(child);
+        }
+	else
+	    // We've found our location in the heap.
+	    break;
+    }
+    
+    copy_node( ht, slot, moved_node);
+}
+
+static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node,
+		       size_t slot, size_t parent)
+{
+    // Restore the heap property after an insertion.
+    
+    while (slot > 0)
+    {
+	// If the parent node is greater than the <moved_node> we need
+	// to copy it down.
+	if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value))
+        {
+	    copy_node(ht, slot, ht->heap[parent]);
+	    slot = parent;
+	    parent = HEAP_PARENT(slot);
+        }
+	else
+	    break;
+    }
+    
+    // Insert the new node into its proper resting place in the heap and
+    // update the corresponding slot in the parallel <timer_ids> array.
+    copy_node(ht, slot, moved_node);
+}
+
+
+static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot)
+{
+    pj_timer_entry *removed_node = ht->heap[slot];
+    
+    // Return this timer id to the freelist.
+    push_freelist( ht, removed_node->_timer_id );
+    
+    // Decrement the size of the heap by one since we're removing the
+    // "slot"th node.
+    ht->cur_size--;
+    
+    // Set the ID
+    removed_node->_timer_id = -1;
+
+    // Only try to reheapify if we're not deleting the last entry.
+    
+    if (slot < ht->cur_size)
+    {
+	int parent;
+	pj_timer_entry *moved_node = ht->heap[ht->cur_size];
+	
+	// Move the end node to the location being removed and update
+	// the corresponding slot in the parallel <timer_ids> array.
+	copy_node( ht, slot, moved_node);
+	
+	// If the <moved_node->time_value_> is great than or equal its
+	// parent it needs be moved down the heap.
+	parent = HEAP_PARENT (slot);
+	
+	if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value))
+	    reheap_down( ht, moved_node, slot, HEAP_LEFT(slot));
+	else
+	    reheap_up( ht, moved_node, slot, parent);
+    }
+    
+    return removed_node;
+}
+
+static void grow_heap(pj_timer_heap_t *ht)
+{
+    // All the containers will double in size from max_size_
+    size_t new_size = ht->max_size * 2;
+    pj_timer_id_t *new_timer_ids;
+    pj_size_t i;
+    
+    // First grow the heap itself.
+    
+    pj_timer_entry **new_heap = 0;
+    
+    new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size);
+    memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*));
+    //delete [] this->heap_;
+    ht->heap = new_heap;
+    
+    // Grow the array of timer ids.
+    
+    new_timer_ids = 0;
+    new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t));
+    
+    memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t));
+    
+    //delete [] timer_ids_;
+    ht->timer_ids = new_timer_ids;
+    
+    // And add the new elements to the end of the "freelist".
+    for (i = ht->max_size; i < new_size; i++)
+	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
+    
+    ht->max_size = new_size;
+}
+
+static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node)
+{
+    if (ht->cur_size + 2 >= ht->max_size)
+	grow_heap(ht);
+    
+    reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size));
+    ht->cur_size++;
+}
+
+
+static pj_status_t schedule_entry( pj_timer_heap_t *ht,
+				   pj_timer_entry *entry, 
+				   const pj_time_val *future_time )
+{
+    if (ht->cur_size < ht->max_size)
+    {
+	// Obtain the next unique sequence number.
+	// Set the entry
+	entry->_timer_id = pop_freelist(ht);
+	entry->_timer_value = *future_time;
+	insert_node( ht, entry);
+	return 0;
+    }
+    else
+	return -1;
+}
+
+
+static int cancel( pj_timer_heap_t *ht, 
+		   pj_timer_entry *entry, 
+		   int dont_call)
+{
+  long timer_node_slot;
+
+  PJ_CHECK_STACK();
+
+  // Check to see if the timer_id is out of range
+  if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size)
+    return 0;
+
+  timer_node_slot = ht->timer_ids[entry->_timer_id];
+
+  if (timer_node_slot < 0) // Check to see if timer_id is still valid.
+    return 0;
+
+  if (entry != ht->heap[timer_node_slot])
+    {
+      pj_assert(entry == ht->heap[timer_node_slot]);
+      return 0;
+    }
+  else
+    {
+      remove_node( ht, timer_node_slot);
+
+      if (dont_call == 0)
+        // Call the close hook.
+	(*ht->callback)(ht, entry);
+      return 1;
+    }
+}
+
+
+/*
+ * Calculate memory size required to create a timer heap.
+ */
+PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
+{
+    return /* size of the timer heap itself: */
+           sizeof(pj_timer_heap_t) + 
+           /* size of each entry: */
+           (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +
+           /* lock, pool etc: */
+           132;
+}
+
+/*
+ * Create a new timer heap.
+ */
+PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
+					  pj_size_t size,
+                                          pj_timer_heap_t **p_heap)
+{
+    pj_timer_heap_t *ht;
+    pj_size_t i;
+
+    PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
+
+    *p_heap = NULL;
+
+    /* Magic? */
+    size += 2;
+
+    /* Allocate timer heap data structure from the pool */
+    ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t));
+    if (!ht)
+        return PJ_ENOMEM;
+
+    /* Initialize timer heap sizes */
+    ht->max_size = size;
+    ht->cur_size = 0;
+    ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;
+    ht->timer_ids_freelist = 1;
+    ht->pool = pool;
+
+    /* Lock. */
+    ht->lock = NULL;
+    ht->auto_delete_lock = 0;
+
+    // Create the heap array.
+    ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);
+    if (!ht->heap)
+        return PJ_ENOMEM;
+
+    // Create the parallel
+    ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size);
+    if (!ht->timer_ids)
+        return PJ_ENOMEM;
+
+    // Initialize the "freelist," which uses negative values to
+    // distinguish freelist elements from "pointers" into the <heap_>
+    // array.
+    for (i=0; i<size; ++i)
+	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
+
+    *p_heap = ht;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )
+{
+    if (ht->lock && ht->auto_delete_lock) {
+        pj_lock_destroy(ht->lock);
+        ht->lock = NULL;
+    }
+}
+
+PJ_DEF(void) pj_timer_heap_set_lock(  pj_timer_heap_t *ht,
+                                      pj_lock_t *lock,
+                                      pj_bool_t auto_del )
+{
+    if (ht->lock && ht->auto_delete_lock)
+        pj_lock_destroy(ht->lock);
+
+    ht->lock = lock;
+    ht->auto_delete_lock = auto_del;
+}
+
+
+PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
+                                                          unsigned count )
+{
+    unsigned old_count = ht->max_entries_per_poll;
+    ht->max_entries_per_poll = count;
+    return old_count;
+}
+
+PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
+                                             int id,
+                                             void *user_data,
+                                             pj_timer_heap_callback *cb )
+{
+    pj_assert(entry && cb);
+
+    entry->id = id;
+    entry->user_data = user_data;
+    entry->cb = cb;
+
+    return entry;
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
+					    pj_timer_entry *entry, 
+					    const pj_time_val *delay)
+{
+    pj_status_t status;
+    pj_time_val expires;
+
+    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
+
+    pj_gettimeofday(&expires);
+    PJ_TIME_VAL_ADD(expires, *delay);
+    
+    lock_timer_heap(ht);
+    status = schedule_entry(ht, entry, &expires);
+    unlock_timer_heap(ht);
+
+    return status;
+}
+
+PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
+				  pj_timer_entry *entry)
+{
+    int count;
+
+    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
+
+    lock_timer_heap(ht);
+    count = cancel(ht, entry, 1);
+    unlock_timer_heap(ht);
+
+    return count;
+}
+
+PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 
+                                     pj_time_val *next_delay )
+{
+    pj_time_val now;
+    unsigned count;
+
+    PJ_ASSERT_RETURN(ht, 0);
+
+    if (!ht->cur_size && next_delay) {
+	next_delay->sec = next_delay->msec = PJ_MAXINT32;
+	return 0;
+    }
+
+    count = 0;
+    pj_gettimeofday(&now);
+
+    lock_timer_heap(ht);
+    while ( ht->cur_size && 
+	    PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) &&
+            count < ht->max_entries_per_poll ) 
+    {
+	pj_timer_entry *node = remove_node(ht, 0);
+	++count;
+
+	unlock_timer_heap(ht);
+	(*node->cb)(ht, node);
+	lock_timer_heap(ht);
+    }
+    if (ht->cur_size && next_delay) {
+	*next_delay = ht->heap[0]->_timer_value;
+	PJ_TIME_VAL_SUB(*next_delay, now);
+    } else if (next_delay) {
+	next_delay->sec = next_delay->msec = PJ_MAXINT32;
+    }
+    unlock_timer_heap(ht);
+
+    return count;
+}
+
+PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
+{
+    PJ_ASSERT_RETURN(ht, 0);
+
+    return ht->cur_size;
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
+					         pj_time_val *timeval)
+{
+    pj_assert(ht->cur_size != 0);
+    if (ht->cur_size == 0)
+        return PJ_ENOTFOUND;
+
+    lock_timer_heap(ht);
+    *timeval = ht->heap[0]->_timer_value;
+    unlock_timer_heap(ht);
+
+    return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/types.c b/pjlib/src/pj/types.c
index 34efff1..d707443 100644
--- a/pjlib/src/pj/types.c
+++ b/pjlib/src/pj/types.c
@@ -1,47 +1,47 @@
-/* $Id$ */

-/* 

- * Copyright (C)2003-2006 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/types.h>

-#include <pj/os.h>

-

-void pj_time_val_normalize(pj_time_val *t)

-{

-    PJ_CHECK_STACK();

-

-    if (t->msec >= 1000) {

-	do {

-	    t->sec++;

-	    t->msec -= 1000;

-        } while (t->msec >= 1000);

-    }

-    else if (t->msec <= -1000) {

-	do {

-	    t->sec--;

-	    t->msec += 1000;

-        } while (t->msec <= -1000);

-    }

-

-    if (t->sec >= 1 && t->msec < 0) {

-	t->sec--;

-	t->msec += 1000;

-

-    } else if (t->sec < 0 && t->msec > 0) {

-	t->sec++;

-	t->msec -= 1000;

-    }

-}

+/* $Id$ */
+/* 
+ * Copyright (C)2003-2006 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/types.h>
+#include <pj/os.h>
+
+void pj_time_val_normalize(pj_time_val *t)
+{
+    PJ_CHECK_STACK();
+
+    if (t->msec >= 1000) {
+	do {
+	    t->sec++;
+	    t->msec -= 1000;
+        } while (t->msec >= 1000);
+    }
+    else if (t->msec <= -1000) {
+	do {
+	    t->sec--;
+	    t->msec += 1000;
+        } while (t->msec <= -1000);
+    }
+
+    if (t->sec >= 1 && t->msec < 0) {
+	t->sec--;
+	t->msec += 1000;
+
+    } else if (t->sec < 0 && t->msec > 0) {
+	t->sec++;
+	t->msec -= 1000;
+    }
+}