diff options
Diffstat (limited to 'pjlib')
42 files changed, 4418 insertions, 72 deletions
diff --git a/pjlib/include/pj/compat/cc_codew.h b/pjlib/include/pj/compat/cc_codew.h new file mode 100644 index 00000000..cad9d0c5 --- /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 00000000..e22e9fb7 --- /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 00000000..51d78eb6 --- /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 b33ce445..2c2e4693 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 52ad3f55..40c03455 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 07ac4e2f..896615b4 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 951823ea..e6d4fd4c 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 efa7638e..f873dd56 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 a07eb220..2f1f9ddd 100644 --- a/pjlib/include/pj/except.h +++ b/pjlib/include/pj/except.h @@ -237,6 +237,29 @@ pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN #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 d8544a79..f0a628e1 100644 --- a/pjlib/include/pj/list_i.h +++ b/pjlib/include/pj/list_i.h @@ -128,7 +128,7 @@ PJ_IDEF(pj_size_t) pj_list_size(pj_list_type *list) 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 00000000..c9a776c8 --- /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 8d63868f..832afee7 100644 --- a/pjlib/src/pj/array.c +++ b/pjlib/src/pj/array.c @@ -55,7 +55,7 @@ PJ_DEF(pj_status_t) pj_array_find( const void *array, 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 00000000..28f13123 --- /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 7745dfd2..f82c22d6 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 00000000..f04045bf --- /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 50b7cf36..08bf907a 100644 --- a/pjlib/src/pj/fifobuf.c +++ b/pjlib/src/pj/fifobuf.c @@ -34,7 +34,7 @@ pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size) "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_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size) 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_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf) 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 dd308d5a..30ac2b13 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 5a97e5f1..5b3454d9 100644 --- a/pjlib/src/pj/hash.c +++ b/pjlib/src/pj/hash.c @@ -55,13 +55,13 @@ PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, 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 @@ PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size) /* 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 @@ PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size) 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 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, */ 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 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, * 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 00000000..50f33503 --- /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 8c2c8b3f..9c0a7fa6 100644 --- a/pjlib/src/pj/lock.c +++ b/pjlib/src/pj/lock.c @@ -64,7 +64,7 @@ static pj_status_t create_mutex_lock( pj_pool_t *pool, 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_DEF(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool, 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 00000000..03ad9ede --- /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 00000000..7386fd63 --- /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 00000000..dcacf288 --- /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 05728da6..27bc5adb 100644 --- a/pjlib/src/pj/os_rwmutex.c +++ b/pjlib/src/pj/os_rwmutex.c @@ -56,7 +56,7 @@ PJ_DEF(pj_status_t) pj_rwmutex_create(pj_pool_t *pool, const char *name, 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 00000000..06973104 --- /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 02b71ed5..9f47892d 100644 --- a/pjlib/src/pj/pool.c +++ b/pjlib/src/pj/pool.c @@ -170,7 +170,7 @@ PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name, { pj_pool_t *pool; pj_pool_block *block; - unsigned char *buffer; + pj_uint8_t *buffer; PJ_CHECK_STACK(); @@ -183,7 +183,7 @@ PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name, 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 f6f294b7..08885ea6 100644 --- a/pjlib/src/pj/pool_buf.c +++ b/pjlib/src/pj/pool_buf.c @@ -57,7 +57,7 @@ static void* stack_alloc(pj_pool_factory *factory, pj_size_t size) 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 35bc580b..b00bf108 100644 --- a/pjlib/src/pj/pool_caching.c +++ b/pjlib/src/pj/pool_caching.c @@ -85,7 +85,7 @@ PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp ) /* 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 @@ PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp ) } /* 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 @@ static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, } 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 @@ static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail ) 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 00000000..367be0f3 --- /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 00000000..cf45a62d --- /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 00000000..1b79098a --- /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 e96a3e54..1e28b926 100644 --- a/pjlib/src/pj/timer.c +++ b/pjlib/src/pj/timer.c @@ -255,7 +255,8 @@ static void grow_heap(pj_timer_heap_t *ht) 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 @@ static void grow_heap(pj_timer_heap_t *ht) // 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 @@ PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, 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 @@ PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, 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 00000000..62806fd1 --- /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 adffc11c..cb8e8270 100644 --- a/pjlib/src/pjlib-test/ioq_perf.c +++ b/pjlib/src/pjlib-test/ioq_perf.c @@ -72,7 +72,7 @@ static void on_read_complete(pj_ioqueue_key_t *key, 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 @@ static void on_write_complete(pj_ioqueue_key_t *key, 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 @@ struct thread_arg /* 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 @@ static int perform_test(int sock_type, const char *type_name, 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 @@ static int perform_test(int sock_type, const char *type_name, 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 @@ static int perform_test(int sock_type, const char *type_name, 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 4ccf30f9..e6f4c0f9 100644 --- a/pjlib/src/pjlib-test/ioq_udp.c +++ b/pjlib/src/pjlib-test/ioq_udp.c @@ -328,7 +328,7 @@ static void on_read_complete(pj_ioqueue_key_t *key, 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 @@ static int many_handles_test(void) 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 1f7a98e7..ef50d048 100644 --- a/pjlib/src/pjlib-test/ioq_unreg.c +++ b/pjlib/src/pjlib-test/ioq_unreg.c @@ -123,7 +123,7 @@ static void on_read_complete(pj_ioqueue_key_t *key, 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 @@ static int perform_unreg_test(pj_ioqueue_t *ioqueue, /* 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 00000000..c2c808b8 --- /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 a3df9b63..044b0f13 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 @@ static int format_test(void) 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 @@ static int format_test(void) /* 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 @@ static int udp_test(void) 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 @@ static int udp_test(void) sizeof(srcaddr)); if (rc != 0) goto on_error; +#endif on_error: retval = rc; @@ -459,12 +463,70 @@ static int gethostbyname_test(void) 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 efb8f065..1fa12082 100644 --- a/pjlib/src/pjlib-test/sock_perf.c +++ b/pjlib/src/pjlib-test/sock_perf.c @@ -69,8 +69,8 @@ static int sock_producer_consumer(int sock_type, } /* 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 dd3649cc..d8bc54fd 100644 --- a/pjlib/src/pjlib-test/string.c +++ b/pjlib/src/pjlib-test/string.c @@ -236,6 +236,9 @@ static int stricmp_test(void) //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 @@ int string_test(void) /* * 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 @@ int string_test(void) /* * 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 @@ int string_test(void) 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 ab86eacc..b30ba9f5 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 - -#define INCLUDE_ERRNO_TEST GROUP_LIBC +#if defined(PJ_SYMBIAN) +# define GROUP_FILE 0 +#else +# define GROUP_FILE 1 +#endif + +#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 0e29bbd2..d2d2246a 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 void on_write_complete(pj_ioqueue_key_t *key, 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; |