diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-04-30 21:03:32 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-04-30 21:03:32 +0000 |
commit | 9bfdd11aac28c934ce580880837cce948d9be10a (patch) | |
tree | e0414666d0e0b7b7ac99adb0125acf7b988b8428 /pjlib/src/pj | |
parent | 25830dbc54149caeb660f1f379e547ed9eb09159 (diff) |
Initial Symbian integration to trunk for pjlib
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1235 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib/src/pj')
-rw-r--r-- | pjlib/src/pj/addr_resolv_symbian.cpp | 147 | ||||
-rw-r--r-- | pjlib/src/pj/array.c | 2 | ||||
-rw-r--r-- | pjlib/src/pj/compat/string_compat.c | 72 | ||||
-rw-r--r-- | pjlib/src/pj/errno.c | 8 | ||||
-rw-r--r-- | pjlib/src/pj/exception_symbian.cpp | 154 | ||||
-rw-r--r-- | pjlib/src/pj/fifobuf.c | 6 | ||||
-rw-r--r-- | pjlib/src/pj/guid.c | 2 | ||||
-rw-r--r-- | pjlib/src/pj/hash.c | 21 | ||||
-rw-r--r-- | pjlib/src/pj/ioqueue_symbian.cpp | 812 | ||||
-rw-r--r-- | pjlib/src/pj/lock.c | 4 | ||||
-rw-r--r-- | pjlib/src/pj/log_writer_symbian_console.cpp | 43 | ||||
-rw-r--r-- | pjlib/src/pj/os_core_symbian.cpp | 816 | ||||
-rw-r--r-- | pjlib/src/pj/os_error_symbian.cpp | 171 | ||||
-rw-r--r-- | pjlib/src/pj/os_rwmutex.c | 2 | ||||
-rw-r--r-- | pjlib/src/pj/os_symbian.h | 302 | ||||
-rw-r--r-- | pjlib/src/pj/pool.c | 4 | ||||
-rw-r--r-- | pjlib/src/pj/pool_buf.c | 2 | ||||
-rw-r--r-- | pjlib/src/pj/pool_caching.c | 8 | ||||
-rw-r--r-- | pjlib/src/pj/pool_policy_new.cpp | 73 | ||||
-rw-r--r-- | pjlib/src/pj/sock_select_symbian.cpp | 162 | ||||
-rw-r--r-- | pjlib/src/pj/sock_symbian.cpp | 931 | ||||
-rw-r--r-- | pjlib/src/pj/timer.c | 14 | ||||
-rw-r--r-- | pjlib/src/pj/unicode_symbian.cpp | 69 |
23 files changed, 3793 insertions, 32 deletions
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; +} + + |