Initial Symbian integration to trunk for pjlib

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1235 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib/include/pj/compat/cc_codew.h b/pjlib/include/pj/compat/cc_codew.h
new file mode 100644
index 0000000..cad9d0c
--- /dev/null
+++ b/pjlib/include/pj/compat/cc_codew.h
@@ -0,0 +1,51 @@
+/* $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_COMPAT_CC_GCC_H__
+#define __PJ_COMPAT_CC_GCC_H__
+
+/**
+ * @file cc_codew.h
+ * @brief Describes MetroWerks Code Warrior compiler specifics.
+ */
+
+#ifndef __MWERKS__
+#  error "This file is only for Code Warrior!"
+#endif
+
+#define PJ_CC_NAME		"codewarrior"
+#define PJ_CC_VER_1		((__MWERKS__ & 0xF000) >> 12)
+#define PJ_CC_VER_2		((__MWERKS__ & 0x0F00) >> 8)
+#define PJ_CC_VER_3		((__MWERKS__ & 0xFF))
+
+
+#define PJ_INLINE_SPECIFIER	static inline
+#define PJ_THREAD_FUNC	
+#define PJ_NORETURN		
+#define PJ_ATTR_NORETURN	
+
+#define PJ_HAS_INT64		1
+
+typedef long long pj_int64_t;
+typedef unsigned long long pj_uint64_t;
+
+#define PJ_INT64_FMT		"L"
+
+
+#endif	/* __PJ_COMPAT_CC_GCC_H__ */
+
diff --git a/pjlib/include/pj/compat/cc_mwcc.h b/pjlib/include/pj/compat/cc_mwcc.h
new file mode 100644
index 0000000..e22e9fb
--- /dev/null
+++ b/pjlib/include/pj/compat/cc_mwcc.h
@@ -0,0 +1,51 @@
+/* $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_COMPAT_CC_MWCC_H__
+#define __PJ_COMPAT_CC_MWCC_H__
+
+/**
+ * @file cc_mwcc.h
+ * @brief Describes MWCC compiler specifics.
+ */
+
+#ifndef __CW32__
+#  error "This file is only for mwcc!"
+#endif
+
+#define PJ_CC_NAME		"mwcc32sym"
+#define PJ_CC_VER_1		1
+#define PJ_CC_VER_2		0
+#define PJ_CC_VER_3		0
+
+
+#define PJ_INLINE_SPECIFIER	static inline
+#define PJ_THREAD_FUNC	
+#define PJ_NORETURN		
+#define PJ_ATTR_NORETURN	__attribute__ ((noreturn))
+
+#define PJ_HAS_INT64		1
+
+typedef long long pj_int64_t;
+typedef unsigned long long pj_uint64_t;
+
+#define PJ_INT64_FMT		"L"
+
+
+#endif	/* __PJ_COMPAT_CC_MWCC_H__ */
+
diff --git a/pjlib/include/pj/compat/os_symbian.h b/pjlib/include/pj/compat/os_symbian.h
new file mode 100644
index 0000000..51d78eb
--- /dev/null
+++ b/pjlib/include/pj/compat/os_symbian.h
@@ -0,0 +1,159 @@
+/* $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_COMPAT_OS_SYMBIAN_H__
+#define __PJ_COMPAT_OS_SYMBIAN_H__
+
+/**
+ * @file os_symbian.h
+ * @brief Describes Symbian operating system specifics.
+ */
+
+#define PJ_OS_NAME		    "symbian"
+
+#define PJ_HAS_ARPA_INET_H	    1
+#define PJ_HAS_ASSERT_H		    1
+#define PJ_HAS_CTYPE_H		    1
+#define PJ_HAS_ERRNO_H		    1
+#define PJ_HAS_LINUX_SOCKET_H	    0
+#define PJ_HAS_MALLOC_H		    0
+#define PJ_HAS_NETDB_H		    1
+#define PJ_HAS_NETINET_IN_H	    1
+#define PJ_HAS_SETJMP_H		    1
+#define PJ_HAS_STDARG_H		    1
+#define PJ_HAS_STDDEF_H		    1
+#define PJ_HAS_STDIO_H		    1
+#define PJ_HAS_STDLIB_H		    1
+#define PJ_HAS_STRING_H		    1
+#define PJ_HAS_NO_SNPRINTF	    1
+#define PJ_HAS_SYS_IOCTL_H	    1
+#define PJ_HAS_SYS_SELECT_H	    0
+#define PJ_HAS_SYS_SOCKET_H	    1
+#define PJ_HAS_SYS_TIME_H	    1
+#define PJ_HAS_SYS_TIMEB_H	    0
+#define PJ_HAS_SYS_TYPES_H	    1
+#define PJ_HAS_TIME_H		    1
+#define PJ_HAS_UNISTD_H		    1
+
+#define PJ_HAS_MSWSOCK_H	    0
+#define PJ_HAS_WINSOCK_H	    0
+#define PJ_HAS_WINSOCK2_H	    0
+
+#define PJ_SOCK_HAS_INET_ATON	    0
+
+/* Set 1 if native sockaddr_in has sin_len member.
+ * Default: 0
+ */
+#define PJ_SOCKADDR_HAS_LEN	    0
+/* Is errno a good way to retrieve OS errors?
+ */
+#define PJ_HAS_ERRNO_VAR	    1
+
+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
+ * the status of non-blocking connect() operation.
+ */
+#define PJ_HAS_SO_ERROR             1
+
+/**
+ * If this macro is set, it tells select I/O Queue that select() needs to
+ * be given correct value of nfds (i.e. largest fd + 1). This requires
+ * select ioqueue to re-scan the descriptors on each registration and
+ * unregistration.
+ * If this macro is not set, then ioqueue will always give FD_SETSIZE for
+ * nfds argument when calling select().
+ *
+ * Default: 0
+ */
+#define PJ_SELECT_NEEDS_NFDS	    0
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket recv() can not return immediate daata.
+ */
+#define PJ_BLOCKING_ERROR_VAL       EAGAIN
+
+/* This value specifies the value set in errno by the OS when a non-blocking
+ * socket connect() can not get connected immediately.
+ */
+#define PJ_BLOCKING_CONNECT_ERROR_VAL   EINPROGRESS
+
+/*
+ * We don't want to use threads in Symbian
+ */
+#define PJ_HAS_THREADS		    0
+
+
+/*
+ * Declare __FD_SETSIZE now before including <linux*>.
+#define __FD_SETSIZE		    PJ_IOQUEUE_MAX_HANDLES
+ */
+
+#ifndef NULL
+#   define NULL 0
+#endif
+
+
+/* Doesn't seem to allow more than this */
+#define PJ_IOQUEUE_MAX_HANDLES	    8
+
+/*
+ * Override features.
+ */
+#define PJ_HAS_FLOATING_POINT	    1
+#define PJ_HAS_MALLOC               0
+#define PJ_HAS_SEMAPHORE	    1
+#define PJ_HAS_EVENT_OBJ	    0
+#define PJ_HAS_HIGH_RES_TIMER	    1
+#define PJ_OS_HAS_CHECK_STACK       0
+#define PJ_TERM_HAS_COLOR	    0
+#define PJ_NATIVE_STRING_IS_UNICODE 0
+
+#define PJ_ATOMIC_VALUE_TYPE	    int
+#define PJ_THREAD_DESC_SIZE	    128
+
+/* If 1, use Read/Write mutex emulation for platforms that don't support it */
+#define PJ_EMULATE_RWMUTEX	    1
+
+/* If 1, pj_thread_create() should enforce the stack size when creating
+ * threads.
+ * Default: 0 (let OS decide the thread's stack size).
+ */
+#define PJ_THREAD_SET_STACK_SIZE    	0
+
+/* If 1, pj_thread_create() should allocate stack from the pool supplied.
+ * Default: 0 (let OS allocate memory for thread's stack).
+ */
+#define PJ_THREAD_ALLOCATE_STACK    	0
+
+/* Missing socklen_t */
+#define PJ_HAS_SOCKLEN_T		1
+typedef unsigned int socklen_t;
+
+#include <e32def.h>
+
+#if defined(PJ_EXPORTING)
+#   define PJ_EXPORT_IMPORT EXPORT_C
+#elif defined(PJ_IMPORTING)
+#   define PJ_EXPORT_IMPORT IMPORT_C
+#else
+#   error "Must define either PJ_EXPORTING or PJ_IMPORTING"
+#endif
+
+#endif	/* __PJ_COMPAT_OS_SYMBIAN_H__ */
+
+
+
diff --git a/pjlib/include/pj/compat/setjmp.h b/pjlib/include/pj/compat/setjmp.h
index b33ce44..2c2e469 100644
--- a/pjlib/include/pj/compat/setjmp.h
+++ b/pjlib/include/pj/compat/setjmp.h
@@ -82,6 +82,9 @@
 
 # endif   /* _ASM */
 
+#elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
+    /* Symbian framework don't use setjmp/longjmp */
+    
 #else
 #  warning "setjmp()/longjmp() is not implemented"
    typedef int pj_jmp_buf[1];
diff --git a/pjlib/include/pj/compat/socket.h b/pjlib/include/pj/compat/socket.h
index 52ad3f5..40c0345 100644
--- a/pjlib/include/pj/compat/socket.h
+++ b/pjlib/include/pj/compat/socket.h
@@ -87,6 +87,11 @@
 #  define OSERR_EINPROGRESS    WSAEINPROGRESS
 #  define OSERR_ECONNRESET     WSAECONNRESET
 #  define OSERR_ENOTCONN       WSAENOTCONN
+#elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
+#  define OSERR_EWOULDBLOCK    -1
+#  define OSERR_EINPROGRESS    -1
+#  define OSERR_ECONNRESET     -1
+#  define OSERR_ENOTCONN       -1
 #else
 #  define OSERR_EWOULDBLOCK    EWOULDBLOCK
 #  define OSERR_EINPROGRESS    EINPROGRESS
diff --git a/pjlib/include/pj/compat/string.h b/pjlib/include/pj/compat/string.h
index 07ac4e2..896615b 100644
--- a/pjlib/include/pj/compat/string.h
+++ b/pjlib/include/pj/compat/string.h
@@ -72,6 +72,16 @@
 #define pj_ansi_strncasecmp	strncasecmp
 #define pj_ansi_strnicmp	strncasecmp
 #define pj_ansi_sprintf		sprintf
+
+#if defined(PJ_HAS_NO_SNPRINTF) && PJ_HAS_NO_SNPRINTF != 0
+#   include <pj/types.h>
+#   include <pj/compat/stdarg.h>
+    PJ_BEGIN_DECL
+    PJ_DECL(int) snprintf(char*s1, pj_size_t len, const char*s2, ...);
+    PJ_DECL(int) vsnprintf(char*s1, pj_size_t len, const char*s2, va_list arg);
+    PJ_END_DECL
+#endif
+    
 #define pj_ansi_snprintf	snprintf
 #define pj_ansi_vsprintf	vsprintf
 #define pj_ansi_vsnprintf	vsnprintf
diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
index 951823e..e6d4fd4 100644
--- a/pjlib/include/pj/config.h
+++ b/pjlib/include/pj/config.h
@@ -31,6 +31,10 @@
 #  include <pj/compat/cc_msvc.h>
 #elif defined(__GNUC__)
 #  include <pj/compat/cc_gcc.h>
+#elif defined(__CW32__)
+#  include <pj/compat/cc_mwcc.h>
+#elif defined(__MWERKS__)
+#  include <pj/compat/cc_codew.h>
 #else
 #  error "Unknown compiler."
 #endif
@@ -45,6 +49,12 @@
      */
 #   include <pj/compat/os_auto.h>
 
