Implemented ticket #246, #247, #261, #268, #250 for Symbian

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1246 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib/src/pj/guid_simple.c b/pjlib/src/pj/guid_simple.c
index 05744bc..fecdd78 100644
--- a/pjlib/src/pj/guid_simple.c
+++ b/pjlib/src/pj/guid_simple.c
@@ -57,8 +57,8 @@
     }
 
     strcpy(str->ptr, str_pid);
-    sprintf(str->ptr+4, "%04x", clock_seq++);
-    pj_memcpy(str->ptr+8, str_mac_addr, 12);
+    sprintf(str->ptr+4, "%08x", clock_seq++);
+    pj_memcpy(str->ptr+12, str_mac_addr, 8);
     str->slen = 20;
 
     return str;
diff --git a/pjlib/src/pj/ioqueue_symbian.cpp b/pjlib/src/pj/ioqueue_symbian.cpp
index df1fa46..6768cc0 100644
--- a/pjlib/src/pj/ioqueue_symbian.cpp
+++ b/pjlib/src/pj/ioqueue_symbian.cpp
@@ -34,7 +34,6 @@
 struct pj_ioqueue_t
 {
     int		     eventCount;
-    CPjTimeoutTimer *timeoutTimer;
 };
 
 
@@ -438,8 +437,7 @@
 
     PJ_UNUSED_ARG(max_fd);
 
-    ioq = (pj_ioqueue_t*) pj_pool_zalloc(pool, sizeof(pj_ioqueue_t));
-    ioq->timeoutTimer = CPjTimeoutTimer::NewL();
+    ioq = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_t);
     *p_ioqueue = ioq;
     return PJ_SUCCESS;
 }
@@ -450,9 +448,7 @@
  */
 PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioq )
 {
-    delete ioq->timeoutTimer;
-    ioq->timeoutTimer = NULL;
-
+    PJ_UNUSED_ARG(ioq);
     return PJ_SUCCESS;
 }
 
@@ -487,7 +483,7 @@
 {
     pj_ioqueue_key_t *key;
 
-    key = (pj_ioqueue_key_t*) pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
+    key = PJ_POOL_ZALLOC_T(pool, pj_ioqueue_key_t);
     key->cbObj = CIoqueueCallback::NewL(ioq, key, sock, cb, user_data);
 
     *p_key = key;
@@ -552,7 +548,7 @@
 PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,
 				     pj_size_t size )
 {
-    pj_memset(op_key, 0, size);
+    pj_bzero(op_key, size);
 }
 
 
@@ -634,34 +630,12 @@
 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;
+    /* Polling is not necessary on Symbian, since all async activities
+     * are registered to active scheduler.
+     */
+    PJ_UNUSED_ARG(ioq);
+    PJ_UNUSED_ARG(timeout);
+    return 0;
 }
 
 
diff --git a/pjlib/src/pj/os_core_symbian.cpp b/pjlib/src/pj/os_core_symbian.cpp
index d0bbb15..a55b548 100644
--- a/pjlib/src/pj/os_core_symbian.cpp
+++ b/pjlib/src/pj/os_core_symbian.cpp
@@ -83,7 +83,7 @@
 //
 
 CPjTimeoutTimer::CPjTimeoutTimer()
-: CActive(EPriorityNormal), hasTimedOut_(PJ_FALSE)
+: CActive(PJ_SYMBIAN_TIMER_PRIORITY), hasTimedOut_(PJ_FALSE)
 {
 }
 
@@ -420,13 +420,7 @@
  */
 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;
 }
 
diff --git a/pjlib/src/pj/os_symbian.h b/pjlib/src/pj/os_symbian.h
index 0697310..929070b 100644
--- a/pjlib/src/pj/os_symbian.h
+++ b/pjlib/src/pj/os_symbian.h
@@ -20,6 +20,7 @@
 #define __OS_SYMBIAN_H__
 
 #include <pj/sock.h>
+#include <pj/string.h>
 
 #include <e32base.h>
 #include <e32cmn.h>
@@ -33,6 +34,10 @@
 // Forward declarations
 class CPjSocketReader;
 
+#ifndef PJ_SYMBIAN_TIMER_PRIORITY
+#    define PJ_SYMBIAN_TIMER_PRIORITY	EPriorityNormal
+#endif
+
 //
 // PJLIB Symbian's Socket
 //
@@ -216,10 +221,10 @@
     static inline void Addr2pj(const TInetAddr & sym_addr,
 			       pj_sockaddr_in &pj_addr)
     {
-	memset(&pj_addr, 0, sizeof(pj_sockaddr_in));
+	pj_bzero(&pj_addr, 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();
+	pj_addr.sin_addr.s_addr = pj_htonl(sym_addr.Address());
+	pj_addr.sin_port = pj_htons((pj_uint16_t) sym_addr.Port());
     }
 
 
@@ -228,8 +233,8 @@
 			       TInetAddr & sym_addr)
     {
 	sym_addr.Init(KAfInet);
-	sym_addr.SetAddress((TUint32)pj_addr.sin_addr.s_addr);
-	sym_addr.SetPort(pj_addr.sin_port);
+	sym_addr.SetAddress((TUint32)pj_ntohl(pj_addr.sin_addr.s_addr));
+	sym_addr.SetPort(pj_ntohs(pj_addr.sin_port));
     }
 
 
diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp
index 5615dde..8d2ab07 100644
--- a/pjlib/src/pj/sock_symbian.cpp
+++ b/pjlib/src/pj/sock_symbian.cpp
@@ -210,8 +210,11 @@
  */
 PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
 {
-    /* There's no difference in host/network byte order in Symbian */
+#if PJ_IS_LITTLE_ENDIAN
+    return pj_swap16(netshort);
+#else
     return netshort;
+#endif
 }
 
 /*
@@ -219,8 +222,11 @@
  */
 PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
 {
-    /* There's no difference in host/network byte order in Symbian */
+#if PJ_IS_LITTLE_ENDIAN
+    return pj_swap16(hostshort);
+#else
     return hostshort;
+#endif
 }
 
 /*
@@ -228,8 +234,11 @@
  */
 PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
 {
-    /* There's no difference in host/network byte order in Symbian */
+#if PJ_IS_LITTLE_ENDIAN
+    return pj_swap32(netlong);
+#else
     return netlong;
+#endif
 }
 
 /*
@@ -237,8 +246,11 @@
  */
 PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
 {
-    /* There's no difference in host/network byte order in Symbian */
-    return hostlong;
+#if PJ_IS_LITTLE_ENDIAN
+    return pj_swap32(hostlong);
+#else
+    return netlong;
+#endif
 }
 
 /*
@@ -250,7 +262,8 @@
     static TBuf<20> str16;
     static char str8[20];
 
-    TInetAddr temp_addr((TUint32)inaddr.s_addr, (TUint)0);
+    /* (Symbian IP address is in host byte order) */
+    TInetAddr temp_addr((TUint32)pj_ntohl(inaddr.s_addr), (TUint)0);
     temp_addr.Output(str16);
  
     return pj_unicode_to_ansi(str16.PtrZ(), str16.Length(),
@@ -294,8 +307,8 @@
     TInetAddr addr;
     addr.Init(KAfInet);
     if (addr.Input(ip_addr) == KErrNone) {
-	/* Success */
-	inp->s_addr = addr.Address();
+	/* Success (Symbian IP address is in host byte order) */
+	inp->s_addr = pj_htonl(addr.Address());
 	return 1;
     } else {
 	/* Error */
@@ -497,7 +510,7 @@
 
     PJ_CHECK_STACK();
 
-    pj_memset(&addr, 0, sizeof(addr));
+    pj_bzero(&addr, sizeof(addr));
     addr.sin_family = PJ_AF_INET;
     addr.sin_addr.s_addr = pj_htonl(addr32);
     addr.sin_port = pj_htons(port);
diff --git a/pjlib/src/pj/timer_symbian.cpp b/pjlib/src/pj/timer_symbian.cpp
new file mode 100644
index 0000000..398f772
--- /dev/null
+++ b/pjlib/src/pj/timer_symbian.cpp
@@ -0,0 +1,272 @@
+/* $Id$ */
+/* 
+ * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj/timer.h>
+#include <pj/pool.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/lock.h>
+
+#include "os_symbian.h"
+
+
+#define DEFAULT_MAX_TIMED_OUT_PER_POLL  (64)
+
+
+/**
+ * The implementation of timer heap.
+ */
+struct pj_timer_heap_t
+{
+    /** Maximum size of the heap. */
+    pj_size_t max_size;
+
+    /** Current size of the heap. */
+    pj_size_t cur_size;
+
+    /** Max timed out entries to process per poll. */
+    unsigned max_entries_per_poll;
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+/**
+ * Active object for each timer entry.
+ */
+class CPjTimerEntry : public CActive 
+{
+public:
+    static CPjTimerEntry* NewL(	pj_timer_heap_t *timer_heap,
+    				pj_timer_entry *entry,
+    				const pj_time_val *delay);
+    
+    ~CPjTimerEntry();
+    
+    virtual void RunL();
+    virtual void DoCancel();
+
+private:	
+    pj_timer_heap_t *timer_heap_;
+    pj_timer_entry  *entry_;
+    RTimer	     rtimer_;
+    
+    CPjTimerEntry(pj_timer_heap_t *timer_heap, pj_timer_entry *entry);
+    void ConstructL(const pj_time_val *delay);
+};
+
+
+CPjTimerEntry::CPjTimerEntry(pj_timer_heap_t *timer_heap,
+			     pj_timer_entry *entry)
+: CActive(PJ_SYMBIAN_TIMER_PRIORITY), timer_heap_(timer_heap), entry_(entry)
+{
+}
+
+CPjTimerEntry::~CPjTimerEntry() 
+{
+    if (IsActive())
+	Cancel();
+    rtimer_.Close();
+}
+
+void CPjTimerEntry::ConstructL(const pj_time_val *delay) 
+{
+    rtimer_.CreateLocal();
+    CActiveScheduler::Add(this);
+    
+    rtimer_.After(iStatus, PJ_TIME_VAL_MSEC(*delay) * 1000);
+    SetActive();
+}
+
+CPjTimerEntry* CPjTimerEntry::NewL(pj_timer_heap_t *timer_heap,
+				   pj_timer_entry *entry,
+				   const pj_time_val *delay) 
+{
+    CPjTimerEntry *self = new CPjTimerEntry(timer_heap, entry);
+    CleanupStack::PushL(self);
+    self->ConstructL(delay);
+    CleanupStack::Pop(self);
+
+    return self;
+}
+
+void CPjTimerEntry::RunL() 
+{
+    --timer_heap_->cur_size;
+    entry_->_timer_id = NULL;
+    entry_->cb(timer_heap_, entry_);
+    
+    // Finger's crossed!
+    delete this;
+}
+
+void CPjTimerEntry::DoCancel() 
+{
+     rtimer_.Cancel();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+/*
+ * Calculate memory size required to create a timer heap.
+ */
+PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
+{
+    return /* size of the timer heap itself: */
+           sizeof(pj_timer_heap_t) + 
+           /* size of each entry: */
+           (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +
+           /* lock, pool etc: */
+           132;
+}
+
+/*
+ * Create a new timer heap.
+ */
+PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
+					  pj_size_t size,
+                                          pj_timer_heap_t **p_heap)
+{
+    pj_timer_heap_t *ht;
+
+    PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
+
+    *p_heap = NULL;
+
+    /* Allocate timer heap data structure from the pool */
+    ht = PJ_POOL_ALLOC_T(pool, pj_timer_heap_t);
+    if (!ht)
+        return PJ_ENOMEM;
+
+    /* Initialize timer heap sizes */
+    ht->max_size = size;
+    ht->cur_size = 0;
+    ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;
+
+    *p_heap = ht;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )
+{
+    PJ_UNUSED_ARG(ht);
+}
+
+PJ_DEF(void) pj_timer_heap_set_lock(  pj_timer_heap_t *ht,
+                                      pj_lock_t *lock,
+                                      pj_bool_t auto_del )
+{
+    PJ_UNUSED_ARG(ht);
+    if (auto_del)
+    	pj_lock_destroy(lock);
+}
+
+
+PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
+                                                          unsigned count )
+{
+    unsigned old_count = ht->max_entries_per_poll;
+    ht->max_entries_per_poll = count;
+    return old_count;
+}
+
+PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
+                                             int id,
+                                             void *user_data,
+                                             pj_timer_heap_callback *cb )
+{
+    pj_assert(entry && cb);
+
+    entry->_timer_id = NULL;
+    entry->id = id;
+    entry->user_data = user_data;
+    entry->cb = cb;
+
+    return entry;
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
+					    pj_timer_entry *entry, 
+					    const pj_time_val *delay)
+{
+    CPjTimerEntry *timerObj;
+    
+    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
+    PJ_ASSERT_RETURN(entry->cb != NULL, PJ_EINVAL);
+
+    /* Prevent same entry from being scheduled more than once */
+    PJ_ASSERT_RETURN(entry->_timer_id == NULL, PJ_EINVALIDOP);
+
+    timerObj = CPjTimerEntry::NewL(ht, entry, delay);
+    entry->_timer_id = (void*) timerObj;
+    
+    ++ht->cur_size;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
+				  pj_timer_entry *entry)
+{
+    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
+    
+    if (entry->_timer_id != NULL) {
+    	CPjTimerEntry *timerObj = (CPjTimerEntry*) entry->_timer_id;
+    	timerObj->Cancel();
+    	delete timerObj;
+    	entry->_timer_id = NULL;
+    	--ht->cur_size;
+    	return 1;
+    } else {
+    	return 0;
+    }
+}
+
+PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 
+                                     pj_time_val *next_delay )
+{
+    /* Polling is not necessary on Symbian, since all async activities
+     * are registered to active scheduler.
+     */
+    PJ_UNUSED_ARG(ht);
+    if (next_delay) {
+    	next_delay->sec = 1;
+    	next_delay->msec = 0;
+    }
+    return 0;
+}
+
+PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
+{
+    PJ_ASSERT_RETURN(ht, 0);
+
+    return ht->cur_size;
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
+					         pj_time_val *timeval)
+{
+    /* We don't support this! */
+    PJ_UNUSED_ARG(ht);
+    
+    timeval->sec = 1;
+    timeval->msec = 0;
+    
+    return PJ_SUCCESS;
+}
+