* #27232: jni: added pjproject checkout as regular git content
We will remove it once the next release of pjsip (with Android support)
comes out and is merged into SFLphone.
diff --git a/jni/pjproject-android/.svn/pristine/61/611c113a1dc829248873e403d13c5fbf466335ca.svn-base b/jni/pjproject-android/.svn/pristine/61/611c113a1dc829248873e403d13c5fbf466335ca.svn-base
new file mode 100644
index 0000000..47288fa
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/61/611c113a1dc829248873e403d13c5fbf466335ca.svn-base
@@ -0,0 +1,1426 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * 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/ssl_sock.h>
+#include <pj/compat/socket.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/math.h>
+#include <pj/pool.h>
+#include <pj/sock.h>
+#include <pj/string.h>
+
+#include "os_symbian.h"
+#include <securesocket.h>
+#include <x509cert.h>
+#include <e32des8.h>
+
+#define THIS_FILE "ssl_sock_symbian.cpp"
+
+
+/* Cipher name structure */
+typedef struct cipher_name_t {
+ pj_ssl_cipher cipher;
+ const char *name;
+} cipher_name_t;
+
+/* Cipher name constants */
+static cipher_name_t cipher_names[] =
+{
+ {PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
+
+ /* TLS/SSLv3 */
+ {PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
+ {PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
+ {PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
+ {PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
+ {PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
+ {PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
+ {PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
+ {PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
+ {PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
+
+ /* TLS (deprecated) */
+ {PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
+ {PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
+ {PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
+ {PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
+ {PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
+ {PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
+ {PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
+
+ /* SSLv3 */
+ {PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
+ {PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
+ {PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
+
+ /* SSLv2 */
+ {PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
+ {PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
+ {PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
+ {PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
+ {PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
+ {PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
+ {PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
+};
+
+
+/* Get cipher name string */
+static const char* get_cipher_name(pj_ssl_cipher cipher)
+{
+ unsigned i, n;
+
+ n = PJ_ARRAY_SIZE(cipher_names);
+ for (i = 0; i < n; ++i) {
+ if (cipher == cipher_names[i].cipher)
+ return cipher_names[i].name;
+ }
+
+ return "CIPHER_UNKNOWN";
+}
+
+typedef void (*CPjSSLSocket_cb)(int err, void *key);
+
+class CPjSSLSocketReader : public CActive
+{
+public:
+ static CPjSSLSocketReader *NewL(CSecureSocket &sock)
+ {
+ CPjSSLSocketReader *self = new (ELeave)
+ CPjSSLSocketReader(sock);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+ ~CPjSSLSocketReader() {
+ Cancel();
+ }
+
+ /* Asynchronous read from the socket. */
+ int Read(CPjSSLSocket_cb cb, void *key, TPtr8 &data, TUint flags)
+ {
+ PJ_ASSERT_RETURN(!IsActive(), PJ_EBUSY);
+
+ cb_ = cb;
+ key_ = key;
+ sock_.RecvOneOrMore(data, iStatus, len_received_);
+ SetActive();
+
+ return PJ_EPENDING;
+ }
+
+private:
+ CSecureSocket &sock_;
+ CPjSSLSocket_cb cb_;
+ void *key_;
+ TSockXfrLength len_received_; /* not really useful? */
+
+ void DoCancel() {
+ sock_.CancelAll();
+ }
+
+ void RunL() {
+ (*cb_)(iStatus.Int(), key_);
+ }
+
+ CPjSSLSocketReader(CSecureSocket &sock) :
+ CActive(0), sock_(sock), cb_(NULL), key_(NULL)
+ {}
+
+ void ConstructL() {
+ CActiveScheduler::Add(this);
+ }
+};
+
+class CPjSSLSocket : public CActive
+{
+public:
+ enum ssl_state {
+ SSL_STATE_NULL,
+ SSL_STATE_CONNECTING,
+ SSL_STATE_HANDSHAKING,
+ SSL_STATE_ESTABLISHED
+ };
+
+ static CPjSSLSocket *NewL(const TDesC8 &ssl_proto,
+ pj_qos_type qos_type,
+ const pj_qos_params &qos_params)
+ {
+ CPjSSLSocket *self = new (ELeave) CPjSSLSocket(qos_type, qos_params);
+ CleanupStack::PushL(self);
+ self->ConstructL(ssl_proto);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+ ~CPjSSLSocket() {
+ Cancel();
+ CleanupSubObjects();
+ }
+
+ int Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr,
+ const TInetAddr &rem_addr,
+ const TDesC8 &servername = TPtrC8(NULL,0),
+ const TDesC8 &ciphers = TPtrC8(NULL,0));
+ int Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, TUint flags);
+ int SendSync(const TDesC8 &aDesc, TUint flags);
+
+ CPjSSLSocketReader* GetReader();
+ enum ssl_state GetState() const { return state_; }
+ const TInetAddr* GetLocalAddr() const { return &local_addr_; }
+ int GetCipher(TDes8 &cipher) const {
+ if (securesock_)
+ return securesock_->CurrentCipherSuite(cipher);
+ return KErrNotFound;
+ }
+ const CX509Certificate *GetPeerCert() {
+ if (securesock_)
+ return securesock_->ServerCert();
+ return NULL;
+ }
+
+private:
+ enum ssl_state state_;
+ pj_sock_t sock_;
+ CSecureSocket *securesock_;
+ bool is_connected_;
+
+ pj_qos_type qos_type_;
+ pj_qos_params qos_params_;
+
+ CPjSSLSocketReader *reader_;
+ TBuf<32> ssl_proto_;
+ TInetAddr rem_addr_;
+ TPtrC8 servername_;
+ TPtrC8 ciphers_;
+ TInetAddr local_addr_;
+ TSockXfrLength sent_len_;
+
+ CPjSSLSocket_cb cb_;
+ void *key_;
+
+ void DoCancel();
+ void RunL();
+
+ CPjSSLSocket(pj_qos_type qos_type, const pj_qos_params &qos_params) :
+ CActive(0), state_(SSL_STATE_NULL), sock_(PJ_INVALID_SOCKET),
+ securesock_(NULL), is_connected_(false),
+ qos_type_(qos_type), qos_params_(qos_params),
+ reader_(NULL), cb_(NULL), key_(NULL)
+ {}
+
+ void ConstructL(const TDesC8 &ssl_proto) {
+ ssl_proto_.Copy(ssl_proto);
+ CActiveScheduler::Add(this);
+ }
+
+ void CleanupSubObjects() {
+ delete reader_;
+ reader_ = NULL;
+ if (securesock_) {
+ if (state_ == SSL_STATE_ESTABLISHED)
+ securesock_->Close();
+ delete securesock_;
+ securesock_ = NULL;
+ }
+ if (sock_ != PJ_INVALID_SOCKET) {
+ pj_sock_close(sock_);
+ sock_ = PJ_INVALID_SOCKET;
+ }
+ }
+};
+
+int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
+ const TInetAddr &local_addr,
+ const TInetAddr &rem_addr,
+ const TDesC8 &servername,
+ const TDesC8 &ciphers)
+{
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(state_ == SSL_STATE_NULL, PJ_EINVALIDOP);
+
+ status = pj_sock_socket(rem_addr.Family(), pj_SOCK_STREAM(), 0, &sock_);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ // Apply QoS
+ status = pj_sock_apply_qos2(sock_, qos_type_, &qos_params_,
+ 2, THIS_FILE, NULL);
+
+ RSocket &rSock = ((CPjSocket*)sock_)->Socket();
+
+ local_addr_ = local_addr;
+
+ if (!local_addr_.IsUnspecified()) {
+ TInt err = rSock.Bind(local_addr_);
+ if (err != KErrNone)
+ return PJ_RETURN_OS_ERROR(err);
+ }
+
+ cb_ = cb;
+ key_ = key;
+ rem_addr_ = rem_addr;
+
+ /* Note: the following members only keep the pointer, not the data */
+ servername_.Set(servername);
+ ciphers_.Set(ciphers);
+
+ rSock.Connect(rem_addr_, iStatus);
+ SetActive();
+ state_ = SSL_STATE_CONNECTING;
+
+ rSock.LocalName(local_addr_);
+
+ return PJ_EPENDING;
+}
+
+int CPjSSLSocket::Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc,
+ TUint flags)
+{
+ PJ_UNUSED_ARG(flags);
+
+ PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
+
+ if (IsActive())
+ return PJ_EBUSY;
+
+ cb_ = cb;
+ key_ = key;
+
+ securesock_->Send(aDesc, iStatus, sent_len_);
+ SetActive();
+
+ return PJ_EPENDING;
+}
+
+int CPjSSLSocket::SendSync(const TDesC8 &aDesc, TUint flags)
+{
+ PJ_UNUSED_ARG(flags);
+
+ PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
+
+ TRequestStatus reqStatus;
+ securesock_->Send(aDesc, reqStatus, sent_len_);
+ User::WaitForRequest(reqStatus);
+
+ return PJ_RETURN_OS_ERROR(reqStatus.Int());
+}
+
+CPjSSLSocketReader* CPjSSLSocket::GetReader()
+{
+ PJ_ASSERT_RETURN(state_ == SSL_STATE_ESTABLISHED, NULL);
+
+ if (reader_)
+ return reader_;
+
+ TRAPD(err, reader_ = CPjSSLSocketReader::NewL(*securesock_));
+ if (err != KErrNone)
+ return NULL;
+
+ return reader_;
+}
+
+void CPjSSLSocket::DoCancel()
+{
+ /* Operation to be cancelled depends on current state */
+ switch (state_) {
+ case SSL_STATE_CONNECTING:
+ {
+ RSocket &rSock = ((CPjSocket*)sock_)->Socket();
+
+ rSock.CancelConnect();
+ CleanupSubObjects();
+ state_ = SSL_STATE_NULL;
+ }
+ break;
+ case SSL_STATE_HANDSHAKING:
+ {
+ securesock_->CancelHandshake();
+ CleanupSubObjects();
+ state_ = SSL_STATE_NULL;
+ }
+ break;
+ case SSL_STATE_ESTABLISHED:
+ securesock_->CancelSend();
+ break;
+ default:
+ break;
+ }
+}
+
+void CPjSSLSocket::RunL()
+{
+ switch (state_) {
+ case SSL_STATE_CONNECTING:
+ if (iStatus != KErrNone) {
+ CleanupSubObjects();
+ state_ = SSL_STATE_NULL;
+ /* Dispatch connect failure notification */
+ if (cb_) (*cb_)(iStatus.Int(), key_);
+ } else {
+ RSocket &rSock = ((CPjSocket*)sock_)->Socket();
+
+ /* Get local addr */
+ rSock.LocalName(local_addr_);
+
+ /* Prepare and start handshake */
+ securesock_ = CSecureSocket::NewL(rSock, ssl_proto_);
+ securesock_->SetDialogMode(EDialogModeAttended);
+ if (servername_.Length() > 0)
+ securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
+ servername_);
+ if (ciphers_.Length() > 0)
+ securesock_->SetAvailableCipherSuites(ciphers_);
+
+ // FlushSessionCache() seems to also fire signals to all
+ // completed AOs (something like CActiveScheduler::RunIfReady())
+ // which may cause problem, e.g: we've experienced that when
+ // SSL timeout is set to 1s, the SSL timeout timer fires up
+ // at this point and securesock_ instance gets deleted here!
+ // So be careful using this. And we don't think we need it here.
+ //securesock_->FlushSessionCache();
+
+ securesock_->StartClientHandshake(iStatus);
+ SetActive();
+ state_ = SSL_STATE_HANDSHAKING;
+ }
+ break;
+ case SSL_STATE_HANDSHAKING:
+ if (iStatus == KErrNone) {
+ state_ = SSL_STATE_ESTABLISHED;
+ } else {
+ state_ = SSL_STATE_NULL;
+ CleanupSubObjects();
+ }
+ /* Dispatch connect status notification */
+ if (cb_) (*cb_)(iStatus.Int(), key_);
+ break;
+ case SSL_STATE_ESTABLISHED:
+ /* Dispatch data sent notification */
+ if (cb_) (*cb_)(iStatus.Int(), key_);
+ break;
+ default:
+ pj_assert(0);
+ break;
+ }
+}
+
+typedef void (*CPjTimer_cb)(void *user_data);
+
+class CPjTimer : public CActive
+{
+public:
+ CPjTimer(const pj_time_val *delay, CPjTimer_cb cb, void *user_data) :
+ CActive(0), cb_(cb), user_data_(user_data)
+ {
+ CActiveScheduler::Add(this);
+
+ rtimer_.CreateLocal();
+ pj_int32_t interval = PJ_TIME_VAL_MSEC(*delay) * 1000;
+ if (interval < 0) {
+ interval = 0;
+ }
+ rtimer_.After(iStatus, interval);
+ SetActive();
+ }
+
+ ~CPjTimer() { Cancel(); }
+
+private:
+ RTimer rtimer_;
+ CPjTimer_cb cb_;
+ void *user_data_;
+
+ void RunL() { if (cb_) (*cb_)(user_data_); }
+ void DoCancel() { rtimer_.Cancel(); }
+};
+
+/*
+ * Structure of recv/read state.
+ */
+typedef struct read_state_t {
+ TPtr8 *read_buf;
+ TPtr8 *orig_buf;
+ pj_uint32_t flags;
+} read_state_t;
+
+/*
+ * Structure of send/write data.
+ */
+typedef struct write_data_t {
+ pj_size_t len;
+ pj_ioqueue_op_key_t *key;
+ pj_size_t data_len;
+ char data[1];
+} write_data_t;
+
+/*
+ * Structure of send/write state.
+ */
+typedef struct write_state_t {
+ char *buf;
+ pj_size_t max_len;
+ char *start;
+ pj_size_t len;
+ write_data_t *current_data;
+ TPtrC8 send_ptr;
+} write_state_t;
+
+/*
+ * Secure socket structure definition.
+ */
+struct pj_ssl_sock_t
+{
+ pj_pool_t *pool;
+ pj_ssl_sock_cb cb;
+ void *user_data;
+
+ pj_bool_t established;
+ write_state_t write_state;
+ read_state_t read_state;
+ CPjTimer *connect_timer;
+
+ CPjSSLSocket *sock;
+ int sock_af;
+ int sock_type;
+ pj_sockaddr local_addr;
+ pj_sockaddr rem_addr;
+
+ /* QoS settings */
+ pj_qos_type qos_type;
+ pj_qos_params qos_params;
+ pj_bool_t qos_ignore_error;
+
+
+ pj_ssl_sock_proto proto;
+ pj_time_val timeout;
+ pj_str_t servername;
+ pj_str_t ciphers;
+ pj_ssl_cert_info remote_cert_info;
+};
+
+
+static pj_str_t get_cert_name(char *buf, unsigned buf_len,
+ const CX500DistinguishedName &name)
+{
+ TInt i;
+ TUint8 *p;
+ TInt l = buf_len;
+
+ p = (TUint8*)buf;
+ for(i = 0; i < name.Count(); ++i) {
+ const CX520AttributeTypeAndValue &attr = name.Element(i);
+
+ /* Print element separator */
+ *p++ = '/';
+ if (0 == --l) break;
+
+ /* Print the type. */
+ TPtr8 type(p, l);
+ type.Copy(attr.Type());
+ p += type.Length();
+ l -= type.Length();
+ if (0 >= --l) break;
+
+ /* Print equal sign */
+ *p++ = '=';
+ if (0 == --l) break;
+
+ /* Print the value. Let's just get the raw data here */
+ TPtr8 value(p, l);
+ value.Copy(attr.EncodedValue().Mid(2));
+ p += value.Length();
+ l -= value.Length();
+ if (0 >= --l) break;
+ }
+
+ pj_str_t src;
+ pj_strset(&src, buf, buf_len - l);
+
+ return src;
+}
+
+/* Get certificate info from CX509Certificate.
+ */
+static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci,
+ const CX509Certificate *x)
+{
+ enum { tmp_buf_len = 512 };
+ char *tmp_buf;
+ unsigned len;
+
+ pj_assert(pool && ci && x);
+
+ /* Init */
+ tmp_buf = new char[tmp_buf_len];
+ pj_bzero(ci, sizeof(*ci));
+
+ /* Version */
+ ci->version = x->Version();
+
+ /* Serial number */
+ len = x->SerialNumber().Length();
+ if (len > sizeof(ci->serial_no))
+ len = sizeof(ci->serial_no);
+ pj_memcpy(ci->serial_no + sizeof(ci->serial_no) - len,
+ x->SerialNumber().Ptr(), len);
+
+ /* Subject */
+ {
+ HBufC *subject = NULL;
+ TRAPD(err, subject = x->SubjectL());
+ if (err == KErrNone) {
+ TPtr16 ptr16(subject->Des());
+ len = ptr16.Length();
+ TPtr8 ptr8((TUint8*)pj_pool_alloc(pool, len), len);
+ ptr8.Copy(ptr16);
+ pj_strset(&ci->subject.cn, (char*)ptr8.Ptr(), ptr8.Length());
+ }
+ pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
+ x->SubjectName());
+ pj_strdup(pool, &ci->subject.info, &tmp);
+ }
+
+ /* Issuer */
+ {
+ HBufC *issuer = NULL;
+ TRAPD(err, issuer = x->IssuerL());
+ if (err == KErrNone) {
+ TPtr16 ptr16(issuer->Des());
+ len = ptr16.Length();
+ TPtr8 ptr8((TUint8*)pj_pool_alloc(pool, len), len);
+ ptr8.Copy(ptr16);
+ pj_strset(&ci->issuer.cn, (char*)ptr8.Ptr(), ptr8.Length());
+ }
+ pj_str_t tmp = get_cert_name(tmp_buf, tmp_buf_len,
+ x->IssuerName());
+ pj_strdup(pool, &ci->issuer.info, &tmp);
+ }
+
+ /* Validity */
+ const CValidityPeriod &valid_period = x->ValidityPeriod();
+ TTime base_time(TDateTime(1970, EJanuary, 0, 0, 0, 0, 0));
+ TTimeIntervalSeconds tmp_sec;
+ valid_period.Start().SecondsFrom(base_time, tmp_sec);
+ ci->validity.start.sec = tmp_sec.Int();
+ valid_period.Finish().SecondsFrom(base_time, tmp_sec);
+ ci->validity.end.sec = tmp_sec.Int();
+
+ /* Deinit */
+ delete [] tmp_buf;
+}
+
+
+/* Update certificates info. This function should be called after handshake
+ * or renegotiation successfully completed.
+ */
+static void update_certs_info(pj_ssl_sock_t *ssock)
+{
+ const CX509Certificate *x;
+
+ pj_assert(ssock && ssock->sock &&
+ ssock->sock->GetState() == CPjSSLSocket::SSL_STATE_ESTABLISHED);
+
+ /* Active remote certificate */
+ x = ssock->sock->GetPeerCert();
+ if (x) {
+ get_cert_info(ssock->pool, &ssock->remote_cert_info, x);
+ } else {
+ pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
+ }
+}
+
+
+/* Available ciphers */
+static unsigned ciphers_num_ = 0;
+static struct ciphers_t
+{
+ pj_ssl_cipher id;
+ const char *name;
+} ciphers_[64];
+
+/*
+ * Get cipher list supported by SSL/TLS backend.
+ */
+PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
+ unsigned *cipher_num)
+{
+ unsigned i;
+
+ PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
+
+ if (ciphers_num_ == 0) {
+ RSocket sock;
+ CSecureSocket *secure_sock;
+ TPtrC16 proto(_L16("TLS1.0"));
+
+ secure_sock = CSecureSocket::NewL(sock, proto);
+ if (secure_sock) {
+ TBuf8<128> ciphers_buf(0);
+ secure_sock->AvailableCipherSuites(ciphers_buf);
+
+ ciphers_num_ = ciphers_buf.Length() / 2;
+ if (ciphers_num_ > PJ_ARRAY_SIZE(ciphers_))
+ ciphers_num_ = PJ_ARRAY_SIZE(ciphers_);
+ for (i = 0; i < ciphers_num_; ++i) {
+ ciphers_[i].id = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
+ ciphers_buf[i*2+1]);
+ ciphers_[i].name = get_cipher_name(ciphers_[i].id);
+ }
+ }
+
+ delete secure_sock;
+ }
+
+ if (ciphers_num_ == 0) {
+ *cipher_num = 0;
+ return PJ_ENOTFOUND;
+ }
+
+ *cipher_num = PJ_MIN(*cipher_num, ciphers_num_);
+ for (i = 0; i < *cipher_num; ++i)
+ ciphers[i] = ciphers_[i].id;
+
+ return PJ_SUCCESS;
+}
+
+
+/* Get cipher name string */
+PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
+{
+ unsigned i;
+
+ if (ciphers_num_ == 0) {
+ pj_ssl_cipher c[1];
+ i = 0;
+ pj_ssl_cipher_get_availables(c, &i);
+ }
+
+ for (i = 0; i < ciphers_num_; ++i) {
+ if (cipher == ciphers_[i].id)
+ return ciphers_[i].name;
+ }
+
+ return NULL;
+}
+
+
+/* Check if the specified cipher is supported by SSL/TLS backend. */
+PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
+{
+ unsigned i;
+
+ if (ciphers_num_ == 0) {
+ pj_ssl_cipher c[1];
+ i = 0;
+ pj_ssl_cipher_get_availables(c, &i);
+ }
+
+ for (i = 0; i < ciphers_num_; ++i) {
+ if (cipher == ciphers_[i].id)
+ return PJ_TRUE;
+ }
+
+ return PJ_FALSE;
+}
+
+
+/*
+ * Create SSL socket instance.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
+ const pj_ssl_sock_param *param,
+ pj_ssl_sock_t **p_ssock)
+{
+ pj_ssl_sock_t *ssock;
+
+ PJ_ASSERT_RETURN(param->async_cnt == 1, PJ_EINVAL);
+ PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
+
+ /* Allocate secure socket */
+ ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
+
+ /* Allocate write buffer */
+ ssock->write_state.buf = (char*)pj_pool_alloc(pool,
+ param->send_buffer_size);
+ ssock->write_state.max_len = param->send_buffer_size;
+ ssock->write_state.start = ssock->write_state.buf;
+
+ /* Init secure socket */
+ ssock->pool = pool;
+ ssock->sock_af = param->sock_af;
+ ssock->sock_type = param->sock_type;
+ ssock->cb = param->cb;
+ ssock->user_data = param->user_data;
+ ssock->timeout = param->timeout;
+ if (param->ciphers_num > 0) {
+ /* Cipher list in Symbian is represented as array of two-octets. */
+ ssock->ciphers.slen = param->ciphers_num*2;
+ ssock->ciphers.ptr = (char*)pj_pool_alloc(pool, ssock->ciphers.slen);
+ pj_uint8_t *c = (pj_uint8_t*)ssock->ciphers.ptr;
+ for (unsigned i = 0; i < param->ciphers_num; ++i) {
+ *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF00) >> 8;
+ *c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF);
+ }
+ }
+ pj_strdup_with_null(pool, &ssock->servername, ¶m->server_name);
+
+ ssock->qos_type = param->qos_type;
+ ssock->qos_ignore_error = param->qos_ignore_error;
+ pj_memcpy(&ssock->qos_params, ¶m->qos_params,
+ sizeof(param->qos_params));
+
+ /* Finally */
+ *p_ssock = ssock;
+
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files(pj_pool_t *pool,
+ const pj_str_t *CA_file,
+ const pj_str_t *cert_file,
+ const pj_str_t *privkey_file,
+ const pj_str_t *privkey_pass,
+ pj_ssl_cert_t **p_cert)
+{
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(CA_file);
+ PJ_UNUSED_ARG(cert_file);
+ PJ_UNUSED_ARG(privkey_file);
+ PJ_UNUSED_ARG(privkey_pass);
+ PJ_UNUSED_ARG(p_cert);
+ return PJ_ENOTSUP;
+}
+
+/*
+ * Set SSL socket credential.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
+ pj_ssl_sock_t *ssock,
+ pj_pool_t *pool,
+ const pj_ssl_cert_t *cert)
+{
+ PJ_UNUSED_ARG(ssock);
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(cert);
+ return PJ_ENOTSUP;
+}
+
+/*
+ * Close the SSL socket.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
+{
+ PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
+
+ delete ssock->connect_timer;
+ ssock->connect_timer = NULL;
+
+ delete ssock->sock;
+ ssock->sock = NULL;
+
+ delete ssock->read_state.read_buf;
+ delete ssock->read_state.orig_buf;
+ ssock->read_state.read_buf = NULL;
+ ssock->read_state.orig_buf = NULL;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Associate arbitrary data with the SSL socket.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data (pj_ssl_sock_t *ssock,
+ void *user_data)
+{
+ PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
+
+ ssock->user_data = user_data;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Retrieve the user data previously associated with this SSL
+ * socket.
+ */
+PJ_DEF(void*) pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
+{
+ PJ_ASSERT_RETURN(ssock, NULL);
+
+ return ssock->user_data;
+}
+
+
+/*
+ * Retrieve the local address and port used by specified SSL socket.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
+ pj_ssl_sock_info *info)
+{
+ PJ_ASSERT_RETURN(ssock && info, PJ_EINVAL);
+
+ pj_bzero(info, sizeof(*info));
+
+ info->established = ssock->established;
+
+ /* Local address */
+ if (ssock->sock) {
+ const TInetAddr* local_addr_ = ssock->sock->GetLocalAddr();
+ int addrlen = sizeof(pj_sockaddr);
+ pj_status_t status;
+
+ status = PjSymbianOS::Addr2pj(*local_addr_, info->local_addr, &addrlen);
+ if (status != PJ_SUCCESS)
+ return status;
+ } else {
+ pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
+ }
+
+ if (info->established) {
+ /* Cipher suite */
+ TBuf8<4> cipher;
+ if (ssock->sock->GetCipher(cipher) == KErrNone) {
+ info->cipher = (pj_ssl_cipher)cipher[1];
+ }
+
+ /* Remote address */
+ pj_sockaddr_cp((pj_sockaddr_t*)&info->remote_addr,
+ (pj_sockaddr_t*)&ssock->rem_addr);
+
+ /* Certificates info */
+ info->remote_cert_info = &ssock->remote_cert_info;
+ }
+
+ /* Protocol */
+ info->proto = ssock->proto;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Starts read operation on this SSL socket.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_start_read (pj_ssl_sock_t *ssock,
+ pj_pool_t *pool,
+ unsigned buff_size,
+ pj_uint32_t flags)
+{
+ PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
+ PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
+
+ /* Reading is already started */
+ if (ssock->read_state.orig_buf) {
+ return PJ_SUCCESS;
+ }
+
+ void *readbuf[1];
+ readbuf[0] = pj_pool_alloc(pool, buff_size);
+ return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
+}
+
+static void read_cb(int err, void *key)
+{
+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
+ pj_status_t status;
+
+ status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
+
+ /* Check connection status */
+ if (err == KErrEof || !PjSymbianOS::Instance()->IsConnectionUp() ||
+ !ssock->established)
+ {
+ status = PJ_EEOF;
+ }
+
+ /* Notify data arrival */
+ if (ssock->cb.on_data_read) {
+ pj_size_t remainder = 0;
+ char *data = (char*)ssock->read_state.orig_buf->Ptr();
+ pj_size_t data_len = ssock->read_state.read_buf->Length() +
+ ssock->read_state.read_buf->Ptr() -
+ ssock->read_state.orig_buf->Ptr();
+
+ if (data_len > 0) {
+ /* Notify received data */
+ pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, data, data_len,
+ status, &remainder);
+ if (!ret) {
+ /* We've been destroyed */
+ return;
+ }
+
+ /* Calculate available data for next READ operation */
+ if (remainder > 0) {
+ pj_size_t data_maxlen = ssock->read_state.orig_buf->MaxLength();
+
+ /* There is some data left unconsumed by application, we give
+ * smaller buffer for next READ operation.
+ */
+ ssock->read_state.read_buf->Set((TUint8*)data+remainder, 0,
+ data_maxlen - remainder);
+ } else {
+ /* Give all buffer for next READ operation.
+ */
+ ssock->read_state.read_buf->Set(*ssock->read_state.orig_buf);
+ }
+ }
+ }
+
+ if (status == PJ_SUCCESS) {
+ /* Perform the "next" READ operation */
+ CPjSSLSocketReader *reader = ssock->sock->GetReader();
+ ssock->read_state.read_buf->SetLength(0);
+ status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf,
+ ssock->read_state.flags);
+ }
+
+ /* Connection closed or something goes wrong */
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ /* Notify error */
+ if (ssock->cb.on_data_read) {
+ pj_bool_t ret = (*ssock->cb.on_data_read)(ssock, NULL, 0,
+ status, NULL);
+ if (!ret) {
+ /* We've been destroyed */
+ return;
+ }
+ }
+
+ delete ssock->read_state.read_buf;
+ delete ssock->read_state.orig_buf;
+ ssock->read_state.read_buf = NULL;
+ ssock->read_state.orig_buf = NULL;
+ ssock->established = PJ_FALSE;
+ }
+}
+
+/*
+ * Same as #pj_ssl_sock_start_read(), except that the application
+ * supplies the buffers for the read operation so that the acive socket
+ * does not have to allocate the buffers.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
+ pj_pool_t *pool,
+ unsigned buff_size,
+ void *readbuf[],
+ pj_uint32_t flags)
+{
+ PJ_ASSERT_RETURN(ssock && buff_size && readbuf, PJ_EINVAL);
+ PJ_ASSERT_RETURN(ssock->established, PJ_EINVALIDOP);
+
+ /* Return failure if access point is marked as down by app. */
+ PJ_SYMBIAN_CHECK_CONNECTION();
+
+ /* Reading is already started */
+ if (ssock->read_state.orig_buf) {
+ return PJ_SUCCESS;
+ }
+
+ PJ_UNUSED_ARG(pool);
+
+ /* Get reader instance */
+ CPjSSLSocketReader *reader = ssock->sock->GetReader();
+ if (!reader)
+ return PJ_ENOMEM;
+
+ /* We manage two buffer pointers here:
+ * 1. orig_buf keeps the orginal buffer address (and its max length).
+ * 2. read_buf provides buffer for READ operation, mind that there may be
+ * some remainder data left by application.
+ */
+ ssock->read_state.read_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
+ ssock->read_state.orig_buf = new TPtr8((TUint8*)readbuf[0], 0, buff_size);
+ ssock->read_state.flags = flags;
+
+ pj_status_t status;
+ status = reader->Read(&read_cb, ssock, *ssock->read_state.read_buf,
+ ssock->read_state.flags);
+
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ delete ssock->read_state.read_buf;
+ delete ssock->read_state.orig_buf;
+ ssock->read_state.read_buf = NULL;
+ ssock->read_state.orig_buf = NULL;
+
+ return status;
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Same as pj_ssl_sock_start_read(), except that this function is used
+ * only for datagram sockets, and it will trigger \a on_data_recvfrom()
+ * callback instead.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
+ pj_pool_t *pool,
+ unsigned buff_size,
+ pj_uint32_t flags)
+{
+ PJ_UNUSED_ARG(ssock);
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(buff_size);
+ PJ_UNUSED_ARG(flags);
+ return PJ_ENOTSUP;
+}
+
+/*
+ * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
+ * operation takes the buffer from the argument rather than creating
+ * new ones.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
+ pj_pool_t *pool,
+ unsigned buff_size,
+ void *readbuf[],
+ pj_uint32_t flags)
+{
+ PJ_UNUSED_ARG(ssock);
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(buff_size);
+ PJ_UNUSED_ARG(readbuf);
+ PJ_UNUSED_ARG(flags);
+ return PJ_ENOTSUP;
+}
+
+static void send_cb(int err, void *key)
+{
+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
+ write_state_t *st = &ssock->write_state;
+
+ /* Check connection status */
+ if (err != KErrNone || !PjSymbianOS::Instance()->IsConnectionUp() ||
+ !ssock->established)
+ {
+ ssock->established = PJ_FALSE;
+ return;
+ }
+
+ /* Remove sent data from buffer */
+ st->start += st->current_data->len;
+ st->len -= st->current_data->len;
+
+ /* Reset current outstanding send */
+ st->current_data = NULL;
+
+ /* Let's check if there is pending data to send */
+ if (st->len) {
+ write_data_t *wdata = (write_data_t*)st->start;
+ pj_status_t status;
+
+ st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
+ st->current_data = wdata;
+ status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, 0);
+ if (status != PJ_EPENDING) {
+ ssock->established = PJ_FALSE;
+ st->len = 0;
+ return;
+ }
+ } else {
+ /* Buffer empty, reset the start position */
+ st->start = st->buf;
+ }
+}
+
+/*
+ * Send data using the socket.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_send (pj_ssl_sock_t *ssock,
+ pj_ioqueue_op_key_t *send_key,
+ const void *data,
+ pj_ssize_t *size,
+ unsigned flags)
+{
+ PJ_CHECK_STACK();
+ PJ_ASSERT_RETURN(ssock && data && size, PJ_EINVAL);
+ PJ_ASSERT_RETURN(ssock->write_state.max_len == 0 ||
+ ssock->write_state.max_len >= (pj_size_t)*size,
+ PJ_ETOOSMALL);
+
+ /* Check connection status */
+ if (!PjSymbianOS::Instance()->IsConnectionUp() || !ssock->established)
+ {
+ ssock->established = PJ_FALSE;
+ return PJ_ECANCELLED;
+ }
+
+ write_state_t *st = &ssock->write_state;
+
+ /* Synchronous mode */
+ if (st->max_len == 0) {
+ st->send_ptr.Set((TUint8*)data, (TInt)*size);
+ return ssock->sock->SendSync(st->send_ptr, flags);
+ }
+
+ /* CSecureSocket only allows one outstanding send operation, so
+ * we use buffering mechanism to allow application to perform send
+ * operations at any time.
+ */
+
+ pj_size_t needed_len = *size + sizeof(write_data_t) - 1;
+
+ /* Align needed_len to be multiplication of 4 */
+ needed_len = ((needed_len + 3) >> 2) << 2;
+
+ /* Block until there is buffer slot available and contiguous! */
+ while (st->start + st->len + needed_len > st->buf + st->max_len) {
+ pj_symbianos_poll(-1, -1);
+ }
+
+ /* Push back the send data into the buffer */
+ write_data_t *wdata = (write_data_t*)(st->start + st->len);
+
+ wdata->len = needed_len;
+ wdata->key = send_key;
+ wdata->data_len = (pj_size_t)*size;
+ pj_memcpy(wdata->data, data, *size);
+ st->len += needed_len;
+
+ /* If no outstanding send, send it */
+ if (st->current_data == NULL) {
+ pj_status_t status;
+
+ wdata = (write_data_t*)st->start;
+ st->current_data = wdata;
+ st->send_ptr.Set((TUint8*)wdata->data, (TInt)wdata->data_len);
+ status = ssock->sock->Send(&send_cb, ssock, st->send_ptr, flags);
+
+ if (status != PJ_EPENDING) {
+ *size = -status;
+ return status;
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Send datagram using the socket.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
+ pj_ioqueue_op_key_t *send_key,
+ const void *data,
+ pj_ssize_t *size,
+ unsigned flags,
+ const pj_sockaddr_t *addr,
+ int addr_len)
+{
+ PJ_UNUSED_ARG(ssock);
+ PJ_UNUSED_ARG(send_key);
+ PJ_UNUSED_ARG(data);
+ PJ_UNUSED_ARG(size);
+ PJ_UNUSED_ARG(flags);
+ PJ_UNUSED_ARG(addr);
+ PJ_UNUSED_ARG(addr_len);
+ return PJ_ENOTSUP;
+}
+
+/*
+ * Starts asynchronous socket accept() operations on this SSL socket.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
+ pj_pool_t *pool,
+ const pj_sockaddr_t *local_addr,
+ int addr_len)
+{
+ PJ_UNUSED_ARG(ssock);
+ PJ_UNUSED_ARG(pool);
+ PJ_UNUSED_ARG(local_addr);
+ PJ_UNUSED_ARG(addr_len);
+
+ return PJ_ENOTSUP;
+}
+
+static void connect_cb(int err, void *key)
+{
+ pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)key;
+ pj_status_t status;
+
+ if (ssock->connect_timer) {
+ delete ssock->connect_timer;
+ ssock->connect_timer = NULL;
+ }
+
+ status = (err == KErrNone)? PJ_SUCCESS : PJ_RETURN_OS_ERROR(err);
+ if (status == PJ_SUCCESS) {
+ ssock->established = PJ_TRUE;
+ update_certs_info(ssock);
+ } else {
+ delete ssock->sock;
+ ssock->sock = NULL;
+ if (err == KErrTimedOut) status = PJ_ETIMEDOUT;
+ }
+
+ if (ssock->cb.on_connect_complete) {
+ pj_bool_t ret = (*ssock->cb.on_connect_complete)(ssock, status);
+ if (!ret) {
+ /* We've been destroyed */
+ return;
+ }
+ }
+}
+
+static void connect_timer_cb(void *key)
+{
+ connect_cb(KErrTimedOut, key);
+}
+
+/*
+ * Starts asynchronous socket connect() operation and SSL/TLS handshaking
+ * for this socket. Once the connection is done (either successfully or not),
+ * the \a on_connect_complete() callback will be called.
+ */
+PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
+ pj_pool_t *pool,
+ const pj_sockaddr_t *localaddr,
+ const pj_sockaddr_t *remaddr,
+ int addr_len)
+{
+ CPjSSLSocket *sock = NULL;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
+ PJ_EINVAL);
+
+ /* Check connection status */
+ PJ_SYMBIAN_CHECK_CONNECTION();
+
+ if (ssock->sock != NULL) {
+ CPjSSLSocket::ssl_state state = ssock->sock->GetState();
+ switch (state) {
+ case CPjSSLSocket::SSL_STATE_ESTABLISHED:
+ return PJ_SUCCESS;
+ default:
+ return PJ_EPENDING;
+ }
+ }
+
+ /* Set SSL protocol */
+ TPtrC8 proto;
+
+ if (ssock->proto == PJ_SSL_SOCK_PROTO_DEFAULT)
+ ssock->proto = PJ_SSL_SOCK_PROTO_TLS1;
+
+ /* CSecureSocket only support TLS1.0 and SSL3.0 */
+ switch(ssock->proto) {
+ case PJ_SSL_SOCK_PROTO_TLS1:
+ proto.Set((const TUint8*)"TLS1.0", 6);
+ break;
+ case PJ_SSL_SOCK_PROTO_SSL3:
+ proto.Set((const TUint8*)"SSL3.0", 6);
+ break;
+ default:
+ return PJ_ENOTSUP;
+ }
+
+ /* Prepare addresses */
+ TInetAddr localaddr_, remaddr_;
+ status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)localaddr, addr_len,
+ localaddr_);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)remaddr, addr_len,
+ remaddr_);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_sockaddr_cp((pj_sockaddr_t*)&ssock->rem_addr, remaddr);
+
+ /* Init SSL engine */
+ TRAPD(err, sock = CPjSSLSocket::NewL(proto, ssock->qos_type,
+ ssock->qos_params));
+ if (err != KErrNone)
+ return PJ_ENOMEM;
+
+ if (ssock->timeout.sec != 0 || ssock->timeout.msec != 0) {
+ ssock->connect_timer = new CPjTimer(&ssock->timeout,
+ &connect_timer_cb, ssock);
+ }
+
+ /* Convert server name to Symbian descriptor */
+ TPtrC8 servername_((TUint8*)ssock->servername.ptr,
+ ssock->servername.slen);
+
+ /* Convert cipher list to Symbian descriptor */
+ TPtrC8 ciphers_((TUint8*)ssock->ciphers.ptr,
+ ssock->ciphers.slen);
+
+ /* Try to connect */
+ status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
+ servername_, ciphers_);
+ if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+ delete sock;
+ return status;
+ }
+
+ ssock->sock = sock;
+ return status;
+}
+
+
+PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
+{
+ PJ_UNUSED_ARG(ssock);
+ return PJ_ENOTSUP;
+}
diff --git a/jni/pjproject-android/.svn/pristine/61/61502019e929e0928e8aea81c12dd935ccd8d34d.svn-base b/jni/pjproject-android/.svn/pristine/61/61502019e929e0928e8aea81c12dd935ccd8d34d.svn-base
new file mode 100644
index 0000000..e03a20c
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/61/61502019e929e0928e8aea81c12dd935ccd8d34d.svn-base
@@ -0,0 +1,438 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="py_pjsua"
+ ProjectGUID="{C44FC030-D46A-47FF-B731-B47ECA5B2B10}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\pjlib\include,..\..\pjlib-util\include,..\..\pjmedia\include,..\..\pjsip\include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="python24.lib ole32.lib shell32.lib user32.lib odbc32.lib odbccp32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib iphlpapi.lib"
+ OutputFile="..\bin\py-pjsua-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).exe"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\pjlib\include,..\..\pjlib-util\include,..\..\pjmedia\include,..\..\pjsip\include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="python24_d.lib ole32.lib shell32.lib user32.lib odbc32.lib odbccp32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib iphlpapi.lib"
+ OutputFile="..\bin\py-pjsua-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).exe"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\pjlib\include,..\..\pjlib-util\include,..\..\pjmedia\include,..\..\pjsip\include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="python24.lib ole32.lib shell32.lib user32.lib odbc32.lib odbccp32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib iphlpapi.lib"
+ OutputFile="..\bin\py-pjsua-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).exe"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\pjlib\include,..\..\pjlib-util\include,..\..\pjmedia\include,..\..\pjsip\include,../../pjnath/include"
+ PreprocessorDefinitions="_LIB;"
+ PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="python24_d.lib ole32.lib shell32.lib user32.lib odbc32.lib odbccp32.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib iphlpapi.lib"
+ OutputFile="..\bin\py-pjsua-$(TargetCPU)-$(PlatformName)-vc$(VSVer)-$(ConfigurationName).exe"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="..\src\py_pjsua\pjsua.py"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\py_pjsua\pjsua_app.py"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\py_pjsua\py_pjsua.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\py_pjsua\py_pjsua.def"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="..\src\py_pjsua\py_pjsua.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/jni/pjproject-android/.svn/pristine/61/6171fba387578fdd349de9274c92842e299f800b.svn-base b/jni/pjproject-android/.svn/pristine/61/6171fba387578fdd349de9274c92842e299f800b.svn-base
new file mode 100644
index 0000000..09b01bb
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/61/6171fba387578fdd349de9274c92842e299f800b.svn-base
@@ -0,0 +1,176 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 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 __PJMEDIA_DELAYBUF_H__
+#define __PJMEDIA_DELAYBUF_H__
+
+
+/**
+ * @file delaybuf.h
+ * @brief Delay Buffer.
+ */
+
+#include <pjmedia/types.h>
+
+/**
+ * @defgroup PJMED_DELAYBUF Adaptive Delay Buffer
+ * @ingroup PJMEDIA_FRAME_OP
+ * @brief Adaptive delay buffer with high-quality time-scale
+ * modification
+ * @{
+ *
+ * This section describes PJMEDIA's implementation of delay buffer.
+ * Delay buffer works quite similarly like a fixed jitter buffer, that
+ * is it will delay the frame retrieval by some interval so that caller
+ * will get continuous frame from the buffer. This can be useful when
+ * the put() and get() operations are not evenly interleaved, for example
+ * when caller performs burst of put() operations and then followed by
+ * burst of get() operations. With using this delay buffer, the buffer
+ * will put the burst frames into a buffer so that get() operations
+ * will always get a frame from the buffer (assuming that the number of
+ * get() and put() are matched).
+ *
+ * The buffer is adaptive, that is it continuously learns the optimal delay
+ * to be applied to the audio flow at run-time. Once the optimal delay has
+ * been learned, the delay buffer will apply this delay to the audio flow,
+ * expanding or shrinking the audio samples as necessary when the actual
+ * audio samples in the buffer are too low or too high. It does this without
+ * distorting the audio quality of the audio, by using \a PJMED_WSOLA.
+ *
+ * The delay buffer is used in \ref PJMED_SND_PORT, \ref PJMEDIA_SPLITCOMB,
+ * and \ref PJMEDIA_CONF.
+ */
+
+PJ_BEGIN_DECL
+
+/** Opaque declaration for delay buffer. */
+typedef struct pjmedia_delay_buf pjmedia_delay_buf;
+
+/**
+ * Delay buffer options.
+ */
+typedef enum pjmedia_delay_buf_flag
+{
+ /**
+ * Use simple FIFO mechanism for the delay buffer, i.e.
+ * without WSOLA for expanding and shrinking audio samples.
+ */
+ PJMEDIA_DELAY_BUF_SIMPLE_FIFO = 1
+
+} pjmedia_delay_buf_flag;
+
+/**
+ * Create the delay buffer. Once the delay buffer is created, it will
+ * enter learning state unless the delay argument is specified, which
+ * in this case it will directly enter the running state.
+ *
+ * @param pool Pool where the delay buffer will be allocated
+ * from.
+ * @param name Optional name for the buffer for log
+ * identification.
+ * @param clock_rate Number of samples processed per second.
+ * @param samples_per_frame Number of samples per frame.
+ * @param channel_count Number of channel per frame.
+ * @param max_delay Maximum number of delay to be accommodated,
+ * in ms, if this value is negative or less than
+ * one frame time, default maximum delay used is
+ * 400 ms.
+ * @param options Options. If PJMEDIA_DELAY_BUF_SIMPLE_FIFO is
+ * specified, then a simple FIFO mechanism
+ * will be used instead of the adaptive
+ * implementation (which uses WSOLA to expand
+ * or shrink audio samples).
+ * See #pjmedia_delay_buf_flag for other options.
+ * @param p_b Pointer to receive the delay buffer instance.
+ *
+ * @return PJ_SUCCESS if the delay buffer has been
+ * created successfully, otherwise the appropriate
+ * error will be returned.
+ */
+PJ_DECL(pj_status_t) pjmedia_delay_buf_create(pj_pool_t *pool,
+ const char *name,
+ unsigned clock_rate,
+ unsigned samples_per_frame,
+ unsigned channel_count,
+ unsigned max_delay,
+ unsigned options,
+ pjmedia_delay_buf **p_b);
+
+/**
+ * Put one frame into the buffer.
+ *
+ * @param b The delay buffer.
+ * @param frame Frame to be put into the buffer. This frame
+ * must have samples_per_frame length.
+ *
+ * @return PJ_SUCCESS if frames can be put successfully.
+ * PJ_EPENDING if the buffer is still at learning
+ * state. PJ_ETOOMANY if the number of frames
+ * will exceed maximum delay level, which in this
+ * case the new frame will overwrite the oldest
+ * frame in the buffer.
+ */
+PJ_DECL(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
+ pj_int16_t frame[]);
+
+/**
+ * Get one frame from the buffer.
+ *
+ * @param b The delay buffer.
+ * @param frame Buffer to receive the frame from the delay
+ * buffer.
+ *
+ * @return PJ_SUCCESS if frame has been copied successfully.
+ * PJ_EPENDING if no frame is available, either
+ * because the buffer is still at learning state or
+ * no buffer is available during running state.
+ * On non-successful return, the frame will be
+ * filled with zeroes.
+ */
+PJ_DECL(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b,
+ pj_int16_t frame[]);
+
+/**
+ * Reset delay buffer. This will clear the buffer's content. But keep
+ * the learning result.
+ *
+ * @param b The delay buffer.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b);
+
+/**
+ * Destroy delay buffer.
+ *
+ * @param b Delay buffer session.
+ *
+ * @return PJ_SUCCESS normally.
+ */
+PJ_DECL(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b);
+
+
+PJ_END_DECL
+
+/**
+ * @}
+ */
+
+#endif /* __PJMEDIA_DELAYBUF_H__ */
diff --git a/jni/pjproject-android/.svn/pristine/61/619e69678cd019676a1491fb3acf2e5f55368e3e.svn-base b/jni/pjproject-android/.svn/pristine/61/619e69678cd019676a1491fb3acf2e5f55368e3e.svn-base
new file mode 100644
index 0000000..0611747
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/61/619e69678cd019676a1491fb3acf2e5f55368e3e.svn-base
@@ -0,0 +1,460 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJLIB_UTIL_RESOLVER_H__
+#define __PJLIB_UTIL_RESOLVER_H__
+
+/**
+ * @file resolver.h
+ * @brief Asynchronous DNS resolver
+ */
+#include <pjlib-util/dns.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @defgroup PJ_DNS_RESOLVER DNS Asynchronous/Caching Resolution Engine
+ * @ingroup PJ_DNS
+ * @{
+ *
+ * This module manages the host/server resolution by performing asynchronous
+ * DNS queries and caching the results in the cache. It uses PJLIB-UTIL
+ * low-level DNS parsing functions (see @ref PJ_DNS) and currently supports
+ * several types of DNS resource records such as A record (typical query with
+ * gethostbyname()) and SRV record.
+ *
+ * \section PJ_DNS_RESOLVER_FEATURES Features
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_ASYNC Asynchronous Query and Query Aggregation
+ *
+ * The DNS queries are performed asychronously, with timeout setting
+ * configured on per resolver instance basis. Application can issue multiple
+ * asynchronous queries simultaneously. Subsequent queries to the same resource
+ * (name and DNS resource type) while existing query is still pending will be
+ * merged into one query, so that only one DNS request packet is issued.
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_RETRANSMISSION Query Retransmission
+ *
+ * Asynchronous query will be retransmitted if no response is received
+ * within the preconfigured time. Once maximum retransmission count is
+ * exceeded and no response is received, the query will time out and the
+ * callback will be called when error status.
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_CACHING Response Caching with TTL
+ *
+ * The resolver instance caches the results returned by nameservers, to
+ * enhance the performance by minimizing the message round-trip to the server.
+ * The TTL of the cached resposne is calculated from minimum TTL value found
+ * across all resource record (RR) TTL in the response and further more it can
+ * be limited to some preconfigured maximum TTL in the resolver.
+ *
+ * Response caching can be disabled by setting the maximum TTL value of the
+ * resolver to zero.
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_PARALLEL Parallel and Backup Name Servers
+ *
+ * When the resolver is configured with multiple nameservers, initially the
+ * queries will be issued to multiple name servers simultaneously to probe
+ * which servers are not active. Once the probing stage is done, subsequent
+ * queries will be directed to only one ACTIVE server which provides the best
+ * response time.
+ *
+ * Name servers are probed periodically to see which nameservers are active
+ * and which are down. This probing is done when a query is sent, thus no
+ * timer is needed to maintain this. Also probing will be done in parallel
+ * so that there would be no additional delay for the query.
+ *
+ *
+ * \subsection PJ_DNS_RESOLVER_FEATURES_REC Supported Resource Records
+ *
+ * The low-level DNS parsing utility (see @ref PJ_DNS) supports parsing of
+ * the following DNS resource records (RR):
+ * - DNS A record
+ * - DNS SRV record
+ * - DNS PTR record
+ * - DNS NS record
+ * - DNS CNAME record
+ *
+ * For other types of record, application can parse the raw resource
+ * record data (rdata) from the parsed DNS packet (#pj_dns_parsed_packet).
+ *
+ *
+ * \section PJ_DNS_RESOLVER_USING Using the Resolver
+ *
+ * To use the resolver, application first creates the resolver instance by
+ * calling #pj_dns_resolver_create(). If application already has its own
+ * timer and ioqueue instances, it can instruct the resolver to use these
+ * instances so that application does not need to poll the resolver
+ * periodically to process events. If application does not specify the
+ * timer and ioqueue instance for the resolver, an internal timer and
+ * ioqueue will be created by the resolver. And since the resolver does not
+ * create it's own thread, application MUST poll the resolver periodically
+ * by calling #pj_dns_resolver_handle_events() to allow events (network and
+ * timer) to be processed.
+ *
+ * Next, application MUST configure the nameservers to be used by the
+ * resolver, by calling #pj_dns_resolver_set_ns().
+ *
+ * Application performs asynchronous query by submitting the query with
+ * #pj_dns_resolver_start_query(). Once the query completes (either
+ * successfully or times out), the callback will be called.
+ *
+ * Application can cancel a pending query by calling #pj_dns_resolver_cancel_query().
+ *
+ * Resolver must be destroyed by calling #pj_dns_resolver_destroy() to
+ * release all resources back to the system.
+ *
+ *
+ * \section PJ_DNS_RESOLVER_LIMITATIONS Resolver Limitations
+ *
+ * Current implementation mainly suffers from a growing memory problem,
+ * which mainly is caused by the response caching. Although there is only
+ * one cache entry per {query, name} combination, these cache entry will
+ * never get deleted since there is no timer is created to invalidate these
+ * entries. So the more unique names being queried by application, there more
+ * enties will be created in the response cache.
+ *
+ * Note that a single response entry will occupy about 600-700 bytes of
+ * pool memory (the PJ_DNS_RESOLVER_RES_BUF_SIZE value plus internal
+ * structure).
+ *
+ * Application can work around this problem by doing one of these:
+ * - disable caching by setting PJ_DNS_RESOLVER_MAX_TTL and
+ * PJ_DNS_RESOLVER_INVALID_TTL to zero.
+ * - periodically query #pj_dns_resolver_get_cached_count() and destroy-
+ * recreate the resolver to recycle the memory used by the resolver.
+ *
+ * Note that future improvement may solve this problem by introducing
+ * expiration timer to the cached entries.
+ *
+ *
+ * \section PJ_DNS_RESOLVER_REFERENCE Reference
+ *
+ * The PJLIB-UTIL resolver was built from the information in the following
+ * standards:
+ * - <A HREF="http://www.faqs.org/rfcs/rfc1035.html">
+ * RFC 1035: "Domain names - implementation and specification"</A>
+ * - <A HREF="http://www.faqs.org/rfcs/rfc2782.html">
+ * RFC 2782: "A DNS RR for specifying the location of services (DNS SRV)"
+ * </A>
+ */
+
+
+
+/**
+ * Opaque data type for DNS resolver object.
+ */
+typedef struct pj_dns_resolver pj_dns_resolver;
+
+/**
+ * Opaque data type for asynchronous DNS query object.
+ */
+typedef struct pj_dns_async_query pj_dns_async_query;
+
+/**
+ * Type of asynchronous callback which will be called when the asynchronous
+ * query completes.
+ *
+ * @param user_data The user data set by application when creating the
+ * asynchronous query.
+ * @param status Status of the DNS resolution.
+ * @param response The response packet received from the server. This
+ * argument may be NULL when status is not PJ_SUCCESS.
+ */
+typedef void pj_dns_callback(void *user_data,
+ pj_status_t status,
+ pj_dns_parsed_packet *response);
+
+
+/**
+ * This structure describes resolver settings.
+ */
+typedef struct pj_dns_settings
+{
+ unsigned options; /**< Options flags. */
+ unsigned qretr_delay; /**< Query retransmit delay in msec. */
+ unsigned qretr_count; /**< Query maximum retransmission count. */
+ unsigned cache_max_ttl; /**< Maximum TTL for cached responses. If the
+ value is zero, caching is disabled. */
+ unsigned good_ns_ttl; /**< See #PJ_DNS_RESOLVER_GOOD_NS_TTL */
+ unsigned bad_ns_ttl; /**< See #PJ_DNS_RESOLVER_BAD_NS_TTL */
+} pj_dns_settings;
+
+
+/**
+ * This structure represents DNS A record, as the result of parsing
+ * DNS response packet using #pj_dns_parse_a_response().
+ */
+typedef struct pj_dns_a_record
+{
+ /** The target name being queried. */
+ pj_str_t name;
+
+ /** If target name corresponds to a CNAME entry, the alias contains
+ * the value of the CNAME entry, otherwise it will be empty.
+ */
+ pj_str_t alias;
+
+ /** Number of IP addresses. */
+ unsigned addr_count;
+
+ /** IP addresses of the host found in the response */
+ pj_in_addr addr[PJ_DNS_MAX_IP_IN_A_REC];
+
+ /** Internal buffer for hostname and alias. */
+ char buf_[128];
+
+} pj_dns_a_record;
+
+
+/**
+ * Set default values to the DNS settings.
+ *
+ * @param s The DNS settings to be initialized.
+ */
+PJ_DECL(void) pj_dns_settings_default(pj_dns_settings *s);
+
+
+/**
+ * Create DNS resolver instance. After the resolver is created, application
+ * MUST configure the nameservers with #pj_dns_resolver_set_ns().
+ *
+ * When creating the resolver, application may specify both timer heap
+ * and ioqueue instance, so that it doesn't need to poll the resolver
+ * periodically.
+ *
+ * @param pf Pool factory where the memory pool will be created from.
+ * @param name Optional resolver name to identify the instance in
+ * the log.
+ * @param options Optional options, must be zero for now.
+ * @param timer Optional timer heap instance to be used by the resolver.
+ * If timer heap is not specified, an internal timer will be
+ * created, and application would need to poll the resolver
+ * periodically.
+ * @param ioqueue Optional I/O Queue instance to be used by the resolver.
+ * If ioqueue is not specified, an internal one will be
+ * created, and application would need to poll the resolver
+ * periodically.
+ * @param p_resolver Pointer to receive the resolver instance.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_create(pj_pool_factory *pf,
+ const char *name,
+ unsigned options,
+ pj_timer_heap_t *timer,
+ pj_ioqueue_t *ioqueue,
+ pj_dns_resolver **p_resolver);
+
+
+/**
+ * Update the name servers for the DNS resolver. The name servers MUST be
+ * configured before any resolution can be done. The order of nameservers
+ * specifies their priority; the first name server will be tried first
+ * before the next in the list.
+ *
+ * @param resolver The resolver instance.
+ * @param count Number of name servers in the array.
+ * @param servers Array of name server IP addresses or hostnames. If
+ * hostname is specified, the hostname must be resolvable
+ * with pj_gethostbyname().
+ * @param ports Optional array of ports. If this argument is NULL,
+ * the nameserver will use default port.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_set_ns(pj_dns_resolver *resolver,
+ unsigned count,
+ const pj_str_t servers[],
+ const pj_uint16_t ports[]);
+
+
+/**
+ * Get the resolver current settings.
+ *
+ * @param resolver The resolver instance.
+ * @param st Buffer to be filled up with resolver settings.
+ *
+ * @return The query timeout setting, in seconds.
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_get_settings(pj_dns_resolver *resolver,
+ pj_dns_settings *st);
+
+
+/**
+ * Modify the resolver settings. Application should initialize the settings
+ * by retrieving current settings first before applying new settings, to
+ * ensure that all fields are initialized properly.
+ *
+ * @param resolver The resolver instance.
+ * @param st The resolver settings.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_set_settings(pj_dns_resolver *resolver,
+ const pj_dns_settings *st);
+
+
+/**
+ * Poll for events from the resolver. This function MUST be called
+ * periodically when the resolver is using it's own timer or ioqueue
+ * (in other words, when NULL is specified as either \a timer or
+ * \a ioqueue argument in #pj_dns_resolver_create()).
+ *
+ * @param resolver The resolver instance.
+ * @param timeout Maximum time to wait for event occurence. If this
+ * argument is NULL, this function will wait forever
+ * until events occur.
+ */
+PJ_DECL(void) pj_dns_resolver_handle_events(pj_dns_resolver *resolver,
+ const pj_time_val *timeout);
+
+
+/**
+ * Destroy DNS resolver instance.
+ *
+ * @param resolver The resolver object to be destryed
+ * @param notify If non-zero, all pending asynchronous queries will be
+ * cancelled and its callback will be called. If FALSE,
+ * then no callback will be called.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_destroy(pj_dns_resolver *resolver,
+ pj_bool_t notify);
+
+
+/**
+ * Create and start asynchronous DNS query for a single resource. Depending
+ * on whether response cache is available, this function will either start
+ * an asynchronous DNS query or call the callback immediately.
+ *
+ * If response is not available in the cache, an asynchronous query will be
+ * started, and callback will be called at some time later when the query
+ * completes. If \a p_query argument is not NULL, it will be filled with
+ * the asynchronous query object.
+ *
+ * If response is available in the cache, the callback will be called
+ * immediately before this function returns. In this case, if \a p_query
+ * argument is not NULL, the value will be set to NULL since no new query
+ * is started.
+ *
+ * @param resolver The resolver object.
+ * @param name The name to be resolved.
+ * @param type The type of resource (see #pj_dns_type constants).
+ * @param options Optional options, must be zero for now.
+ * @param cb Callback to be called when the query completes,
+ * either successfully or with failure.
+ * @param user_data Arbitrary user data to be associated with the query,
+ * and which will be given back in the callback.
+ * @param p_query Optional pointer to receive the query object, if one
+ * was started. If this pointer is specified, a NULL may
+ * be returned if response cache is available immediately.
+ *
+ * @return PJ_SUCCESS if either an asynchronous query has been
+ * started successfully or response cache is available and
+ * the user callback has been called.
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_start_query(pj_dns_resolver *resolver,
+ const pj_str_t *name,
+ int type,
+ unsigned options,
+ pj_dns_callback *cb,
+ void *user_data,
+ pj_dns_async_query **p_query);
+
+/**
+ * Cancel a pending query.
+ *
+ * @param query The pending asynchronous query to be cancelled.
+ * @param notify If non-zero, the callback will be called with failure
+ * status to notify that the query has been cancelled.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code,
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,
+ pj_bool_t notify);
+
+/**
+ * A utility function to parse a DNS response containing A records into
+ * DNS A record.
+ *
+ * @param pkt The DNS response packet.
+ * @param rec The structure to be initialized with the parsed
+ * DNS A record from the packet.
+ *
+ * @return PJ_SUCCESS if response can be parsed successfully.
+ */
+PJ_DECL(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
+ pj_dns_a_record *rec);
+
+
+/**
+ * Put the specified DNS packet into DNS cache. This function is mainly used
+ * for testing the resolver, however it can also be used to inject entries
+ * into the resolver.
+ *
+ * The packet MUST contain either answer section or query section so that
+ * it can be indexed.
+ *
+ * @param resolver The resolver instance.
+ * @param pkt DNS packet to be added to the DNS cache. If the packet
+ * matches existing entry, it will update the entry.
+ * @param set_ttl If the value is PJ_FALSE, the entry will not expire
+ * (so use with care). Otherwise cache expiration will be
+ * calculated based on the TTL of the answeres.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_dns_resolver_add_entry(pj_dns_resolver *resolver,
+ const pj_dns_parsed_packet *pkt,
+ pj_bool_t set_ttl);
+
+/**
+ * Get the total number of response in the response cache.
+ *
+ * @param resolver The resolver instance.
+ *
+ * @return Current number of entries being stored in the response
+ * cache.
+ */
+PJ_DECL(unsigned) pj_dns_resolver_get_cached_count(pj_dns_resolver *resolver);
+
+
+/**
+ * Dump resolver state to the log.
+ *
+ * @param resolver The resolver instance.
+ * @param detail Will print detailed entries.
+ */
+PJ_DECL(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
+ pj_bool_t detail);
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif /* __PJLIB_UTIL_RESOLVER_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/61/61d5e1488c31ac78b69dc31023ab27fc963166bd.svn-base b/jni/pjproject-android/.svn/pristine/61/61d5e1488c31ac78b69dc31023ab27fc963166bd.svn-base
new file mode 100644
index 0000000..849e354
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/61/61d5e1488c31ac78b69dc31023ab27fc963166bd.svn-base
@@ -0,0 +1,7 @@
+#!/bin/sh
+./aconfigure $*
+
+# Note:
+# if you're looking for the old configure script, it has been renamed
+# to configure-legacy
+