+#elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
+    /*
+     * SymbianOS
+     */
+#  include <pj/compat/os_symbian.h>
+
 #elif defined(PJ_WIN32_WINCE) || defined(_WIN32_WCE) || defined(UNDER_CE)
     /*
      * Windows CE
diff --git a/pjlib/include/pj/config_site_sample.h b/pjlib/include/pj/config_site_sample.h
index efa7638..f873dd5 100644
--- a/pjlib/include/pj/config_site_sample.h
+++ b/pjlib/include/pj/config_site_sample.h
@@ -65,7 +65,7 @@
 #   define PJSIP_UDP_SO_RCVBUF_SIZE	(24*1024*1024)
 #   define PJ_DEBUG			0
 #   define PJSIP_SAFE_MODULE		0
-#   define PJ_HAS_STRICMP_ALNUM		1
+#   define PJ_HAS_STRICMP_ALNUM		0
 #   define PJ_HASH_USE_OWN_TOLOWER	1
 #   define PJSIP_UNESCAPE_IN_PLACE	1
 
diff --git a/pjlib/include/pj/except.h b/pjlib/include/pj/except.h
index a07eb22..2f1f9dd 100644
--- a/pjlib/include/pj/except.h
+++ b/pjlib/include/pj/except.h
@@ -237,6 +237,29 @@
 #define PJ_THROW(id)	    pj_throw_exception_(id)
 #define PJ_GET_EXCEPTION()  GetExceptionCode()
 
+
+#elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
+/*****************************************************************************
+ **
+ ** IMPLEMENTATION OF EXCEPTION USING SYMBIAN LEAVE/TRAP FRAMEWORK
+ **
+ ****************************************************************************/
+
+class TPjException
+{
+public:
+    int code_;
+};
+
+#define PJ_USE_EXCEPTION
+#define PJ_TRY			try
+//#define PJ_CATCH(id)		
+#define PJ_CATCH_ANY		catch (const TPjException & pj_excp_)
+#define PJ_END
+#define PJ_THROW(x_id)		do { TPjException e; e.code_=x_id; throw e;} \
+				while (0)
+#define PJ_GET_EXCEPTION()	pj_excp_.code_
+
 #else
 /*****************************************************************************
  **
diff --git a/pjlib/include/pj/list_i.h b/pjlib/include/pj/list_i.h
index d8544a7..f0a628e 100644
--- a/pjlib/include/pj/list_i.h
+++ b/pjlib/include/pj/list_i.h
@@ -128,7 +128,7 @@
 
     while (node != list) {
 	++count;
-	node = node->next;
+	node = (pj_list*)node->next;
     }
 
     return count;
diff --git a/pjlib/src/pj/addr_resolv_symbian.cpp b/pjlib/src/pj/addr_resolv_symbian.cpp
new file mode 100644
index 0000000..c9a776c
--- /dev/null
+++ b/pjlib/src/pj/addr_resolv_symbian.cpp
@@ -0,0 +1,147 @@
+/* $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/addr_resolv.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <pj/unicode.h>
+
+#include "os_symbian.h"
+ 
+
+// PJLIB API: resolve hostname
+PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he)
+{
+    PJ_ASSERT_RETURN(name && he, PJ_EINVAL);
+
+    RHostResolver &resv = PjSymbianOS::Instance()->GetResolver();
+
+    // Convert name to Unicode
+    wchar_t name16[PJ_MAX_HOSTNAME];
+    pj_ansi_to_unicode(name->ptr, name->slen, name16, PJ_ARRAY_SIZE(name16));
+    TPtrC16 data(name16);
+
+    // Resolve!
+    TNameEntry nameEntry;
+    TRequestStatus reqStatus;
+    
+    resv.GetByName(data, nameEntry, reqStatus);
+    User::WaitForRequest(reqStatus);
+    
+    if (reqStatus != KErrNone)
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+
+    // Get the resolved TInetAddr
+    // This doesn't work, see Martin email on 28/3/2007:
+    // const TNameRecord &rec = (const TNameRecord&) nameEntry;
+    // TInetAddr inetAddr(rec.iAddr);
+    TInetAddr inetAddr(nameEntry().iAddr);
+
+    //
+    // This where we keep static variables.
+    // These should be kept in TLS probably, to allow multiple threads
+    // to call pj_gethostbyname() without interfering each other.
+    // But again, we don't support threads in Symbian!
+    //
+    static char resolved_name[PJ_MAX_HOSTNAME];
+    static char *no_aliases[1];
+    static pj_in_addr *addr_list[2];
+    static pj_sockaddr_in resolved_addr;
+
+    // Convert the official address to ANSI.
+    pj_unicode_to_ansi(nameEntry().iName.Ptr(), nameEntry().iName.Length(),
+		       resolved_name, sizeof(resolved_name));
+
+    // Convert IP address
+    
+    PjSymbianOS::Addr2pj(inetAddr, resolved_addr);
+    addr_list[0] = &resolved_addr.sin_addr;
+
+    // Return hostent
+    he->h_name = resolved_name;
+    he->h_aliases = no_aliases;
+    he->h_addrtype = PJ_AF_INET;
+    he->h_length = 4;
+    he->h_addr_list = (char**) addr_list;
+
+    return PJ_SUCCESS;
+}
+
+
+/* Resolve the IP address of local machine */
+pj_status_t pj_gethostip(pj_in_addr *addr)
+{
+    const pj_str_t *hostname = pj_gethostname();
+    struct pj_hostent he;
+    pj_str_t cp;
+    pj_in_addr loopip;
+    pj_status_t status;
+
+    cp = pj_str("127.0.0.1");
+    loopip = pj_inet_addr(&cp);
+
+    /* Try with resolving local hostname first */
+    status = pj_gethostbyname(hostname, &he);
+    if (status == PJ_SUCCESS) {
+	*addr = *(pj_in_addr*)he.h_addr;
+    }
+
+
+    /* If we end up with 127.0.0.1 or 0.0.0.0, resolve the IP by getting 
+     * the default interface to connect to some public host.
+     */
+    if (status!=PJ_SUCCESS || addr->s_addr == loopip.s_addr || !addr->s_addr) {
+	pj_sock_t fd;
+	pj_sockaddr_in a;
+	int len;
+
+	status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &fd);
+	if (status != PJ_SUCCESS) {
+	    return status;
+	}
+
+	cp = pj_str("1.1.1.1");
+	pj_sockaddr_in_init(&a, &cp, 53);
+
+	status = pj_sock_connect(fd, &a, sizeof(a));
+	if (status != PJ_SUCCESS) {
+	    pj_sock_close(fd);
+	    return status;
+	}
+
+	len = sizeof(a);
+	status = pj_sock_getsockname(fd, &a, &len);
+	if (status != PJ_SUCCESS) {
+	    pj_sock_close(fd);
+	    return status;
+	}
+
+	pj_sock_close(fd);
+	
+	*addr = a.sin_addr;
+
+	if (a.sin_addr.s_addr == 0)
+	    return PJ_ENOTFOUND;
+    }
+
+    return status;
+}
+
+
+
diff --git a/pjlib/src/pj/array.c b/pjlib/src/pj/array.c
index 8d63868..832afee 100644
--- a/pjlib/src/pj/array.c
+++ b/pjlib/src/pj/array.c
@@ -55,7 +55,7 @@
 				   void **result)
 {
     unsigned i;
-    const char *char_array = array;
+    const char *char_array = (const char*)array;
     for (i=0; i<count; ++i) {
 	if ( (*matching)(char_array) == PJ_SUCCESS) {
 	    if (result) {
diff --git a/pjlib/src/pj/compat/string_compat.c b/pjlib/src/pj/compat/string_compat.c
new file mode 100644
index 0000000..28f1312
--- /dev/null
+++ b/pjlib/src/pj/compat/string_compat.c
@@ -0,0 +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/types.h>
+#include <pj/compat/string.h>
+#include <pj/ctype.h>
+
+#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H != 0
+/* Nothing to do */
+#else
+PJ_DEF(int) strcasecmp(const char *s1, const char *s2)
+{
+    while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
+	if (!*s1++)
+	    return 0;
+	++s2;
+    }
+    return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
+}
+
+PJ_DEF(int) strncasecmp(const char *s1, const char *s2, int len)
+{
+    if (!len) return 0;
+
+    while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
+	if (!*s1++ || --len <= 0)
+	    return 0;
+	++s2;
+    }
+    return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
+}
+#endif
+
+#if defined(PJ_HAS_NO_SNPRINTF) && PJ_HAS_NO_SNPRINTF != 0
+
+PJ_DEF(int) snprintf(char *s1, pj_size_t len, const char *s2, ...)
+{
+    int ret;
+    va_list arg;
+
+    PJ_UNUSED_ARG(len);
+
+    va_start(arg, s2);
+    ret = vsprintf(s1, s2, arg);
+    va_end(arg);
+    
+    return ret;
+}
+
+PJ_DEF(int) vsnprintf(char *s1, pj_size_t len, const char *s2, va_list arg)
+{
+    PJ_UNUSED_ARG(len);
+    return vsprintf(s1,s2,arg);
+}
+
+#endif
+
diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c
index 7745dfd..f82c22d 100644
--- a/pjlib/src/pj/errno.c
+++ b/pjlib/src/pj/errno.c
@@ -18,13 +18,17 @@
  */
 #include <pj/errno.h>
 #include <pj/string.h>
+#include <pj/compat/string.h>
 #include <pj/assert.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 );
+PJ_BEGIN_DECL
+
+    PJ_DECL(int) platform_strerror(pj_os_err_type code, 
+                              	   char *buf, pj_size_t bufsize );
+PJ_END_DECL
 
 #define PJLIB_MAX_ERR_MSG_HANDLER   8
 
diff --git a/pjlib/src/pj/exception_symbian.cpp b/pjlib/src/pj/exception_symbian.cpp
new file mode 100644
index 0000000..f04045b
--- /dev/null
+++ b/pjlib/src/pj/exception_symbian.cpp
@@ -0,0 +1,154 @@
+/* $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 */
+
+
+//#if !defined(PJ_EXCEPTION_USE_WIN32_SEH) || PJ_EXCEPTION_USE_WIN32_SEH==0
+#if 0
+PJ_DEF(void) pj_throw_exception_(int exception_id)
+{
+    struct pj_exception_state_t *handler;
+
+    handler = (pj_exception_state_t*)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_exception_state_t*)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_exception_state_t*)pj_thread_local_get(thread_local_id);
+    pj_assert(handler != NULL);
+    pj_thread_local_set(thread_local_id, handler->prev);
+}
+#endif
+
+#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/fifobuf.c b/pjlib/src/pj/fifobuf.c
index 50b7cf3..08bf907 100644
--- a/pjlib/src/pj/fifobuf.c
+++ b/pjlib/src/pj/fifobuf.c
@@ -34,7 +34,7 @@
 	       "fifobuf_init fifobuf=%p buffer=%p, size=%d", 
 	       fifobuf, buffer, size));
 
-    fifobuf->first = buffer;
+    fifobuf->first = (char*)buffer;
     fifobuf->last = fifobuf->first + size;
     fifobuf->ubegin = fifobuf->uend = fifobuf->first;
     fifobuf->full = 0;
@@ -118,7 +118,7 @@
 PJ_DEF(pj_status_t)
 pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)
 {
-    char *ptr = buf;
+    char *ptr = (char*)buf;
     char *endptr;
     unsigned sz;
 
@@ -149,7 +149,7 @@
 PJ_DEF(pj_status_t)
 pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)
 {
-    char *ptr = buf;
+    char *ptr = (char*)buf;
     char *end;
     unsigned sz;
 
diff --git a/pjlib/src/pj/guid.c b/pjlib/src/pj/guid.c
index dd308d5..30ac2b1 100644
--- a/pjlib/src/pj/guid.c
+++ b/pjlib/src/pj/guid.c
@@ -21,6 +21,6 @@
 
 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);
+    str->ptr = (char*)pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);
     pj_generate_unique_string(str);
 }
diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c
index 5a97e5f..5b3454d 100644
--- a/pjlib/src/pj/hash.c
+++ b/pjlib/src/pj/hash.c
@@ -55,13 +55,13 @@
     PJ_CHECK_STACK();
 
     if (keylen==PJ_HASH_KEY_STRING) {
-	const unsigned char *p = key;
+	const pj_uint8_t *p = (const pj_uint8_t*)key;
 	for ( ; *p; ++p ) {
 	    hash = (hash * PJ_HASH_MULTIPLIER) + *p;
 	}
     } else {
-	const unsigned char *p = key,
-			    *end = p + keylen;
+	const pj_uint8_t *p = (const pj_uint8_t*)key,
+			      *end = p + keylen;
 	for ( ; p!=end; ++p) {
 	    hash = (hash * PJ_HASH_MULTIPLIER) + *p;
 	}
@@ -103,7 +103,7 @@
     /* Check that PJ_HASH_ENTRY_SIZE is correct. */
     PJ_ASSERT_RETURN(sizeof(pj_hash_entry)==PJ_HASH_ENTRY_SIZE, NULL);
 
-    h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));
+    h = PJ_POOL_ALLOC_T(pool, pj_hash_table_t);
     h->count = 0;
 
     PJ_LOG( 6, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool)));
@@ -119,7 +119,8 @@
     table_size -= 1;
     
     h->rows = table_size;
-    h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));
+    h->table = (pj_hash_entry**)
+    	       pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));
     return h;
 }
 
@@ -142,14 +143,14 @@
 	 */
 	hash=0;
 	if (keylen==PJ_HASH_KEY_STRING) {
-	    const unsigned char *p = key;
+	    const pj_uint8_t *p = (const pj_uint8_t*)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;
+	    const pj_uint8_t *p = (const pj_uint8_t*)key,
+				  *end = p + keylen;
 	    for ( ; p!=end; ++p) {
 		hash = hash * PJ_HASH_MULTIPLIER + *p;
 	    }
@@ -179,12 +180,12 @@
      * If entry_buf is specified, use it. Otherwise allocate from pool.
      */
     if (entry_buf) {
-	entry = entry_buf;
+	entry = (pj_hash_entry*)entry_buf;
     } else {
 	/* Pool must be specified! */
 	PJ_ASSERT_RETURN(pool != NULL, NULL);
 
-	entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
+	entry = PJ_POOL_ALLOC_T(pool, pj_hash_entry);
 	PJ_LOG(6, ("hashtbl", 
 		   "%p: New p_entry %p created, pool used=%u, cap=%u", 
 		   ht, entry,  pj_pool_get_used_size(pool), 
diff --git a/pjlib/src/pj/ioqueue_symbian.cpp b/pjlib/src/pj/ioqueue_symbian.cpp
new file mode 100644
index 0000000..50f3350
--- /dev/null
+++ b/pjlib/src/pj/ioqueue_symbian.cpp
@@ -0,0 +1,812 @@
+/* $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/assert.h>
+#include <pj/errno.h>
+#include <pj/list.h>
+#include <pj/lock.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+#include "os_symbian.h"
+
+class CIoqueueCallback;
+
+/*
+ * IO Queue structure.
+ */
+struct pj_ioqueue_t
+{
+    int		     eventCount;
+    CPjTimeoutTimer *timeoutTimer;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Class to encapsulate asynchronous socket operation.
+//
+class CIoqueueCallback : public CActive
+{
+public:
+    static CIoqueueCallback* NewL(pj_ioqueue_t *ioqueue,
+				  pj_ioqueue_key_t *key, 
+				  pj_sock_t sock, 
+				  const pj_ioqueue_callback *cb, 
+				  void *user_data);
+
+    //
+    // Start asynchronous recv() operation
+    //
+    pj_status_t StartRead(pj_ioqueue_op_key_t *op_key, 
+			  void *buf, pj_ssize_t *size, unsigned flags,
+			  pj_sockaddr_t *addr, int *addrlen);
+
+    //
+    // Start asynchronous accept() operation.
+    //
+    pj_status_t StartAccept(pj_ioqueue_op_key_t *op_key,
+			    pj_sock_t *new_sock,
+			    pj_sockaddr_t *local,
+			    pj_sockaddr_t *remote,
+			    int *addrlen );
+
+    //
+    // Completion callback.
+    //
+    void RunL();
+
+    //
+    // CActive's DoCancel()
+    //
+    void DoCancel();
+
+    //
+    // Cancel operation and call callback.
+    //
+    void CancelOperation(pj_ioqueue_op_key_t *op_key, 
+			 pj_ssize_t bytes_status);
+
+    //
+    // Accessors
+    //
+    void* get_user_data() const
+    {
+	return user_data_;
+    }
+    void set_user_data(void *user_data)
+    {
+	user_data_ = user_data;
+    }
+    pj_ioqueue_op_key_t *get_op_key() const
+    {
+	return pending_data_.common_.op_key_;
+    }
+    CPjSocket* get_pj_socket()
+    {
+	return sock_;
+    }
+
+private:
+    // Type of pending operation.
+    enum Type {
+	TYPE_NONE,
+	TYPE_READ,
+	TYPE_ACCEPT,
+    };
+
+    // Static data.
+    pj_ioqueue_t		*ioqueue_;
+    pj_ioqueue_key_t		*key_;
+    CPjSocket			*sock_;
+    pj_ioqueue_callback		 cb_;
+    void			*user_data_;
+
+    // Symbian data.
+    TPtr8			 aBufferPtr_;
+    TInetAddr			 aAddress_;
+
+    // Application data.
+    Type			 type_;
+
+    union Pending_Data
+    {
+	struct Common
+	{
+	    pj_ioqueue_op_key_t	*op_key_;
+	} common_;
+
+	struct Pending_Read
+	{
+	    pj_ioqueue_op_key_t	*op_key_;
+	    pj_sockaddr_t	*addr_;
+	    int			*addrlen_;
+	} read_;
+
+	struct Pending_Accept
+	{
+	    pj_ioqueue_op_key_t *op_key_;
+	    pj_sock_t		*new_sock_;
+	    pj_sockaddr_t	*local_;
+	    pj_sockaddr_t	*remote_;
+	    int			*addrlen_;
+	} accept_;
+    };
+
+    union Pending_Data		 pending_data_;
+    RSocket			blank_sock_;
+
+    CIoqueueCallback(pj_ioqueue_t *ioqueue,
+		     pj_ioqueue_key_t *key, pj_sock_t sock, 
+		     const pj_ioqueue_callback *cb, void *user_data)
+    : CActive(CActive::EPriorityStandard),
+	  ioqueue_(ioqueue), key_(key), sock_((CPjSocket*)sock), 
+	  user_data_(user_data), aBufferPtr_(NULL, 0), type_(TYPE_NONE)
+    {
+    	pj_memcpy(&cb_, cb, sizeof(*cb));
+    }
+
+
+    void ConstructL()
+    {
+	CActiveScheduler::Add(this);
+    }
+    
+    void HandleReadCompletion();
+    CPjSocket *HandleAcceptCompletion();
+};
+
+
+CIoqueueCallback* CIoqueueCallback::NewL(pj_ioqueue_t *ioqueue,
+					 pj_ioqueue_key_t *key, 
+					 pj_sock_t sock, 
+					 const pj_ioqueue_callback *cb, 
+					 void *user_data)
+{
+    CIoqueueCallback *self = new CIoqueueCallback(ioqueue, key, sock, 
+						  cb, user_data);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+
+    return self;
+}
+
+
+//
+// Start asynchronous recv() operation
+//
+pj_status_t CIoqueueCallback::StartRead(pj_ioqueue_op_key_t *op_key, 
+					void *buf, pj_ssize_t *size, 
+					unsigned flags,
+					pj_sockaddr_t *addr, int *addrlen)
+{
+    PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
+    PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
+
+    flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
+
+    pending_data_.read_.op_key_ = op_key;
+    pending_data_.read_.addr_ = addr;
+    pending_data_.read_.addrlen_ = addrlen;
+
+    aBufferPtr_.Set((TUint8*)buf, 0, (TInt)*size);
+
+    type_ = TYPE_READ;
+    if (addr && addrlen) {
+	sock_->Socket().RecvFrom(aBufferPtr_, aAddress_, flags, iStatus);
+    } else {
+	aAddress_.SetAddress(0);
+	aAddress_.SetPort(0);
+	sock_->Socket().Recv(aBufferPtr_, flags, iStatus);
+    }
+
+    if (iStatus==KRequestPending) {
+	SetActive();
+	return PJ_EPENDING;
+    } else {
+    	// Complete immediately (with success or error)
+    	if (iStatus == KErrNone) {
+    	    *size = aBufferPtr_.Length();
+    	    HandleReadCompletion();
+    	    return PJ_SUCCESS;
+    	}
+    	else {
+	    pending_data_.read_.op_key_ = NULL;
+	    pending_data_.read_.addr_ = NULL;
+	    pending_data_.read_.addrlen_ = NULL;
+	    return PJ_RETURN_OS_ERROR(iStatus.Int());
+    	}
+    }
+}
+
+
+//
+// Start asynchronous accept() operation.
+//
+pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key,
+					  pj_sock_t *new_sock,
+					  pj_sockaddr_t *local,
+					  pj_sockaddr_t *remote,
+					  int *addrlen )
+{
+    PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY);
+    PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY);
+
+    pending_data_.accept_.op_key_ = op_key;
+    pending_data_.accept_.new_sock_ = new_sock;
+    pending_data_.accept_.local_ = local;
+    pending_data_.accept_.remote_ = remote;
+    pending_data_.accept_.addrlen_ = addrlen;
+
+    // Create blank socket
+    blank_sock_.Open(PjSymbianOS::Instance()->SocketServ());
+
+    type_ = TYPE_ACCEPT;
+    sock_->Socket().Accept(blank_sock_, iStatus);
+
+    if (iStatus==KRequestPending) {
+	SetActive();
+	return PJ_EPENDING;
+    } else {
+    	// Accept() completed immediately (with success or error).
+    	if (iStatus == KErrNone) {
+    	    HandleAcceptCompletion();
+    	    return PJ_SUCCESS;
+    	}
+    	else {
+	    pending_data_.accept_.op_key_ = NULL;
+	    pending_data_.accept_.new_sock_ = NULL;
+	    pending_data_.accept_.local_ = NULL;
+	    pending_data_.accept_.remote_ = NULL;
+	    pending_data_.accept_.addrlen_ = NULL;
+	    return PJ_RETURN_OS_ERROR(iStatus.Int());
+    	}
+    }
+}
+
+
+//
+// Handle asynchronous RecvFrom() completion
+//
+void CIoqueueCallback::HandleReadCompletion() 
+{
+	if (pending_data_.read_.addr_) {
+	    PjSymbianOS::Addr2pj(aAddress_, 
+				 *(pj_sockaddr_in*)pending_data_.read_.addr_);
+	    pending_data_.read_.addr_ = NULL;
+	}
+	if (pending_data_.read_.addrlen_) {
+	    *pending_data_.read_.addrlen_ = sizeof(pj_sockaddr_in);
+	    pending_data_.read_.addrlen_ = NULL;
+	}
+	
+	pending_data_.read_.op_key_ = NULL;
+}
+
+
+//
+// Handle asynchronous Accept() completion.
+//
+CPjSocket *CIoqueueCallback::HandleAcceptCompletion() 
+{
+	CPjSocket *pjNewSock = new CPjSocket(blank_sock_);
+
+	if (pending_data_.accept_.new_sock_) {
+	    *pending_data_.accept_.new_sock_ = (pj_sock_t)pjNewSock;
+	    pending_data_.accept_.new_sock_ = NULL;
+	}
+
+	if (pending_data_.accept_.local_) {
+	    TInetAddr aAddr;
+	    pj_sockaddr_in *ptr_sockaddr;
+
+	    blank_sock_.LocalName(aAddr);
+	    ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.local_;
+	    PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
+	    pending_data_.accept_.local_ = NULL;
+	}
+
+	if (pending_data_.accept_.remote_) {
+	    TInetAddr aAddr;
+	    pj_sockaddr_in *ptr_sockaddr;
+
+	    blank_sock_.RemoteName(aAddr);
+	    ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.remote_;
+	    PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr);
+	    pending_data_.accept_.remote_ = NULL;
+	}
+
+	if (pending_data_.accept_.addrlen_) {
+	    *pending_data_.accept_.addrlen_ = sizeof(pj_sockaddr_in);
+	    pending_data_.accept_.addrlen_ = NULL;
+	}
+	
+	return pjNewSock;
+}
+
+
+//
+// Completion callback.
+//
+void CIoqueueCallback::RunL()
+{
+    Type cur_type = type_;
+
+    type_ = TYPE_NONE;
+
+    if (cur_type == TYPE_READ) {
+	//
+	// Completion of asynchronous RecvFrom()
+	//
+
+	/* Clear op_key (save it to temp variable first!) */
+	pj_ioqueue_op_key_t	*op_key = pending_data_.read_.op_key_;
+	pending_data_.read_.op_key_ = NULL;
+
+	// Handle failure condition
+	if (iStatus != KErrNone) {
+	    if (cb_.on_read_complete) {
+	    	cb_.on_read_complete( key_, op_key, 
+				      -PJ_RETURN_OS_ERROR(iStatus.Int()));
+	    }
+	    return;
+	}
+
+	HandleReadCompletion();
+
+	/* Call callback */
+	if (cb_.on_read_complete) {
+	    cb_.on_read_complete(key_, op_key, aBufferPtr_.Length());
+	}
+
+    } else if (cur_type == TYPE_ACCEPT) {
+	//
+	// Completion of asynchronous Accept()
+	//
+	
+	/* Clear op_key (save it to temp variable first!) */
+	pj_ioqueue_op_key_t	*op_key = pending_data_.read_.op_key_;
+	pending_data_.read_.op_key_ = NULL;
+
+	// Handle failure condition
+	if (iStatus != KErrNone) {
+	    if (pending_data_.accept_.new_sock_)
+		*pending_data_.accept_.new_sock_ = PJ_INVALID_SOCKET;
+	    
+	    if (cb_.on_accept_complete) {
+	    	cb_.on_accept_complete( key_, op_key, PJ_INVALID_SOCKET,
+				        -PJ_RETURN_OS_ERROR(iStatus.Int()));
+	    }
+	    return;
+	}
+
+	CPjSocket *pjNewSock = HandleAcceptCompletion();
+	
+	// Call callback.
+	if (cb_.on_accept_complete) {
+	    cb_.on_accept_complete( key_, op_key, (pj_sock_t)pjNewSock, 
+				    PJ_SUCCESS);
+	}
+    }
+
+    ioqueue_->eventCount++;
+}
+
+//
+// CActive's DoCancel()
+//
+void CIoqueueCallback::DoCancel()
+{
+    if (type_ == TYPE_READ)
+	sock_->Socket().CancelRecv();
+    else if (type_ == TYPE_ACCEPT)
+	sock_->Socket().CancelAccept();
+
+    type_ = TYPE_NONE;
+}
+
+//
+// Cancel operation and call callback.
+//
+void CIoqueueCallback::CancelOperation(pj_ioqueue_op_key_t *op_key, 
+				       pj_ssize_t bytes_status)
+{
+    Type cur_type = type_;
+
+    Cancel();
+
+    if (cur_type == TYPE_READ) {
+    	if (cb_.on_read_complete)
+    	    cb_.on_read_complete(key_, op_key, bytes_status);
+    } else if (cur_type == TYPE_ACCEPT)
+	;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+/*
+ * IO Queue key structure.
+ */
+struct pj_ioqueue_key_t
+{
+    CIoqueueCallback	*cbObj;
+};
+
+
+/*
+ * Return the name of the ioqueue implementation.
+ */
+PJ_DEF(const char*) pj_ioqueue_name(void)
+{
+    return "ioqueue-symbian";
+}
+
+
+/*
+ * Create a new I/O Queue framework.
+ */
+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 *ioq;
+
+    PJ_UNUSED_ARG(max_fd);
+
+    ioq = (pj_ioqueue_t*) pj_pool_zalloc(pool, sizeof(pj_ioqueue_t));
+    ioq->timeoutTimer = CPjTimeoutTimer::NewL();
+    *p_ioqueue = ioq;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Destroy the I/O queue.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioq )
+{
+    delete ioq->timeoutTimer;
+    ioq->timeoutTimer = NULL;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set the lock object to be used by the I/O Queue. 
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioq, 
+					 pj_lock_t *lock,
+					 pj_bool_t auto_delete )
+{
+    /* Don't really need lock for now */
+    PJ_UNUSED_ARG(ioq);
+    
+    if (auto_delete) {
+	pj_lock_destroy(lock);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Register a socket to the I/O queue framework. 
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					      pj_ioqueue_t *ioq,
+					      pj_sock_t sock,
+					      void *user_data,
+					      const pj_ioqueue_callback *cb,
+                                              pj_ioqueue_key_t **p_key )
+{
+    pj_ioqueue_key_t *key;
+
+    key = (pj_ioqueue_key_t*) pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+    key->cbObj = CIoqueueCallback::NewL(ioq, key, sock, cb, user_data);
+
+    *p_key = key;
+    return PJ_SUCCESS;
+}
+
+/*
+ * Unregister from the I/O Queue framework. 
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
+{
+    if (key == NULL || key->cbObj == NULL)
+	return PJ_SUCCESS;
+
+    // Cancel pending async object
+    if (key->cbObj && key->cbObj->IsActive()) {
+	key->cbObj->Cancel();
+    }
+
+    // Close socket.
+    key->cbObj->get_pj_socket()->Socket().Close();
+    delete key->cbObj->get_pj_socket();
+
+    // Delete async object.
+    if (key->cbObj) {
+	delete key->cbObj;
+	key->cbObj = NULL;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get user data associated with an ioqueue key.
+ */
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+    return key->cbObj->get_user_data();
+}
+
+
+/*
+ * Set or change the user data to be associated with the file descriptor or
+ * handle or socket descriptor.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
+                                              void *user_data,
+                                              void **old_data)
+{
+    if (old_data)
+	*old_data = key->cbObj->get_user_data();
+    key->cbObj->set_user_data(user_data);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Initialize operation key.
+ */
+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);
+}
+
+
+/*
+ * Check if operation is pending on the specified operation key.
+ */
+PJ_DEF(pj_bool_t) pj_ioqueue_is_pending( pj_ioqueue_key_t *key,
+                                         pj_ioqueue_op_key_t *op_key )
+{
+    return key->cbObj->get_op_key()==op_key &&
+	   key->cbObj->IsActive();
+}
+
+
+/*
+ * Post completion status to the specified operation key and call the
+ * appropriate callback. 
+ */
+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 )
+{
+    if (pj_ioqueue_is_pending(key, op_key)) {
+	key->cbObj->CancelOperation(op_key, bytes_status);
+    }
+    return PJ_SUCCESS;
+}
+
+
+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
+/**
+ * Instruct I/O Queue to accept incoming connection on the specified 
+ * listening socket.
+ */
+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 )
+{
+    
+    return key->cbObj->StartAccept(op_key, new_sock, local, remote, addrlen);
+}
+
+
+/*
+ * Initiate non-blocking socket connect.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
+					const pj_sockaddr_t *addr,
+					int addrlen )
+{
+    PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL);
+
+    RSocket &rSock = key->cbObj->get_pj_socket()->Socket();
+    TInetAddr inetAddr;
+    PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr);
+    TRequestStatus reqStatus;
+
+    // We don't support async connect for now.
+    PJ_TODO(IOQUEUE_SUPPORT_ASYNC_CONNECT);
+
+    rSock.Connect(inetAddr, reqStatus);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus == KErrNone)
+	return PJ_SUCCESS;
+
+    return PJ_RETURN_OS_ERROR(reqStatus.Int());
+}
+
+
+#endif	/* PJ_HAS_TCP */
+
+/*
+ * Poll the I/O Queue for completed events.
+ */
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioq,
+			     const pj_time_val *timeout)
+{
+    CPjTimeoutTimer *timer;
+
+    if (timeout) {
+	//if (!ioq->timeoutTimer->IsActive())
+	if (0)
+	    timer = ioq->timeoutTimer;
+	else
+	    timer = CPjTimeoutTimer::NewL();
+
+	timer->StartTimer(timeout->sec*1000 + timeout->msec);
+
+    } else {
+	timer = NULL;
+    }
+
+    ioq->eventCount = 0;
+
+    do {
+	PjSymbianOS::Instance()->WaitForActiveObjects();
+    } while (ioq->eventCount == 0 && (!timer || (timer && !timer->HasTimedOut())));
+
+    if (timer && !timer->HasTimedOut())
+	timer->Cancel();
+
+    if (timer && timer != ioq->timeoutTimer)
+	delete timer;
+
+    return ioq->eventCount;
+}
+
+
+/*
+ * Instruct the I/O Queue to read from the specified handle.
+ */
+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 )
+{
+    // Clear flag
+    flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
+    return key->cbObj->StartRead(op_key, buffer, length, flags, NULL, NULL);
+}
+
+
+/*
+ * 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.
+ */
+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)
+{
+    if (key->cbObj->IsActive())
+	return PJ_EBUSY;
+
+    // Clear flag
+    flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
+    return key->cbObj->StartRead(op_key, buffer, length, flags, addr, addrlen);
+}
+
+
+/*
+ * Instruct the I/O Queue to write to the handle.
+ */
+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 )
+{
+    TRequestStatus reqStatus;
+    TPtrC8 aBuffer((const TUint8*)data, (TInt)*length);
+    TSockXfrLength aLen;
+    
+    PJ_UNUSED_ARG(op_key);
+
+    // Forcing pending operation is not supported.
+    PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
+
+    // Clear flag
+    flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
+
+    key->cbObj->get_pj_socket()->Socket().Send(aBuffer, flags, reqStatus, aLen);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus.Int() != KErrNone)
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+
+    //At least in UIQ Emulator, aLen.Length() reports incorrect length
+    //for UDP (some newlc.com users seem to have reported this too).
+    //*length = aLen.Length();
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Instruct the I/O Queue to write to the handle.
+ */
+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)
+{
+    TRequestStatus reqStatus;
+    TPtrC8 aBuffer;
+    TInetAddr inetAddr;
+    TSockXfrLength aLen;
+    
+    PJ_UNUSED_ARG(op_key);
+
+    // Forcing pending operation is not supported.
+    PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL);
+
+    // Must be pj_sockaddr_in for now.
+    PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL);
+
+    // Clear flag
+    flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC;
+
+    aBuffer.Set((const TUint8*)data, (TInt)*length);
+    PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr);
+    CPjSocket *pjSock = key->cbObj->get_pj_socket();
+
+    pjSock->Socket().SendTo(aBuffer, inetAddr, flags, reqStatus, aLen);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus.Int() != KErrNone)
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+
+    //At least in UIQ Emulator, aLen.Length() reports incorrect length
+    //for UDP (some newlc.com users seem to have reported this too).
+    //*length = aLen.Length();
+    return PJ_SUCCESS;
+}
+
diff --git a/pjlib/src/pj/lock.c b/pjlib/src/pj/lock.c
index 8c2c8b3..9c0a7fa 100644
--- a/pjlib/src/pj/lock.c
+++ b/pjlib/src/pj/lock.c
@@ -64,7 +64,7 @@
 
     PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
 
-    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
+    p_lock = PJ_POOL_ALLOC_T(pool, pj_lock_t);
     if (!p_lock)
 	return PJ_ENOMEM;
 
@@ -152,7 +152,7 @@
 
     PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
 
-    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
+    p_lock = PJ_POOL_ALLOC_T(pool, pj_lock_t);
     if (!p_lock)
 	return PJ_ENOMEM;
 
diff --git a/pjlib/src/pj/log_writer_symbian_console.cpp b/pjlib/src/pj/log_writer_symbian_console.cpp
new file mode 100644
index 0000000..03ad9ed
--- /dev/null
+++ b/pjlib/src/pj/log_writer_symbian_console.cpp
@@ -0,0 +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 
+ */
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/unicode.h>
+
+#include "os_symbian.h"
+#include <e32cons.h>
+
+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
+{
+#if 0
+    wchar_t wbuffer[PJ_LOG_MAX_SIZE];
+    CConsoleBase *cons = PjSymbianOS::Instance->Console();
+
+    pj_ansi_to_unicode(buffer, len, wbuffer, PJ_ARRAY_SIZE(wbuffer));
+
+    
+    TPtrC16 aPtr((TUint16*)wbuffer, len);
+    console->Write(aPtr);
+#else
+    PJ_UNUSED_ARG(level);
+    PJ_UNUSED_ARG(buffer);
+    PJ_UNUSED_ARG(len);
+#endif
+}
+
diff --git a/pjlib/src/pj/os_core_symbian.cpp b/pjlib/src/pj/os_core_symbian.cpp
new file mode 100644
index 0000000..7386fd6
--- /dev/null
+++ b/pjlib/src/pj/os_core_symbian.cpp
@@ -0,0 +1,816 @@
+/* $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/except.h>
+#include <pj/errno.h>
+
+#include "os_symbian.h"
+
+
+#define PJ_MAX_TLS	    32
+#define DUMMY_MUTEX	    ((pj_mutex_t*)101)
+#define DUMMY_SEMAPHORE	    ((pj_sem_t*)102)
+#define THIS_FILE	    "os_core_symbian.c"
+ 
+/*
+ * Note:
+ *
+ * The Symbian implementation does not support threading!
+ */ 
+
+struct pj_thread_t
+{
+    char	    obj_name[PJ_MAX_OBJ_NAME];
+    void	   *tls_values[PJ_MAX_TLS];
+
+#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
+
+} main_thread;
+
+struct pj_atomic_t
+{
+    pj_atomic_value_t	value;
+};
+
+struct pj_sem_t
+{
+    int value;
+    int max;
+};
+
+/* Flags to indicate which TLS variables have been used */
+static int tls_vars[PJ_MAX_TLS];
+
+/* atexit handlers */
+static unsigned atexit_count;
+static void (*atexit_func[32])(void);
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// CPjTimeoutTimer implementation
+//
+
+CPjTimeoutTimer::CPjTimeoutTimer()
+: CActive(EPriorityNormal), hasTimedOut_(PJ_FALSE)
+{
+}
+
+CPjTimeoutTimer::~CPjTimeoutTimer()
+{
+    if (IsActive())
+	Cancel();
+    timer_.Close();
+}
+
+void CPjTimeoutTimer::ConstructL()
+{
+    hasTimedOut_ = PJ_FALSE;
+    timer_.CreateLocal();
+    CActiveScheduler::Add(this);
+}
+
+CPjTimeoutTimer *CPjTimeoutTimer::NewL()
+{
+    CPjTimeoutTimer *self = new CPjTimeoutTimer;
+    CleanupStack::PushL(self);
+
+    self->ConstructL();
+
+    CleanupStack::Pop(self);
+    return self;
+
+}
+
+void CPjTimeoutTimer::StartTimer(TUint miliSeconds)
+{
+    if (IsActive())
+	Cancel();
+
+    hasTimedOut_ = PJ_FALSE;
+    timer_.After(iStatus, miliSeconds * 1000);
+    SetActive();
+
+    pj_assert(iStatus==KRequestPending);
+}
+
+bool CPjTimeoutTimer::HasTimedOut() const
+{
+    return hasTimedOut_ != 0;
+}
+
+void CPjTimeoutTimer::RunL()
+{
+    hasTimedOut_ = PJ_TRUE;
+}
+
+void CPjTimeoutTimer::DoCancel()
+{
+    timer_.Cancel();
+}
+
+TInt CPjTimeoutTimer::RunError(TInt aError)
+{
+    PJ_UNUSED_ARG(aError);
+    return KErrNone;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PjSymbianOS implementation
+//
+
+PjSymbianOS::PjSymbianOS()
+: isSocketServInitialized_(false), isResolverInitialized_(false),
+  console_(NULL), selectTimeoutTimer_(NULL)
+{
+}
+
+// Get PjSymbianOS instance
+PjSymbianOS *PjSymbianOS::Instance()
+{
+    static PjSymbianOS instance_;
+    return &instance_;
+}
+
+
+// Initialize
+TInt PjSymbianOS::Initialize()
+{
+    TInt err;
+
+    selectTimeoutTimer_ = CPjTimeoutTimer::NewL();
+
+#if 0
+    pj_assert(console_ == NULL);
+    TRAPD(err, console_ = Console::NewL(_L("PJLIB"), 
+				        TSize(KConsFullScreen,KConsFullScreen)));
+    return err;
+#endif
+
+    if (!isSocketServInitialized_) {
+	err = socketServ_.Connect();
+	if (err != KErrNone)
+	    goto on_error;
+
+	isSocketServInitialized_ = true;
+    }
+
+    if (!isResolverInitialized_) {
+	err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream);
+	if (err != KErrNone)
+	    goto on_error;
+
+	isResolverInitialized_ = true;
+    }
+
+    return KErrNone;
+
+on_error:
+    Shutdown();
+    return err;
+}
+
+// Shutdown
+void PjSymbianOS::Shutdown()
+{
+    if (isResolverInitialized_) {
+	hostResolver_.Close();
+	isResolverInitialized_ = false;
+    }
+
+    if (isSocketServInitialized_) {
+	socketServ_.Close();
+	isSocketServInitialized_ = false;
+    }
+
+    if (console_) {
+	delete console_;
+	console_ = NULL;
+    }
+
+    if (selectTimeoutTimer_) {
+	delete selectTimeoutTimer_;
+	selectTimeoutTimer_ = NULL;
+    }
+}
+
+// Convert to Unicode
+TInt PjSymbianOS::ConvertToUnicode(TDes16 &aUnicode, const TDesC8 &aForeign)
+{
+#if 0
+    pj_assert(conv_ != NULL);
+    return conv_->ConvertToUnicode(aUnicode, aForeign, convToUnicodeState_);
+#else
+    return CnvUtfConverter::ConvertToUnicodeFromUtf8(aUnicode, aForeign);
+#endif
+}
+
+// Convert from Unicode
+TInt PjSymbianOS::ConvertFromUnicode(TDes8 &aForeign, const TDesC16 &aUnicode)
+{
+#if 0
+    pj_assert(conv_ != NULL);
+    return conv_->ConvertFromUnicode(aForeign, aUnicode, convToAnsiState_);
+#else
+    return CnvUtfConverter::ConvertFromUnicodeToUtf8(aForeign, aUnicode);
+#endif
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PJLIB os.h implementation
+//
+
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+    return 0;
+}
+
+
+PJ_DECL(void) pj_shutdown(void);
+
+/*
+ * pj_init(void).
+ * Init PJLIB!
+ */
+PJ_DEF(pj_status_t) pj_init(void)
+{
+    pj_ansi_strcpy(main_thread.obj_name, "pjthread");
+
+    // Init main thread
+    pj_memset(&main_thread, 0, sizeof(main_thread));
+
+    // Initialize PjSymbianOS instance
+    PjSymbianOS *os = PjSymbianOS::Instance();
+
+    PJ_LOG(4,(THIS_FILE, "Initializing PJLIB for Symbian OS.."));
+
+    TInt err;
+    err = os->Initialize();
+    if (err != KErrNone)
+	goto on_error;
+
+    PJ_LOG(5,(THIS_FILE, "PJLIB initialized."));
+    return PJ_SUCCESS;
+
+on_error:
+    pj_shutdown();
+    return PJ_RETURN_OS_ERROR(err);
+}
+
+
+PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
+{
+    if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
+	return PJ_ETOOMANY;
+
+    atexit_func[atexit_count++] = func;
+    return PJ_SUCCESS;
+}
+
+
+
+PJ_DEF(void) pj_shutdown(void)
+{
+    unsigned i;
+
+    /* Call atexit() functions */
+    for (i=atexit_count-1; i>=0; --i) {
+	(*atexit_func[i])();
+    }
+    atexit_count = 0;
+
+    /* Free exception ID */
+    if (PJ_NO_MEMORY_EXCEPTION != -1) {
+	pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
+	PJ_NO_MEMORY_EXCEPTION = -1;
+    }
+
+    /* Clear static variables */
+    pj_errno_clear_handlers();
+
+    PjSymbianOS *os = PjSymbianOS::Instance();
+    os->Shutdown();
+}
+
+
+/*
+ * 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)
+{
+    PJ_UNUSED_ARG(cstr_thread_name);
+    PJ_UNUSED_ARG(desc);
+    PJ_UNUSED_ARG(thread_ptr);
+    return PJ_EINVALIDOP;
+}
+
+
+/*
+ * 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)
+{
+    PJ_UNUSED_ARG(pool);
+    PJ_UNUSED_ARG(thread_name);
+    PJ_UNUSED_ARG(proc);
+    PJ_UNUSED_ARG(arg);
+    PJ_UNUSED_ARG(stack_size);
+    PJ_UNUSED_ARG(flags);
+    PJ_UNUSED_ARG(ptr_thread);
+
+    /* Sorry mate, we don't support threading */
+    return PJ_ENOTSUP;
+}
+
+/*
+ * pj_thread-get_name()
+ */
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
+{
+    pj_assert(p == &main_thread);
+    return p->obj_name;
+}
+
+/*
+ * pj_thread_resume()
+ */
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
+{
+    PJ_UNUSED_ARG(p);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_thread_this()
+ */
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+    return &main_thread;
+}
+
+/*
+ * pj_thread_join()
+ */
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *rec)
+{
+    PJ_UNUSED_ARG(rec);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_thread_destroy()
+ */
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *rec)
+{
+    PJ_UNUSED_ARG(rec);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * pj_thread_sleep()
+ */
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+    //Not a good idea, as we don't want network events to
+    //arrive while we're not polling them:
+    //PjSymbianOS::Instance()->WaitForActiveObjects();
+
+    //.. so rather use this, which won't wake up Active Objects:
+    User::After(msec*1000);
+
+    return PJ_SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * pj_thread_local_alloc()
+ */
+
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
+{
+    unsigned i;
+
+    /* Find unused TLS variable */
+    for (i=0; i<PJ_ARRAY_SIZE(tls_vars); ++i) {
+	if (tls_vars[i] == 0)
+	    break;
+    }
+
+    if (i == PJ_ARRAY_SIZE(tls_vars))
+	return PJ_ETOOMANY;
+
+    tls_vars[i] = 1;
+    *index = i;
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_local_free()
+ */
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+    PJ_ASSERT_ON_FAIL(index >= 0 && index < PJ_ARRAY_SIZE(tls_vars) &&
+		     tls_vars[index] != 0, return);
+
+    tls_vars[index] = 0;
+}
+
+
+/*
+ * pj_thread_local_set()
+ */
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+    pj_thread_t *rec = pj_thread_this();
+
+    PJ_ASSERT_RETURN(index >= 0 && index < PJ_ARRAY_SIZE(tls_vars) &&
+		     tls_vars[index] != 0, PJ_EINVAL);
+
+    rec->tls_values[index] = value;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_thread_local_get()
+ */
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+    pj_thread_t *rec = pj_thread_this();
+
+    PJ_ASSERT_RETURN(index >= 0 && index < PJ_ARRAY_SIZE(tls_vars) &&
+		     tls_vars[index] != 0, NULL);
+
+    return rec->tls_values[index];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Create atomic variable.
+ */
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
+				      pj_atomic_value_t initial,
+				      pj_atomic_t **atomic )
+{
+    *atomic = (pj_atomic_t*)pj_pool_alloc(pool, sizeof(struct pj_atomic_t));
+    (*atomic)->value = initial;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Destroy atomic variable.
+ */
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
+{
+    PJ_UNUSED_ARG(atomic_var);
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set the value of an atomic type, and return the previous value.
+ */
+PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, 
+			    pj_atomic_value_t value)
+{
+    atomic_var->value = value;
+}
+
+
+/*
+ * Get the value of an atomic type.
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
+{
+    return atomic_var->value;
+}
+
+
+/*
+ * Increment the value of an atomic type.
+ */
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
+{
+    ++atomic_var->value;
+}
+
+
+/*
+ * Increment the value of an atomic type and get the result.
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
+{
+    return ++atomic_var->value;
+}
+
+
+/*
+ * Decrement the value of an atomic type.
+ */
+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
+{
+    --atomic_var->value;
+}	
+
+
+/*
+ * Decrement the value of an atomic type and get the result.
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
+{
+    return --atomic_var->value;
+}
+
+
+/*
+ * Add a value to an atomic type.
+ */
+PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
+			    pj_atomic_value_t value)
+{
+    atomic_var->value += value;
+}
+
+
+/*
+ * Add a value to an atomic type and get the result.
+ */
+PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
+			                         pj_atomic_value_t value)
+{
+    atomic_var->value += value;
+    return atomic_var->value;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool, 
+                                     const char *name,
+				     int type, 
+                                     pj_mutex_t **mutex)
+{
+    PJ_UNUSED_ARG(pool);
+    PJ_UNUSED_ARG(name);
+    PJ_UNUSED_ARG(type);
+
+    *mutex = DUMMY_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_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_assert(mutex == DUMMY_MUTEX);
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_mutex_trylock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+    pj_assert(mutex == DUMMY_MUTEX);
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_mutex_unlock()
+ */
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+    pj_assert(mutex == DUMMY_MUTEX);
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_mutex_destroy()
+ */
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+    pj_assert(mutex == DUMMY_MUTEX);
+    return PJ_SUCCESS;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+/*
+ * RW Mutex
+ */
+#include "os_rwmutex.c"
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Enter critical section.
+ */
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+    /* Nothing to do */
+}
+
+
+/*
+ * Leave critical section.
+ */
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+    /* Nothing to do */
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Create semaphore.
+ */
+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 
+                                   const char *name,
+				   unsigned initial, 
+                                   unsigned max,
+				   pj_sem_t **p_sem)
+{
+    pj_sem_t *sem;
+ 
+    PJ_UNUSED_ARG(name);
+
+    sem = (pj_sem_t*) pj_pool_zalloc(pool, sizeof(pj_sem_t));
+    sem->value = initial;
+    sem->max = max;
+
+    *p_sem = sem;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Wait for semaphore.
+ */
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+    if (sem->value > 0) {
+	sem->value--;
+	return PJ_SUCCESS;
+    } else {
+	pj_assert(!"Unexpected!");
+	return PJ_EINVALIDOP;
+    }
+}
+
+
+/*
+ * Try wait for semaphore.
+ */
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+    if (sem->value > 0) {
+	sem->value--;
+	return PJ_SUCCESS;
+    } else {
+	pj_assert(!"Unexpected!");
+	return PJ_EINVALIDOP;
+    }
+}
+
+
+/*
+ * Release semaphore.
+ */
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+    sem->value++;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Destroy semaphore.
+ */
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+    PJ_UNUSED_ARG(sem);
+    return PJ_SUCCESS;
+}
+
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
+/*
+ * The implementation of stack checking. 
+ */
+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;
+    }
+}
+
+/*
+ * Get maximum stack usage statistic. 
+ */
+PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
+{
+    return thread->stk_max_usage;
+}
+
+/*
+ * Dump thread stack status. 
+ */
+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 */
diff --git a/pjlib/src/pj/os_error_symbian.cpp b/pjlib/src/pj/os_error_symbian.cpp
new file mode 100644
index 0000000..dcacf28
--- /dev/null
+++ b/pjlib/src/pj/os_error_symbian.cpp
@@ -0,0 +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 
+ */
+#include <pj/errno.h>
+#include <pj/assert.h>
+#include <pj/compat/stdarg.h>
+#include <pj/unicode.h>
+#include <pj/string.h>
+
+#include <e32err.h>
+#include <in_sock.h>
+
+
+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING!=0)
+static const struct {
+    pj_os_err_type code;
+    const char *msg;
+} gaErrorList[] = {
+    /*
+     * Generic error -1 to -46
+     */
+    PJ_BUILD_ERR( KErrNotFound,	    "Unable to find the specified object"),
+    PJ_BUILD_ERR( KErrGeneral,	    "General (unspecified) error"),
+    PJ_BUILD_ERR( KErrCancel,	    "The operation was cancelled"),
+    PJ_BUILD_ERR( KErrNoMemory,	    "Not enough memory"),
+    PJ_BUILD_ERR( KErrNotSupported, "The operation requested is not supported"),
+    PJ_BUILD_ERR( KErrArgument,	    "Bad request"),
+    PJ_BUILD_ERR( KErrTotalLossOfPrecision, "Total loss of precision"),
+    PJ_BUILD_ERR( KErrBadHandle,    "Bad object"),
+    PJ_BUILD_ERR( KErrOverflow,	    "Overflow"),
+    PJ_BUILD_ERR( KErrUnderflow,    "Underflow"),
+    PJ_BUILD_ERR( KErrAlreadyExists,"Already exists"),
+    PJ_BUILD_ERR( KErrPathNotFound, "Unable to find the specified folder"),
+    PJ_BUILD_ERR( KErrDied,	    "Closed"),
+    PJ_BUILD_ERR( KErrInUse,	    "The specified object is currently in use by another program"),
+    PJ_BUILD_ERR( KErrServerTerminated,	    "Server has closed"),
+    PJ_BUILD_ERR( KErrServerBusy,   "Server busy"),
+    PJ_BUILD_ERR( KErrCompletion,   "Completion error"),
+    PJ_BUILD_ERR( KErrNotReady,	    "Not ready"),
+    PJ_BUILD_ERR( KErrUnknown,	    "Unknown error"),
+    PJ_BUILD_ERR( KErrCorrupt,	    "Corrupt"),
+    PJ_BUILD_ERR( KErrAccessDenied, "Access denied"),
+    PJ_BUILD_ERR( KErrLocked,	    "Locked"),
+    PJ_BUILD_ERR( KErrWrite,	    "Failed to write"),
+    PJ_BUILD_ERR( KErrDisMounted,   "Wrong disk present"),
+    PJ_BUILD_ERR( KErrEof,	    "Unexpected end of file"),
+    PJ_BUILD_ERR( KErrDiskFull,	    "Disk full"),
+    PJ_BUILD_ERR( KErrBadDriver,    "Bad device driver"),
+    PJ_BUILD_ERR( KErrBadName,	    "Bad name"),
+    PJ_BUILD_ERR( KErrCommsLineFail,"Comms line failed"),
+    PJ_BUILD_ERR( KErrCommsFrame,   "Comms frame error"),
+    PJ_BUILD_ERR( KErrCommsOverrun, "Comms overrun error"),
+    PJ_BUILD_ERR( KErrCommsParity,  "Comms parity error"),
+    PJ_BUILD_ERR( KErrTimedOut,	    "Timed out"),
+    PJ_BUILD_ERR( KErrCouldNotConnect, "Failed to connect"),
+    PJ_BUILD_ERR( KErrCouldNotDisconnect, "Failed to disconnect"),
+    PJ_BUILD_ERR( KErrDisconnected, "Disconnected"),
+    PJ_BUILD_ERR( KErrBadLibraryEntryPoint, "Bad library entry point"),
+    PJ_BUILD_ERR( KErrBadDescriptor,"Bad descriptor"),
+    PJ_BUILD_ERR( KErrAbort,	    "Interrupted"),
+    PJ_BUILD_ERR( KErrTooBig,	    "Too big"),
+    PJ_BUILD_ERR( KErrDivideByZero, "Divide by zero"),
+    PJ_BUILD_ERR( KErrBadPower,	    "Batteries too low"),
+    PJ_BUILD_ERR( KErrDirFull,	    "Folder full"),
+    PJ_BUILD_ERR( KErrHardwareNotAvailable, ""),
+    PJ_BUILD_ERR( KErrSessionClosed,	    ""),
+    PJ_BUILD_ERR( KErrPermissionDenied,     ""),
+
+    /*
+     * Socket errors (-190 - -1000)
+     */
+    PJ_BUILD_ERR( KErrNetUnreach,   "Could not connect to the network. Currently unreachable"),
+    PJ_BUILD_ERR( KErrHostUnreach,  "Could not connect to the specified server"),
+    PJ_BUILD_ERR( KErrNoProtocolOpt,"The specified server refuses the selected protocol"),
+    PJ_BUILD_ERR( KErrUrgentData,   ""),
+    PJ_BUILD_ERR( KErrWouldBlock,   "Conflicts with KErrExtended, but cannot occur in practice"),
+
+    {0, NULL}
+};
+
+#endif	/* PJ_HAS_ERROR_STRING */
+
+
+PJ_DEF(pj_status_t) pj_get_os_error(void)
+{
+    return -1;
+}
+
+PJ_DEF(void) pj_set_os_error(pj_status_t code)
+{
+    PJ_UNUSED_ARG(code);
+}
+
+PJ_DEF(pj_status_t) pj_get_netos_error(void)
+{
+    return -1;
+}
+
+PJ_DEF(void) pj_set_netos_error(pj_status_t code)
+{
+    PJ_UNUSED_ARG(code);
+}
+
+PJ_BEGIN_DECL
+
+    PJ_DECL(int) platform_strerror( pj_os_err_type os_errcode, 
+                       		    char *buf, pj_size_t bufsize);
+PJ_END_DECL
+
+/* 
+ * platform_strerror()
+ *
+ * Platform specific error message. This file is called by pj_strerror() 
+ * in errno.c 
+ */
+PJ_DEF(int) platform_strerror( pj_os_err_type os_errcode, 
+			       char *buf, pj_size_t bufsize)
+{
+    int len = 0;
+
+    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();
+     */
+
+    if (!len) {
+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING!=0)
+	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;
+            }
+        }
+#endif	/* PJ_HAS_ERROR_STRING */
+
+    }
+
+    if (!len) {
+	len = pj_ansi_snprintf( buf, bufsize, "Symbian native error %d", 
+				os_errcode);
+	buf[len] = '\0';
+    }
+
+    return len;
+}
+
diff --git a/pjlib/src/pj/os_rwmutex.c b/pjlib/src/pj/os_rwmutex.c
index 05728da..27bc5ad 100644
--- a/pjlib/src/pj/os_rwmutex.c
+++ b/pjlib/src/pj/os_rwmutex.c
@@ -56,7 +56,7 @@
     PJ_ASSERT_RETURN(pool && p_mutex, PJ_EINVAL);
 
     *p_mutex = NULL;
-    rwmutex = pj_pool_alloc(pool, sizeof(struct pj_rwmutex_t));
+    rwmutex = PJ_POOL_ALLOC_T(pool, pj_rwmutex_t);
 
     status = pj_mutex_create_simple(pool, name, &rwmutex ->read_lock);
     if (status != PJ_SUCCESS)
diff --git a/pjlib/src/pj/os_symbian.h b/pjlib/src/pj/os_symbian.h
new file mode 100644
index 0000000..0697310
--- /dev/null
+++ b/pjlib/src/pj/os_symbian.h
@@ -0,0 +1,302 @@
+/* $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 __OS_SYMBIAN_H__
+#define __OS_SYMBIAN_H__
+
+#include <pj/sock.h>
+
+#include <e32base.h>
+#include <e32cmn.h>
+#include <e32std.h>
+#include <ES_SOCK.H>
+#include <in_sock.h>
+#include <CHARCONV.H>
+#include <utf.h>
+#include <e32cons.h>
+
+// Forward declarations
+class CPjSocketReader;
+
+//
+// PJLIB Symbian's Socket
+//
+class CPjSocket
+{
+public:
+    enum
+    {
+	MAX_LEN = 1500,
+    };
+
+    // Construct CPjSocket
+    CPjSocket(RSocket &sock)
+	: sock_(sock), connected_(false), sockReader_(NULL)
+    { 
+    }
+
+    // Destroy CPjSocket
+    ~CPjSocket();
+
+    // Get the internal RSocket
+    RSocket& Socket()
+    {
+	return sock_;
+    }
+
+    // Get socket connected flag.
+    bool IsConnected() const
+    {
+	return connected_;
+    }
+
+    // Set socket connected flag.
+    void SetConnected(bool connected)
+    {
+	connected_ = connected;
+    }
+
+    // Get socket reader, if any.
+    // May return NULL.
+    CPjSocketReader *Reader()
+    {
+	return sockReader_;
+    }
+
+    // Create socket reader.
+    CPjSocketReader *CreateReader(unsigned max_len=CPjSocket::MAX_LEN);
+
+private:
+    RSocket	     sock_;	    // Must not be reference, or otherwise
+				    // it may point to local variable!
+    bool	     connected_;
+    CPjSocketReader *sockReader_;
+};
+
+
+//
+// Socket reader, used by select() and ioqueue abstraction
+//
+class CPjSocketReader : public CActive
+{
+public:
+    // Construct.
+    static CPjSocketReader *NewL(CPjSocket &sock, unsigned max_len=CPjSocket::MAX_LEN);
+
+    // Destroy;
+    ~CPjSocketReader();
+
+    // Start asynchronous read from the socket.
+    void StartRecv(void (*cb)(void *key)=NULL, 
+		   void *key=NULL, 
+		   TDes8 *aDesc = NULL,
+		   TUint flags = 0);
+
+    // Start asynchronous read from the socket.
+    void StartRecvFrom(void (*cb)(void *key)=NULL, 
+		       void *key=NULL, 
+		       TDes8 *aDesc = NULL,
+		       TUint flags = 0,
+		       TSockAddr *fromAddr = NULL);
+
+    // Cancel asynchronous read.
+    void DoCancel();
+
+    // Implementation: called when read has completed.
+    void RunL();
+
+    // Check if there's pending data.
+    bool HasData() const
+    {
+	return buffer_.Length() != 0;
+    }
+
+    // Append data to aDesc, up to aDesc's maximum size.
+    // If socket is datagram based, buffer_ will be clared.
+    void ReadData(TDes8 &aDesc, TInetAddr *addr=NULL);
+
+private:
+    CPjSocket	   &sock_;
+    bool	    isDatagram_;
+    TPtr8	    buffer_;
+    TInetAddr	    recvAddr_;
+
+    void	   (*readCb_)(void *key);
+    void	    *key_;
+
+    //
+    // Constructor
+    //
+    CPjSocketReader(CPjSocket &sock);
+    void ConstructL(unsigned max_len);
+};
+
+
+
+//
+// Time-out Timer Active Object
+//
+class CPjTimeoutTimer : public CActive
+{
+public:
+    static CPjTimeoutTimer *NewL();
+    ~CPjTimeoutTimer();
+
+    void StartTimer(TUint miliSeconds);
+    bool HasTimedOut() const;
+
+protected:
+    virtual void RunL();
+    virtual void DoCancel();
+    virtual TInt RunError(TInt aError);
+
+private:
+    RTimer	timer_;
+    pj_bool_t	hasTimedOut_;
+
+    CPjTimeoutTimer();
+    void ConstructL();
+};
+
+
+
+//
+// Symbian OS helper for PJLIB
+//
+class PjSymbianOS
+{
+public:
+    //
+    // Construct PjSymbianOS instance.
+    //
+    static PjSymbianOS *NewL();
+
+    //
+    // Get the singleton instance of PjSymbianOS
+    //
+    static PjSymbianOS *Instance();
+
+    //
+    // Initialize.
+    //
+    TInt Initialize();
+
+    //
+    // Shutdown.
+    //
+    void Shutdown();
+
+
+    //
+    // Socket helper.
+    //
+
+    // Get RSocketServ instance to be used by all sockets.
+    RSocketServ &SocketServ()
+    {
+	return socketServ_;
+    }
+
+    // Convert TInetAddr to pj_sockaddr_in
+    static inline void Addr2pj(const TInetAddr & sym_addr,
+			       pj_sockaddr_in &pj_addr)
+    {
+	memset(&pj_addr, 0, sizeof(pj_sockaddr_in));
+	pj_addr.sin_family = PJ_AF_INET;
+	pj_addr.sin_addr.s_addr = sym_addr.Address();
+	pj_addr.sin_port = (pj_uint16_t) sym_addr.Port();
+    }
+
+
+    // Convert pj_sockaddr_in to TInetAddr
+    static inline void pj2Addr(const pj_sockaddr_in &pj_addr,
+			       TInetAddr & sym_addr)
+    {
+	sym_addr.Init(KAfInet);
+	sym_addr.SetAddress((TUint32)pj_addr.sin_addr.s_addr);
+	sym_addr.SetPort(pj_addr.sin_port);
+    }
+
+
+    //
+    // Resolver helper
+    //
+
+    // Get RHostResolver instance
+    RHostResolver & GetResolver()
+    {
+	return hostResolver_;
+    }
+
+
+    //
+    // Unicode Converter
+    //
+
+    // Convert to Unicode
+    TInt ConvertToUnicode(TDes16 &aUnicode, const TDesC8 &aForeign);
+
+    // Convert from Unicode
+    TInt ConvertFromUnicode(TDes8 &aForeign, const TDesC16 &aUnicode);
+
+    //
+    // Get console
+    //
+    
+    // Get console
+    CConsoleBase *Console()
+    {
+	return console_;
+    }
+    
+    //
+    // Get select() timeout timer.
+    //
+    CPjTimeoutTimer *SelectTimeoutTimer()
+    {
+	return selectTimeoutTimer_;
+    }
+
+    //
+    // Wait for any active objects to run.
+    //
+    void WaitForActiveObjects(TInt aPriority = CActive::EPriorityStandard)
+    {
+	TInt aError;
+	User::WaitForAnyRequest();
+	CActiveScheduler::RunIfReady(aError, aPriority);
+    }
+
+private:
+    bool isSocketServInitialized_;
+    RSocketServ socketServ_;
+
+    bool isResolverInitialized_;
+    RHostResolver hostResolver_;
+
+    CConsoleBase* console_;
+
+    CPjTimeoutTimer *selectTimeoutTimer_;
+
+private:
+    PjSymbianOS();
+};
+
+
+#endif	/* __OS_SYMBIAN_H__ */
+
diff --git a/pjlib/src/pj/pool.c b/pjlib/src/pj/pool.c
index 02b71ed..9f47892 100644
--- a/pjlib/src/pj/pool.c
+++ b/pjlib/src/pj/pool.c
@@ -170,7 +170,7 @@
 {
     pj_pool_t *pool;
     pj_pool_block *block;
-    unsigned char *buffer;
+    pj_uint8_t *buffer;
 
     PJ_CHECK_STACK();
 
@@ -183,7 +183,7 @@
 	callback = f->policy.callback;
 
     /* Allocate initial block */
-    buffer = (*f->policy.block_alloc)(f, initial_size);
+    buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
     if (!buffer)
 	return NULL;
 
diff --git a/pjlib/src/pj/pool_buf.c b/pjlib/src/pj/pool_buf.c
index f6f294b..08885ea 100644
--- a/pjlib/src/pj/pool_buf.c
+++ b/pjlib/src/pj/pool_buf.c
@@ -57,7 +57,7 @@
 
     PJ_UNUSED_ARG(factory);
 
-    param = pj_thread_local_get(tls);
+    param = (struct creation_param*) pj_thread_local_get(tls);
     if (param == NULL) {
 	/* Don't assert(), this is normal no-memory situation */
 	return NULL;
diff --git a/pjlib/src/pj/pool_caching.c b/pjlib/src/pj/pool_caching.c
index 35bc580..b00bf10 100644
--- a/pjlib/src/pj/pool_caching.c
+++ b/pjlib/src/pj/pool_caching.c
@@ -85,7 +85,7 @@
 
     /* 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 *pool = (pj_pool_t*) cp->free_list[i].next;
 	pj_pool_t *next;
 	for (; pool != (void*)&cp->free_list[i]; pool = next) {
 	    next = pool->next;
@@ -95,7 +95,7 @@
     }
 
     /* Delete all pools in used list */
-    pool = cp->used_list.next;
+    pool = (pj_pool_t*) cp->used_list.next;
     while (pool != (pj_pool_t*) &cp->used_list) {
 	pj_pool_t *next = pool->next;
 	pj_list_erase(pool);
@@ -164,7 +164,7 @@
 
     } else {
 	/* Get one pool from the list. */
-	pool = cp->free_list[idx].next;
+	pool = (pj_pool_t*) cp->free_list[idx].next;
 	pj_list_erase(pool);
 
 	/* Initialize the pool. */
@@ -257,7 +257,7 @@
     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_pool_t *pool = (pj_pool_t*) 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) {
diff --git a/pjlib/src/pj/pool_policy_new.cpp b/pjlib/src/pj/pool_policy_new.cpp
new file mode 100644
index 0000000..367be0f
--- /dev/null
+++ b/pjlib/src/pj/pool_policy_new.cpp
@@ -0,0 +1,73 @@
+/* $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>
+
+#if !PJ_HAS_POOL_ALT_API
+
+/*
+ * This file contains pool default policy definition and implementation.
+ */
+ 
+
+static void *operator_new(pj_pool_factory *factory, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(factory);
+    PJ_UNUSED_ARG(size);
+
+    return new char[size];
+}
+
+static void operator_delete(pj_pool_factory *factory, void *mem, pj_size_t size)
+{
+    PJ_CHECK_STACK();
+    PJ_UNUSED_ARG(factory);
+    PJ_UNUSED_ARG(size);
+
+    char *p = (char*)mem;
+    delete [] p;
+}
+
+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 = 
+{
+    &operator_new,
+    &operator_delete,
+    &default_pool_callback,
+    0
+};
+ 
+PJ_DEF(pj_pool_factory_policy*) pj_pool_factory_get_default_policy(void)
+{
+    return &pj_pool_factory_default_policy;
+}
+
+
+#endif	/* PJ_HAS_POOL_ALT_API */
+
diff --git a/pjlib/src/pj/sock_select_symbian.cpp b/pjlib/src/pj/sock_select_symbian.cpp
new file mode 100644
index 0000000..cf45a62
--- /dev/null
+++ b/pjlib/src/pj/sock_select_symbian.cpp
@@ -0,0 +1,162 @@
+/* $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/array.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include "os_symbian.h"
+
+ 
+struct symbian_fd_set
+{
+    unsigned	 count;
+    CPjSocket	*sock[FD_SETSIZE];
+};
+
+
+PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)
+{
+    symbian_fd_set *fds = (symbian_fd_set *)fdsetp;
+    fds->count = 0;
+}
+
+
+PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp)
+{
+    symbian_fd_set *fds = (symbian_fd_set *)fdsetp;
+
+    PJ_ASSERT_ON_FAIL(fds->count < FD_SETSIZE, return);
+    fds->sock[fds->count++] = (CPjSocket*)fd;
+}
+
+
+PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp)
+{
+    symbian_fd_set *fds = (symbian_fd_set *)fdsetp;
+    unsigned i;
+    
+    for (i=0; i<fds->count; ++i) {
+	if (fds->sock[i] == (CPjSocket*)fd) {
+	    pj_array_erase(fds->sock, sizeof(fds->sock[0]), fds->count, i);
+	    --fds->count;
+	    return;
+	}
+    }
+}
+
+
+PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp)
+{
+    symbian_fd_set *fds = (symbian_fd_set *)fdsetp;
+    unsigned i;
+    
+    for (i=0; i<fds->count; ++i) {
+	if (fds->sock[i] == (CPjSocket*)fd) {
+	    return PJ_TRUE;
+	}
+    }
+
+    return PJ_FALSE;
+}
+
+PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp)
+{
+    symbian_fd_set *fds = (symbian_fd_set *)fdsetp;
+    return fds->count;
+}
+
+
+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)
+{
+    CPjTimeoutTimer *pjTimer;
+    unsigned i;
+
+    PJ_UNUSED_ARG(n);
+    PJ_UNUSED_ARG(writefds);
+    PJ_UNUSED_ARG(exceptfds);
+
+    if (timeout) {
+	pjTimer = PjSymbianOS::Instance()->SelectTimeoutTimer();
+	pjTimer->StartTimer(timeout->sec*1000 + timeout->msec);
+
+    } else {
+	pjTimer = NULL;
+    }
+
+    /* Scan for readable sockets */
+
+    if (readfds) {
+	symbian_fd_set *fds = (symbian_fd_set *)readfds;
+
+	do {
+	    /* Scan sockets for readily available data */
+	    for (i=0; i<fds->count; ++i) {
+		CPjSocket *pjsock = fds->sock[i];
+
+		if (pjsock->Reader()) {
+		    if (pjsock->Reader()->HasData() && !pjsock->Reader()->IsActive()) {
+
+			/* Found socket with data ready */
+			PJ_FD_ZERO(readfds);
+			PJ_FD_SET((pj_sock_t)pjsock, readfds);
+
+			/* Cancel timer, if any */
+			if (pjTimer) {
+			    pjTimer->Cancel();
+			}
+
+			/* Clear writable and exception fd_set */
+			if (writefds)
+			    PJ_FD_ZERO(writefds);
+			if (exceptfds)
+			    PJ_FD_ZERO(exceptfds);
+
+			return 1;
+
+		    } else if (!pjsock->Reader()->IsActive())
+			pjsock->Reader()->StartRecvFrom();
+
+		} else {
+		    pjsock->CreateReader();
+		    pjsock->Reader()->StartRecvFrom();
+		}
+	    }
+
+	    PjSymbianOS::Instance()->WaitForActiveObjects();
+
+	} while (pjTimer==NULL || !pjTimer->HasTimedOut());
+    }
+
+
+    /* Timeout */
+
+    if (readfds)
+	PJ_FD_ZERO(readfds);
+    if (writefds)
+	PJ_FD_ZERO(writefds);
+    if (exceptfds)
+	PJ_FD_ZERO(exceptfds);
+
+    return 0;
+}
+
diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp
new file mode 100644
index 0000000..1b79098
--- /dev/null
+++ b/pjlib/src/pj/sock_symbian.cpp
@@ -0,0 +1,931 @@
+/* $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/addr_resolv.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/os.h>
+#include <pj/string.h>
+#include <pj/unicode.h>
+
+#include "os_symbian.h"
+
+
+/*
+ * Address families.
+ */
+const pj_uint16_t PJ_AF_UNIX	= 0xFFFF;
+const pj_uint16_t PJ_AF_INET	= KAfInet;
+const pj_uint16_t PJ_AF_INET6	= KAfInet6;
+const pj_uint16_t PJ_AF_PACKET	= 0xFFFF;
+const pj_uint16_t PJ_AF_IRDA	= 0xFFFF;
+
+/*
+ * Socket types conversion.
+ * The values here are indexed based on pj_sock_type
+ */
+const pj_uint16_t PJ_SOCK_STREAM= KSockStream;
+const pj_uint16_t PJ_SOCK_DGRAM	= KSockDatagram;
+const pj_uint16_t PJ_SOCK_RAW	= 0xFFFF;
+const pj_uint16_t PJ_SOCK_RDM	= 0xFFFF;
+
+/* setsockop() is not really supported. */
+const pj_uint16_t PJ_SOL_SOCKET	= 0xFFFF;
+const pj_uint16_t PJ_SOL_IP	= 0xFFFF;
+const pj_uint16_t PJ_SOL_TCP	= 0xFFFF;
+const pj_uint16_t PJ_SOL_UDP	= 0xFFFF;
+const pj_uint16_t PJ_SOL_IPV6	= 0xFFFF;
+
+/* ioctl() is also not supported. */
+const pj_uint16_t PJ_SO_TYPE    = 0xFFFF;
+const pj_uint16_t PJ_SO_RCVBUF  = 0xFFFF;
+const pj_uint16_t PJ_SO_SNDBUF  = 0xFFFF;
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// CPjSocket implementation.
+// (declaration is in os_symbian.h)
+//
+
+CPjSocket::~CPjSocket()
+{
+    if (sockReader_) {
+	if (sockReader_->IsActive())
+	    sockReader_->Cancel();
+	delete sockReader_;
+	sockReader_ = NULL;
+    }
+    sock_.Close();
+}
+
+
+// Create socket reader.
+CPjSocketReader *CPjSocket::CreateReader(unsigned max_len)
+{
+    pj_assert(sockReader_ == NULL);
+    return sockReader_ = CPjSocketReader::NewL(*this, max_len);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// CPjSocketReader implementation
+// (declaration in os_symbian.h)
+//
+
+
+CPjSocketReader::CPjSocketReader(CPjSocket &sock)
+: CActive(EPriorityStandard), 
+  sock_(sock), buffer_(NULL, 0), readCb_(NULL), key_(NULL)
+{
+}
+
+
+void CPjSocketReader::ConstructL(unsigned max_len)
+{
+    TProtocolDesc aProtocol;
+    TInt err;
+
+    err = sock_.Socket().Info(aProtocol);
+    User::LeaveIfError(err);
+
+    isDatagram_ = (aProtocol.iSockType == KSockDatagram);
+
+    TUint8 *ptr = new TUint8[max_len];
+    buffer_.Set(ptr, 0, (TInt)max_len);
+    CActiveScheduler::Add(this);
+}
+
+CPjSocketReader *CPjSocketReader::NewL(CPjSocket &sock, unsigned max_len)
+{
+    CPjSocketReader *self = new (ELeave) CPjSocketReader(sock);
+    CleanupStack::PushL(self);
+    self->ConstructL(max_len);
+    CleanupStack::Pop(self);
+
+    return self;
+}
+
+
+CPjSocketReader::~CPjSocketReader()
+{
+    const TUint8 *data = buffer_.Ptr();
+    delete [] data;
+}
+
+void CPjSocketReader::StartRecv(void (*cb)(void *key), 
+			        void *key, 
+			        TDes8 *aDesc,
+			        TUint flags)
+{
+    StartRecvFrom(cb, key, aDesc, flags, NULL);
+}
+
+void CPjSocketReader::StartRecvFrom(void (*cb)(void *key), 
+				    void *key, 
+				    TDes8 *aDesc,
+				    TUint flags,
+				    TSockAddr *fromAddr)
+{
+    readCb_ = cb;
+    key_ = key;
+
+    if (aDesc == NULL) aDesc = &buffer_;
+    if (fromAddr == NULL) fromAddr = &recvAddr_;
+
+    sock_.Socket().RecvFrom(*aDesc, *fromAddr, flags, iStatus);
+    if (iStatus == KRequestPending)
+	SetActive();
+}
+
+void CPjSocketReader::DoCancel()
+{
+    sock_.Socket().CancelRecv();
+}
+
+void CPjSocketReader::RunL()
+{
+    void (*old_cb)(void *key) = readCb_;
+    void *old_key = key_;
+    bool is_active = IsActive();
+
+    readCb_ = NULL;
+    key_ = NULL;
+
+    if (old_cb) {
+	(*old_cb)(old_key);
+    }
+}
+
+// Append data to aDesc, up to aDesc's maximum size.
+// If socket is datagram based, buffer_ will be clared.
+void CPjSocketReader::ReadData(TDes8 &aDesc, TInetAddr *addr)
+{
+    if (isDatagram_)
+	aDesc.Zero();
+
+    if (buffer_.Length() == 0)
+	return;
+
+    TInt size_to_copy = aDesc.MaxLength() - aDesc.Length();
+    if (size_to_copy > buffer_.Length())
+	size_to_copy = buffer_.Length();
+
+    aDesc.Append(buffer_.Ptr(), size_to_copy);
+
+    if (isDatagram_)
+	buffer_.Zero();
+    else
+	buffer_.Delete(0, size_to_copy);
+
+    if (addr)
+	*addr = recvAddr_;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PJLIB's sock.h implementation
+//
+
+/*
+ * Convert 16-bit value from network byte order to host byte order.
+ */
+PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
+{
+    /* There's no difference in host/network byte order in Symbian */
+    return netshort;
+}
+
+/*
+ * Convert 16-bit value from host byte order to network byte order.
+ */
+PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
+{
+    /* There's no difference in host/network byte order in Symbian */
+    return hostshort;
+}
+
+/*
+ * Convert 32-bit value from network byte order to host byte order.
+ */
+PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
+{
+    /* There's no difference in host/network byte order in Symbian */
+    return netlong;
+}
+
+/*
+ * Convert 32-bit value from host byte order to network byte order.
+ */
+PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
+{
+    /* There's no difference in host/network byte order in Symbian */
+    return 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)
+{
+    static TBuf<20> str16;
+    static char str8[20];
+
+    TInetAddr temp_addr((TUint32)inaddr.s_addr, (TUint)0);
+    temp_addr.Output(str16);
+ 
+    return pj_unicode_to_ansi(str16.PtrZ(), str16.Length(),
+			      str8, sizeof(str8));
+}
+
+/*
+ * 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)
+{
+    enum { MAXIPLEN = 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;
+    }
+
+    char tempaddr8[MAXIPLEN];
+    pj_memcpy(tempaddr8, cp->ptr, cp->slen);
+    tempaddr8[cp->slen] = '\0';
+
+    wchar_t tempaddr16[MAXIPLEN];
+    pj_ansi_to_unicode(tempaddr8, pj_ansi_strlen(tempaddr8),
+		       tempaddr16, sizeof(tempaddr16));
+
+    TBuf<MAXIPLEN> ip_addr(tempaddr16);
+
+    TInetAddr addr;
+    addr.Init(KAfInet);
+    if (addr.Input(ip_addr) == KErrNone) {
+	/* Success */
+	inp->s_addr = addr.Address();
+	return 1;
+    } else {
+	/* Error */
+	return 0;
+    }
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Convert address string with numbers and dots to binary IP address.
+ */ 
+PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp)
+{
+    pj_str_t str = pj_str((char*)cp);
+    return pj_inet_addr(&str);
+}
+
+/*
+ * 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 = PJ_AF_INET;
+    pj_memset(addr->sin_zero, 0, sizeof(addr->sin_zero));
+
+    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, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
+
+    addr->sin_family = PJ_AF_INET;
+    pj_memset(addr->sin_zero, 0, sizeof(addr->sin_zero));
+    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) {
+	RHostResolver & resv = PjSymbianOS::Instance()->GetResolver();
+	TRequestStatus reqStatus;
+	THostName tmpName;
+
+	resv.GetHostName(tmpName, reqStatus);
+	User::WaitForRequest(reqStatus);
+
+	hostname.ptr = pj_unicode_to_ansi(tmpName.Ptr(), tmpName.Length(),
+					  buf, sizeof(buf));
+	hostname.slen = tmpName.Length();
+    }
+    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 *p_sock)
+{
+    TInt rc;
+
+    PJ_CHECK_STACK();
+
+    /* Sanity checks. */
+    PJ_ASSERT_RETURN(p_sock!=NULL, PJ_EINVAL);
+
+    /* Set proto if none is specified. */
+    if (proto == 0) {
+	if (type == PJ_SOCK_STREAM)
+	    proto = KProtocolInetTcp;
+	else if (type == PJ_SOCK_DGRAM)
+	    proto = KProtocolInetUdp;
+    }
+
+    /* Create Symbian RSocket */
+    RSocket rSock;
+    rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(), af, type, proto);
+    if (rc != KErrNone)
+	return PJ_RETURN_OS_ERROR(rc);
+
+
+    /* Wrap Symbian RSocket into PJLIB's CPjSocket, and return to caller */
+    CPjSocket *pjSock = new CPjSocket(rSock);
+    *p_sock = (pj_sock_t)pjSock;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Bind socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, 
+				  const pj_sockaddr_t *addr,
+				  int len)
+{
+    TInt rc;
+
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
+    PJ_ASSERT_RETURN(addr && len == sizeof(pj_sockaddr_in), PJ_EINVAL);
+
+    // Convert PJLIB's pj_sockaddr_in into Symbian's TInetAddr
+    TInetAddr inetAddr;
+    PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)addr, inetAddr);
+
+    // Get the RSocket instance
+    RSocket &rSock = ((CPjSocket*)sock)->Socket();
+
+    // Bind
+    rc = rSock.Bind(inetAddr);
+
+    return (rc==KErrNone) ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
+}
+
+
+/*
+ * 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();
+
+    pj_memset(&addr, 0, sizeof(addr));
+    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)
+{
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+
+    // This will close the socket.
+    delete pjSock;
+
+    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();
+    
+    PJ_ASSERT_RETURN(sock && addr && namelen && 
+		     *namelen>=sizeof(pj_sockaddr_in), PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    // Socket must be connected.
+    PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
+
+    TInetAddr inetAddr;
+    rSock.RemoteName(inetAddr);
+
+    PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)addr);
+    *namelen = sizeof(pj_sockaddr_in);
+
+    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();
+    
+    PJ_ASSERT_RETURN(sock && addr && namelen && 
+		     *namelen>=sizeof(pj_sockaddr_in), PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    TInetAddr inetAddr;
+    rSock.LocalName(inetAddr);
+
+    PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)addr);
+    *namelen = sizeof(pj_sockaddr_in);
+
+    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(sock && buf && len, PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    // send() should only be called to connected socket
+    PJ_ASSERT_RETURN(pjSock->IsConnected(), PJ_EINVALIDOP);
+
+    TPtrC8 data((const TUint8*)buf, (TInt)*len);
+    TRequestStatus reqStatus;
+    TSockXfrLength sentLen;
+
+    rSock.Send(data, flags, reqStatus, sentLen);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus.Int()==KErrNone) {
+	//*len = (TInt) sentLen.Length();
+	return PJ_SUCCESS;
+    } else
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+}
+
+
+/*
+ * 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(sock && buf && len, PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    // Only supports AF_INET for now
+    PJ_ASSERT_RETURN(tolen==sizeof(pj_sockaddr_in) && 
+		     ((pj_sockaddr*)to)->addr.sa_family == PJ_AF_INET, 
+		     PJ_EINVAL);
+
+    TInetAddr inetAddr;
+    PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)to, inetAddr);
+
+    TPtrC8 data((const TUint8*)buf, (TInt)*len);
+    TRequestStatus reqStatus;
+    TSockXfrLength sentLen;
+
+    rSock.SendTo(data, inetAddr, flags, reqStatus, sentLen);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus.Int()==KErrNone) {
+	//For some reason TSockXfrLength is not returning correctly!
+	//*len = (TInt) sentLen.Length();
+	return PJ_SUCCESS;
+    } else 
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+}
+
+/*
+ * 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(sock && buf && len, PJ_EINVAL);
+    PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    if (pjSock->Reader()) {
+	CPjSocketReader *reader = pjSock->Reader();
+
+	while (reader->IsActive() && !reader->HasData()) {
+	    User::WaitForAnyRequest();
+	}
+
+	if (reader->HasData()) {
+	    TPtr8 data((TUint8*)buf, (TInt)*len);
+	    TInetAddr inetAddr;
+
+	    reader->ReadData(data, &inetAddr);
+
+	    *len = data.Length();
+	    return PJ_SUCCESS;
+	}
+    }
+
+    TRequestStatus reqStatus;
+    TSockXfrLength recvLen;
+    TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
+
+    rSock.Recv(data, flags, reqStatus, recvLen);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus == KErrNone) {
+	//*len = (TInt)recvLen.Length();
+	*len = data.Length();
+	return PJ_SUCCESS;
+    } else {
+	*len = -1;
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+    }
+}
+
+/*
+ * 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(sock && buf && len && from && fromlen, PJ_EINVAL);
+    PJ_ASSERT_RETURN(*len > 0, PJ_EINVAL);
+    PJ_ASSERT_RETURN(*fromlen >= sizeof(pj_sockaddr_in), PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    if (pjSock->Reader()) {
+	CPjSocketReader *reader = pjSock->Reader();
+
+	while (reader->IsActive() && !reader->HasData()) {
+	    User::WaitForAnyRequest();
+	}
+
+	if (reader->HasData()) {
+	    TPtr8 data((TUint8*)buf, (TInt)*len);
+	    TInetAddr inetAddr;
+
+	    reader->ReadData(data, &inetAddr);
+
+	    *len = data.Length();
+
+	    if (from && fromlen) {
+		PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)from);
+		*fromlen = sizeof(pj_sockaddr_in);
+	    }
+	    return PJ_SUCCESS;
+	}
+    }
+
+    TInetAddr inetAddr;
+    TRequestStatus reqStatus;
+    TSockXfrLength recvLen;
+    TPtr8 data((TUint8*)buf, (TInt)*len, (TInt)*len);
+
+    rSock.RecvFrom(data, inetAddr, flags, reqStatus, recvLen);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus == KErrNone) {
+	//*len = (TInt)recvLen.Length();
+	*len = data.Length();
+	*fromlen = sizeof(pj_sockaddr_in);
+	PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)from);
+	return PJ_SUCCESS;
+    } else {
+	*len = -1;
+	*fromlen = -1;
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+    }
+}
+
+/*
+ * 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)
+{
+    // Not supported for now.
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(level);
+    PJ_UNUSED_ARG(optname);
+    PJ_UNUSED_ARG(optval);
+    PJ_UNUSED_ARG(optlen);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * 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)
+{
+    // Not supported for now.
+    PJ_UNUSED_ARG(sock);
+    PJ_UNUSED_ARG(level);
+    PJ_UNUSED_ARG(optname);
+    PJ_UNUSED_ARG(optval);
+    PJ_UNUSED_ARG(optlen);
+    return PJ_EINVALIDOP;
+}
+
+/*
+ * Connect socket.
+ */
+PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
+				     const pj_sockaddr_t *addr,
+				     int namelen)
+{
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(sock && addr && namelen, PJ_EINVAL);
+    PJ_ASSERT_RETURN(((pj_sockaddr*)addr)->addr.sa_family == PJ_AF_INET, 
+		     PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    TInetAddr inetAddr;
+    TRequestStatus reqStatus;
+
+    PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)addr, inetAddr);
+
+    rSock.Connect(inetAddr, reqStatus);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus == KErrNone) {
+	pjSock->SetConnected(true);
+	return PJ_SUCCESS;
+    } else {
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+    }
+}
+
+
+/*
+ * Shutdown socket.
+ */
+#if PJ_HAS_TCP
+PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
+				      int how)
+{
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(sock, PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    RSocket::TShutdown aHow;
+    if (how == PJ_SD_RECEIVE)
+	aHow = RSocket::EStopInput;
+    else if (how == PJ_SHUT_WR)
+	aHow = RSocket::EStopOutput;
+    else
+	aHow = RSocket::ENormal;
+
+    TRequestStatus reqStatus;
+
+    rSock.Shutdown(aHow, reqStatus);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus == KErrNone) {
+	return PJ_SUCCESS;
+    } else {
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+    }
+}
+
+/*
+ * Start listening to incoming connections.
+ */
+PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
+				    int backlog)
+{
+    PJ_CHECK_STACK();
+
+    PJ_ASSERT_RETURN(sock && backlog, PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)sock;
+    RSocket &rSock = pjSock->Socket();
+
+    TInt rc = rSock.Listen((TUint)backlog);
+
+    if (rc == KErrNone) {
+	return PJ_SUCCESS;
+    } else {
+	return PJ_RETURN_OS_ERROR(rc);
+    }
+}
+
+/*
+ * 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(serverfd && newsock, PJ_EINVAL);
+
+    CPjSocket *pjSock = (CPjSocket*)serverfd;
+    RSocket &rSock = pjSock->Socket();
+
+    // Create a 'blank' socket
+    RSocket newSock;
+    newSock.Open(PjSymbianOS::Instance()->SocketServ());
+
+    // Call Accept()
+    TRequestStatus reqStatus;
+
+    rSock.Accept(newSock, reqStatus);
+    User::WaitForRequest(reqStatus);
+
+    if (reqStatus != KErrNone) {
+	return PJ_RETURN_OS_ERROR(reqStatus.Int());
+    }
+
+    // Create PJ socket
+    CPjSocket *newPjSock = new CPjSocket(newSock);
+    newPjSock->SetConnected(true);
+
+    *newsock = (pj_sock_t) newPjSock;
+
+    if (addr && addrlen) {
+	return pj_sock_getpeername(*newsock, addr, addrlen);
+    }
+
+    return PJ_SUCCESS;
+}
+#endif	/* PJ_HAS_TCP */
+
+
diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c
index e96a3e5..1e28b92 100644
--- a/pjlib/src/pj/timer.c
+++ b/pjlib/src/pj/timer.c
@@ -255,7 +255,8 @@
     
     pj_timer_entry **new_heap = 0;
     
-    new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size);
+    new_heap = (pj_timer_entry**) 
+    	       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;
@@ -263,7 +264,8 @@
     // 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));
+    new_timer_ids = (pj_timer_id_t*)
+    		    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));
     
@@ -370,7 +372,7 @@
     size += 2;
 
     /* Allocate timer heap data structure from the pool */
-    ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t));
+    ht = PJ_POOL_ALLOC_T(pool, pj_timer_heap_t);
     if (!ht)
         return PJ_ENOMEM;
 
@@ -386,12 +388,14 @@
     ht->auto_delete_lock = 0;
 
     // Create the heap array.
-    ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);
+    ht->heap = (pj_timer_entry**)
+    	       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);
+    ht->timer_ids = (pj_timer_id_t *)
+    		    pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size);
     if (!ht->timer_ids)
         return PJ_ENOMEM;
 
diff --git a/pjlib/src/pj/unicode_symbian.cpp b/pjlib/src/pj/unicode_symbian.cpp
new file mode 100644
index 0000000..62806fd
--- /dev/null
+++ b/pjlib/src/pj/unicode_symbian.cpp
@@ -0,0 +1,69 @@
+/* $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/unicode.h>
+
+#include "os_symbian.h"
+
+
+/*
+ * Convert ANSI strings to Unicode strings.
+ */
+PJ_DEF(wchar_t*) pj_ansi_to_unicode( const char *str, pj_size_t len,
+				     wchar_t *wbuf, pj_size_t wbuf_count)
+{
+    TPtrC8 aForeign((const TUint8*)str, (TInt)len);
+    TPtr16 aUnicode((TUint16*)wbuf, (TInt)(wbuf_count-1));
+    TInt left;
+
+    left = PjSymbianOS::Instance()->ConvertToUnicode(aUnicode, aForeign);
+
+    if (left != 0) {
+	// Error, or there are unconvertable characters
+	*wbuf = 0;
+    } else {
+	wbuf[len] = 0;
+    }
+
+    return wbuf;
+}
+
+
+/*
+ * Convert Unicode string to ANSI string.
+ */
+PJ_DEF(char*) pj_unicode_to_ansi( const wchar_t *wstr, pj_size_t len,
+				  char *buf, pj_size_t buf_size)
+{
+    TPtrC16 aUnicode((const TUint16*)wstr, (TInt)len);
+    TPtr8 aForeign((TUint8*)buf, (TInt)(buf_size-1));
+    TInt left;
+
+    left = PjSymbianOS::Instance()->ConvertFromUnicode(aForeign, aUnicode);
+
+    if (left != 0) {
+	// Error, or there are unconvertable characters
+	buf[0] = '\0';
+    } else {
+	buf[len] = '\0';
+    }
+
+    return buf;
+}
+
+
diff --git a/pjlib/src/pjlib-test/ioq_perf.c b/pjlib/src/pjlib-test/ioq_perf.c
index adffc11..cb8e827 100644
--- a/pjlib/src/pjlib-test/ioq_perf.c
+++ b/pjlib/src/pjlib-test/ioq_perf.c
@@ -72,7 +72,7 @@
                              pj_ioqueue_op_key_t *op_key,
                              pj_ssize_t bytes_read)
 {
-    test_item *item = pj_ioqueue_get_user_data(key);
+    test_item *item = (test_item*)pj_ioqueue_get_user_data(key);
     pj_status_t rc;
     int data_is_available = 1;
 
@@ -150,7 +150,7 @@
                               pj_ioqueue_op_key_t *op_key,
                               pj_ssize_t bytes_sent)
 {
-    test_item *item = pj_ioqueue_get_user_data(key);
+    test_item *item = (test_item*) pj_ioqueue_get_user_data(key);
     
     //TRACE_((THIS_FILE, "     write complete: sent = %d", bytes_sent));
 
@@ -188,7 +188,7 @@
 /* The worker thread. */
 static int worker_thread(void *p)
 {
-    struct thread_arg *arg = p;
+    struct thread_arg *arg = (struct thread_arg*) p;
     const pj_time_val timeout = {0, 100};
     int rc;
 
@@ -249,8 +249,9 @@
     if (!pool)
         return -10;
 
-    items = pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item));
-    thread = pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*));
+    items = (test_item*) pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item));
+    thread = (pj_thread_t**)
+    	     pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*));
 
     TRACE_((THIS_FILE, "     creating ioqueue.."));
     rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue);
@@ -265,8 +266,8 @@
 
         items[i].ioqueue = ioqueue;
         items[i].buffer_size = buffer_size;
-        items[i].outgoing_buffer = pj_pool_alloc(pool, buffer_size);
-        items[i].incoming_buffer = pj_pool_alloc(pool, buffer_size);
+        items[i].outgoing_buffer = (char*) pj_pool_alloc(pool, buffer_size);
+        items[i].incoming_buffer = (char*) pj_pool_alloc(pool, buffer_size);
         items[i].bytes_recv = items[i].bytes_sent = 0;
 
         /* randomize outgoing buffer. */
@@ -331,7 +332,7 @@
     for (i=0; i<thread_cnt; ++i) {
 	struct thread_arg *arg;
 
-	arg = pj_pool_zalloc(pool, sizeof(*arg));
+	arg = (thread_arg*) pj_pool_zalloc(pool, sizeof(*arg));
 	arg->id = i;
 	arg->ioqueue = ioqueue;
 	arg->counter = 0;
diff --git a/pjlib/src/pjlib-test/ioq_udp.c b/pjlib/src/pjlib-test/ioq_udp.c
index 4ccf30f..e6f4c0f 100644
--- a/pjlib/src/pjlib-test/ioq_udp.c
+++ b/pjlib/src/pjlib-test/ioq_udp.c
@@ -328,7 +328,7 @@
                              pj_ioqueue_op_key_t *op_key, 
                              pj_ssize_t bytes_read)
 {
-    unsigned *p_packet_cnt = pj_ioqueue_get_user_data(key);
+    unsigned *p_packet_cnt = (unsigned*) pj_ioqueue_get_user_data(key);
 
     PJ_UNUSED_ARG(op_key);
     PJ_UNUSED_ARG(bytes_read);
@@ -510,8 +510,9 @@
     if (!pool)
 	return PJ_ENOMEM;
 
-    key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
-    sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
+    key = (pj_ioqueue_key_t**) 
+    	  pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
+    sock = (pj_sock_t*) pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
     
     /* Create IOQueue */
     rc = pj_ioqueue_create(pool, MAX, &ioqueue);
diff --git a/pjlib/src/pjlib-test/ioq_unreg.c b/pjlib/src/pjlib-test/ioq_unreg.c
index 1f7a98e..ef50d04 100644
--- a/pjlib/src/pjlib-test/ioq_unreg.c
+++ b/pjlib/src/pjlib-test/ioq_unreg.c
@@ -123,7 +123,7 @@
 
 static int worker_thread(void *arg)
 {
-    pj_ioqueue_t *ioqueue = arg;
+    pj_ioqueue_t *ioqueue = (pj_ioqueue_t*) arg;
 
     while (!thread_quitting) {
 	pj_time_val timeout = { 0, 20 };
@@ -210,9 +210,10 @@
 
     /* Initialize test data */
     sock_data.pool = pj_pool_create(mem, "sd", 1000, 1000, NULL);
-    sock_data.buffer = pj_pool_alloc(sock_data.pool, 128);
+    sock_data.buffer = (char*) pj_pool_alloc(sock_data.pool, 128);
     sock_data.bufsize = 128;
-    sock_data.op_key = pj_pool_alloc(sock_data.pool, 
+    sock_data.op_key = (pj_ioqueue_op_key_t*) 
+    		       pj_pool_alloc(sock_data.pool, 
 				     sizeof(*sock_data.op_key));
     sock_data.received = 0;
     sock_data.unregistered = 0;
diff --git a/pjlib/src/pjlib-test/main_symbian.cpp b/pjlib/src/pjlib-test/main_symbian.cpp
new file mode 100644
index 0000000..c2c808b
--- /dev/null
+++ b/pjlib/src/pjlib-test/main_symbian.cpp
@@ -0,0 +1,193 @@
+//Auto-generated file. Please do not modify.
+//#include <e32cmn.h>
+
+//#pragma data_seg(".SYMBIAN")
+//__EMULATOR_IMAGE_HEADER2 (0x1000007a,0x00000000,0x00000000,EPriorityForeground,0x00000000u,0x00000000u,0x00000000,0x00000000,0x00000000,0)
+//#pragma data_seg()
+
+#include "test.h"
+#include <stdlib.h>
+#include <pj/errno.h>
+#include <pj/os.h>
+#include <pj/log.h>
+#include <pj/unicode.h>
+#include <stdio.h>
+
+#include <e32std.h>
+
+#if 0
+int main()
+{
+    int err = 0;
+    int exp = 0;
+
+    err = test_main();
+    //err = test_main();
+
+    if (err)
+	return err;
+    return exp;
+    //return 0;
+}
+
+#else
+#include <pj/os.h>
+
+#include <e32base.h>
+#include <e32std.h>
+#include <e32cons.h>            // Console
+
+
+
+//  Global Variables
+
+LOCAL_D CConsoleBase* console;  // write all messages to this
+
+
+//  Local Functions
+
+LOCAL_C void MainL()
+{
+    //
+    // add your program code here, example code below
+    //
+    int rc = test_main();
+
+    console->Printf(_L(" [press any key]\n"));
+    console->Getch();
+
+    CActiveScheduler::Stop();
+}
+
+class MyScheduler : public CActiveScheduler
+{
+public:
+    MyScheduler()
+    {}
+
+    void Error(TInt aError) const;
+};
+
+void MyScheduler::Error(TInt aError) const
+{
+    PJ_UNUSED_ARG(aError);
+}
+
+class ProgramStarter : public CActive
+{
+public:
+    static ProgramStarter *NewL();
+    void Start();
+
+protected:
+    ProgramStarter();
+    void ConstructL();
+    virtual void RunL();
+    virtual void DoCancel();
+    TInt RunError(TInt aError);
+
+private:
+    RTimer timer_;
+};
+
+ProgramStarter::ProgramStarter()
+: CActive(EPriorityNormal)
+{
+}
+
+void ProgramStarter::ConstructL()
+{
+    timer_.CreateLocal();
+    CActiveScheduler::Add(this);
+}
+
+ProgramStarter *ProgramStarter::NewL()
+{
+    ProgramStarter *self = new (ELeave) ProgramStarter;
+    CleanupStack::PushL(self);
+
+    self->ConstructL();
+
+    CleanupStack::Pop(self);
+    return self;
+}
+
+void ProgramStarter::Start()
+{
+    timer_.After(iStatus, 0);
+    SetActive();
+}
+
+void ProgramStarter::RunL()
+{
+    MainL();
+}
+
+void ProgramStarter::DoCancel()
+{
+}
+
+TInt ProgramStarter::RunError(TInt aError)
+{
+    PJ_UNUSED_ARG(aError);
+    return KErrNone;
+}
+
+
+LOCAL_C void DoStartL()
+    {
+    // Create active scheduler (to run active objects)
+    CActiveScheduler* scheduler = new (ELeave) MyScheduler;
+    CleanupStack::PushL(scheduler);
+    CActiveScheduler::Install(scheduler);
+
+    ProgramStarter *starter = ProgramStarter::NewL();
+    starter->Start();
+
+    CActiveScheduler::Start();
+    }
+
+
+//  Global Functions
+
+static void log_writer(int level, const char *buf, int len)
+{
+    wchar_t buf16[PJ_LOG_MAX_SIZE];
+
+    PJ_UNUSED_ARG(level);
+    
+    pj_ansi_to_unicode(buf, len, buf16, PJ_ARRAY_SIZE(buf16));
+
+    TPtrC16 aBuf((const TUint16*)buf16, (TInt)len);
+    console->Write(aBuf);
+}
+
+
+GLDEF_C TInt E32Main()
+    {
+    // Create cleanup stack
+    __UHEAP_MARK;
+    CTrapCleanup* cleanup = CTrapCleanup::New();
+
+    // Create output console
+    TRAPD(createError, console = Console::NewL(_L("Console"), TSize(KConsFullScreen,KConsFullScreen)));
+    if (createError)
+        return createError;
+
+    pj_log_set_log_func(&log_writer);
+
+    // Run application code inside TRAP harness, wait keypress when terminated
+    TRAPD(mainError, DoStartL());
+    if (mainError)
+        console->Printf(_L(" failed, leave code = %d"), mainError);
+    console->Printf(_L(" [press any key]\n"));
+    console->Getch();
+    
+    delete console;
+    delete cleanup;
+    __UHEAP_MARKEND;
+    return KErrNone;
+    }
+
+#endif	/* if 0 */
+
diff --git a/pjlib/src/pjlib-test/sock.c b/pjlib/src/pjlib-test/sock.c
index a3df9b6..044b0f1 100644
--- a/pjlib/src/pjlib-test/sock.c
+++ b/pjlib/src/pjlib-test/sock.c
@@ -63,13 +63,8 @@
 
 #define UDP_PORT	51234
 #define TCP_PORT        (UDP_PORT+10)
-#define BIG_DATA_LEN	9000
+#define BIG_DATA_LEN	8192
 #define ADDRESS		"127.0.0.1"
-#define A0		127
-#define A1		0
-#define A2		0
-#define A3		1
-
 
 static char bigdata[BIG_DATA_LEN];
 static char bigbuffer[BIG_DATA_LEN];
@@ -82,6 +77,12 @@
     char zero[64];
     pj_sockaddr_in addr2;
     const pj_str_t *hostname;
+#if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
+    /* Symbian IP address is saved in host order */
+    unsigned char A[] = {1, 0, 0, 127};
+#else
+    unsigned char A[] = {127, 0, 0, 1};
+#endif
 
     PJ_LOG(3,("test", "...format_test()"));
     
@@ -91,7 +92,7 @@
     
     /* Check the result. */
     p = (unsigned char*)&addr;
-    if (p[0]!=A0 || p[1]!=A1 || p[2]!=A2 || p[3]!=A3) {
+    if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) {
 	PJ_LOG(3,("test", "  error: mismatched address. p0=%d, p1=%d, "
 			  "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, 
 			   p[2] & 0xFF, p[3] & 0xFF));
@@ -368,6 +369,8 @@
     if (rc != 0)
 	goto on_error;
 
+// This test will fail on S60 3rd Edition MR2
+#if 0
     /* connect() the sockets. */
     rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr));
     if (rc != 0) {
@@ -385,6 +388,7 @@
                         sizeof(srcaddr));
     if (rc != 0)
 	goto on_error;
+#endif
 
 on_error:
     retval = rc;
@@ -459,12 +463,70 @@
 	return 0;
 }
 
+#if 0
+#include "../pj/os_symbian.h"
+static int connect_test()
+{
+	RSocketServ rSockServ;
+	RSocket rSock;
+	TInetAddr inetAddr;
+	TRequestStatus reqStatus;
+	char buffer[16];
+	TPtrC8 data((const TUint8*)buffer, (TInt)sizeof(buffer));
+ 	int rc;
+	
+	rc = rSockServ.Connect();
+	if (rc != KErrNone)
+		return rc;
+	
+	rc = rSock.Open(rSockServ, KAfInet, KSockDatagram, KProtocolInetUdp);
+    	if (rc != KErrNone) 
+    	{    		
+    		rSockServ.Close();
+    		return rc;
+    	}
+   	
+    	inetAddr.Init(KAfInet);
+    	inetAddr.Input(_L("127.0.0.1"));
+    	inetAddr.SetPort(80);
+    	
+    	rSock.Connect(inetAddr, reqStatus);
+    	User::WaitForRequest(reqStatus);
+
+    	if (reqStatus != KErrNone) {
+		rSock.Close();
+    		rSockServ.Close();
+		return rc;
+    	}
+    
+    	rSock.Send(data, 0, reqStatus);
+    	User::WaitForRequest(reqStatus);
+    	
+    	if (reqStatus!=KErrNone) {
+    		rSock.Close();
+    		rSockServ.Close();
+    		return rc;
+    	}
+    	
+    	rSock.Close();
+    	rSockServ.Close();
+	return KErrNone;
+}
+#endif
+
 int sock_test()
 {
     int rc;
     
     pj_create_random_string(bigdata, BIG_DATA_LEN);
 
+// Enable this to demonstrate the error witn S60 3rd Edition MR2
+#if 0
+    rc = connect_test();
+    if (rc != 0)
+    	return rc;
+#endif
+    
     rc = format_test();
     if (rc != 0)
 	return rc;
diff --git a/pjlib/src/pjlib-test/sock_perf.c b/pjlib/src/pjlib-test/sock_perf.c
index efb8f06..1fa1208 100644
--- a/pjlib/src/pjlib-test/sock_perf.c
+++ b/pjlib/src/pjlib-test/sock_perf.c
@@ -69,8 +69,8 @@
     }
 
     /* Create buffers. */
-    outgoing_buffer = pj_pool_alloc(pool, buf_size);
-    incoming_buffer = pj_pool_alloc(pool, buf_size);
+    outgoing_buffer = (char*) pj_pool_alloc(pool, buf_size);
+    incoming_buffer = (char*) pj_pool_alloc(pool, buf_size);
 
     /* Start loop. */
     pj_get_timestamp(&start);
diff --git a/pjlib/src/pjlib-test/string.c b/pjlib/src/pjlib-test/string.c
index dd3649c..d8bc54f 100644
--- a/pjlib/src/pjlib-test/string.c
+++ b/pjlib/src/pjlib-test/string.c
@@ -236,6 +236,9 @@
 	//return -700;
     }
 
+    /* Avoid division by zero */
+    if (c2 == 0) c2=1;
+    
     PJ_LOG(3, ("", "  time: stricmp=%u, stricmp_alnum=%u (speedup=%d.%02dx)", 
 		   c1, c2,
 		   (c1 * 100 / c2) / 100,
@@ -328,7 +331,7 @@
     /* 
      * pj_strcpy(), pj_strcat() 
      */
-    s3.ptr = pj_pool_alloc(pool, 256);
+    s3.ptr = (char*) pj_pool_alloc(pool, 256);
     if (!s3.ptr) 
 	return -200;
     pj_strcpy(&s3, &s2);
@@ -348,7 +351,7 @@
     /* 
      * pj_utoa() 
      */
-    s5.ptr = pj_pool_alloc(pool, 16);
+    s5.ptr = (char*) pj_pool_alloc(pool, 16);
     if (!s5.ptr)
 	return -270;
     s5.slen = pj_utoa(UL_VALUE, s5.ptr);
@@ -392,7 +395,7 @@
     for (i=0; i<RCOUNT; ++i) {
 	int j;
 	
-	random[i].ptr = pj_pool_alloc(pool, RLEN);
+	random[i].ptr = (char*) pj_pool_alloc(pool, RLEN);
 	if (!random[i].ptr)
 	    return -320;
 
diff --git a/pjlib/src/pjlib-test/test.h b/pjlib/src/pjlib-test/test.h
index ab86eac..b30ba9f 100644
--- a/pjlib/src/pjlib-test/test.h
+++ b/pjlib/src/pjlib-test/test.h
@@ -21,13 +21,21 @@
 
 #include <pj/types.h>
 
-#define GROUP_LIBC                  1
-#define GROUP_OS                    1
-#define GROUP_DATA_STRUCTURE        1
+#define GROUP_LIBC                  0
+#define GROUP_OS                    0
+#define GROUP_DATA_STRUCTURE        0
 #define GROUP_NETWORK               1
-#define GROUP_FILE                  1
+#if defined(PJ_SYMBIAN)
+#   define GROUP_FILE               0
+#else
+#   define GROUP_FILE               1
+#endif
 
-#define INCLUDE_ERRNO_TEST          GROUP_LIBC
+#if defined(PJ_SYMBIAN)
+#   define INCLUDE_ERRNO_TEST       0
+#else
+#   define INCLUDE_ERRNO_TEST       GROUP_LIBC
+#endif
 #define INCLUDE_TIMESTAMP_TEST      GROUP_OS
 #define INCLUDE_EXCEPTION_TEST	    GROUP_LIBC
 #define INCLUDE_RAND_TEST	    GROUP_LIBC
@@ -39,16 +47,20 @@
 #define INCLUDE_RBTREE_TEST	    GROUP_DATA_STRUCTURE
 #define INCLUDE_TIMER_TEST	    GROUP_DATA_STRUCTURE
 #define INCLUDE_ATOMIC_TEST         GROUP_OS
-#define INCLUDE_MUTEX_TEST	    GROUP_OS
+#define INCLUDE_MUTEX_TEST	    (PJ_HAS_THREADS && GROUP_OS)
 #define INCLUDE_SLEEP_TEST          GROUP_OS
-#define INCLUDE_THREAD_TEST         GROUP_OS 
+#define INCLUDE_THREAD_TEST         (PJ_HAS_THREADS && GROUP_OS)
 #define INCLUDE_SOCK_TEST	    GROUP_NETWORK
-#define INCLUDE_SOCK_PERF_TEST      GROUP_NETWORK
+#if defined(PJ_SYMBIAN)
+#   define INCLUDE_SOCK_PERF_TEST   0
+#else
+#   define INCLUDE_SOCK_PERF_TEST   GROUP_NETWORK
+#endif
 #define INCLUDE_SELECT_TEST	    GROUP_NETWORK
 #define INCLUDE_UDP_IOQUEUE_TEST    GROUP_NETWORK
 #define INCLUDE_TCP_IOQUEUE_TEST    GROUP_NETWORK
-#define INCLUDE_IOQUEUE_PERF_TEST   GROUP_NETWORK
-#define INCLUDE_IOQUEUE_UNREG_TEST  GROUP_NETWORK
+#define INCLUDE_IOQUEUE_PERF_TEST   (PJ_HAS_THREADS && GROUP_NETWORK)
+#define INCLUDE_IOQUEUE_UNREG_TEST  (PJ_HAS_THREADS && GROUP_NETWORK)
 #define INCLUDE_FILE_TEST           GROUP_FILE
 
 #define INCLUDE_ECHO_SERVER         0
diff --git a/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c b/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
index 0e29bbd..d2d2246 100644
--- a/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
+++ b/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
@@ -117,7 +117,7 @@
 
 static int worker_thread(void *arg)
 {
-    pj_ioqueue_t *ioqueue = arg;
+    pj_ioqueue_t *ioqueue = (pj_ioqueue_t*) arg;
     struct op_key read_op, write_op;
     char recv_buf[512], send_buf[512];
     pj_ssize_t length;