summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2010-03-06 02:04:52 +0000
committerNanang Izzuddin <nanang@teluu.com>2010-03-06 02:04:52 +0000
commit5ef168f30582cfd441def20089c1d503128ec159 (patch)
tree1a5a348f460b78fce48c3942ffce9405f56f4253
parentac131cb38e62d9b73fc857e270430c0f9ecab27c (diff)
Ticket #1043:
- Fixed bug of unused timeout setting in Symbian SSL socket, ssl_sock_symbian.cpp. - Added an SSL test scenario of SSL connect timeout, SSL socket client tries to connect to non-SSL socket server. - Fixed OpenSSL-based SSL socket to start SSL timer before TCP connect (was started after TCP connected and before SSL handshake). git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3117 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjlib/src/pj/ssl_sock_ossl.c28
-rw-r--r--pjlib/src/pj/ssl_sock_symbian.cpp24
-rw-r--r--pjlib/src/pjlib-test/ssl_sock.c213
3 files changed, 238 insertions, 27 deletions
diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
index 7fe0c435..3528fe72 100644
--- a/pjlib/src/pj/ssl_sock_ossl.c
+++ b/pjlib/src/pj/ssl_sock_ossl.c
@@ -1165,7 +1165,7 @@ static void on_timer(pj_timer_heap_t *th, struct pj_timer_entry *te)
switch (timer_id) {
case TIMER_HANDSHAKE_TIMEOUT:
- PJ_LOG(1,(ssock->pool->obj_name, "SSL handshake timeout after %d.%ds",
+ PJ_LOG(1,(ssock->pool->obj_name, "SSL timeout after %d.%ds",
ssock->param.timeout.sec, ssock->param.timeout.msec));
on_handshake_complete(ssock, PJ_ETIMEDOUT);
@@ -1607,19 +1607,6 @@ static pj_bool_t asock_on_connect_complete (pj_activesock_t *asock,
ssock->write_state.start = ssock->write_state.buf;
ssock->write_state.len = 0;
- /* Start handshake timer */
- if (ssock->param.timer_heap && (ssock->param.timeout.sec != 0 ||
- ssock->param.timeout.msec != 0))
- {
- pj_assert(ssock->timer.id == TIMER_NONE);
- ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
- status = pj_timer_heap_schedule(ssock->param.timer_heap,
- &ssock->timer,
- &ssock->param.timeout);
- if (status != PJ_SUCCESS)
- ssock->timer.id = TIMER_NONE;
- }
-
#ifdef SSL_set_tlsext_host_name
/* Set server name to connect */
if (ssock->param.server_name.slen) {
@@ -2290,6 +2277,19 @@ PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
/* Save remote address */
pj_sockaddr_cp(&ssock->rem_addr, remaddr);
+ /* Start timer */
+ if (ssock->param.timer_heap && (ssock->param.timeout.sec != 0 ||
+ ssock->param.timeout.msec != 0))
+ {
+ pj_assert(ssock->timer.id == TIMER_NONE);
+ ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
+ status = pj_timer_heap_schedule(ssock->param.timer_heap,
+ &ssock->timer,
+ &ssock->param.timeout);
+ if (status != PJ_SUCCESS)
+ ssock->timer.id = TIMER_NONE;
+ }
+
status = pj_activesock_start_connect(ssock->asock, pool, remaddr,
addr_len);
diff --git a/pjlib/src/pj/ssl_sock_symbian.cpp b/pjlib/src/pj/ssl_sock_symbian.cpp
index 65916d73..9237ef13 100644
--- a/pjlib/src/pj/ssl_sock_symbian.cpp
+++ b/pjlib/src/pj/ssl_sock_symbian.cpp
@@ -171,7 +171,8 @@ private:
delete reader_;
reader_ = NULL;
if (securesock_) {
- securesock_->Close();
+ if (state_ == SSL_STATE_ESTABLISHED)
+ securesock_->Close();
delete securesock_;
securesock_ = NULL;
}
@@ -213,10 +214,9 @@ int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
key_ = key;
rem_addr_ = rem_addr;
servername_.Set(servername);
- state_ = SSL_STATE_CONNECTING;
-
rSock.Connect(rem_addr_, iStatus);
SetActive();
+ state_ = SSL_STATE_CONNECTING;
rSock.LocalName(local_addr_);
@@ -276,20 +276,16 @@ void CPjSSLSocket::DoCancel()
case SSL_STATE_CONNECTING:
{
RSocket &rSock = ((CPjSocket*)sock_)->Socket();
+
rSock.CancelConnect();
-
CleanupSubObjects();
-
state_ = SSL_STATE_NULL;
}
break;
case SSL_STATE_HANDSHAKING:
{
securesock_->CancelHandshake();
- securesock_->Close();
-
CleanupSubObjects();
-
state_ = SSL_STATE_NULL;
}
break;
@@ -322,7 +318,15 @@ void CPjSSLSocket::RunL()
if (servername_.Length() > 0)
securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
servername_);
- securesock_->FlushSessionCache();
+
+ // 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;
@@ -647,6 +651,7 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
ssock->sock_type = param->sock_type;
ssock->cb = param->cb;
ssock->user_data = param->user_data;
+ ssock->timeout = param->timeout;
ssock->ciphers_num = param->ciphers_num;
if (param->ciphers_num > 0) {
unsigned i;
@@ -1153,6 +1158,7 @@ static void connect_cb(int err, void *key)
} else {
delete ssock->sock;
ssock->sock = NULL;
+ if (err == KErrTimedOut) status = PJ_ETIMEDOUT;
}
if (ssock->cb.on_connect_complete) {
diff --git a/pjlib/src/pjlib-test/ssl_sock.c b/pjlib/src/pjlib-test/ssl_sock.c
index 68769501..ab3f9f3e 100644
--- a/pjlib/src/pjlib-test/ssl_sock.c
+++ b/pjlib/src/pjlib-test/ssl_sock.c
@@ -68,6 +68,7 @@ static int get_cipher_list(void) {
struct test_state
{
pj_pool_t *pool; /* pool */
+ pj_ioqueue_t *ioqueue; /* ioqueue */
pj_bool_t is_server; /* server role flag */
pj_bool_t is_verbose; /* verbose flag, e.g: cert info */
pj_bool_t echo; /* echo received data */
@@ -746,6 +747,47 @@ static pj_bool_t asock_on_connect_complete(pj_activesock_t *asock,
return PJ_TRUE;
}
+static pj_bool_t asock_on_accept_complete(pj_activesock_t *asock,
+ pj_sock_t newsock,
+ const pj_sockaddr_t *src_addr,
+ int src_addr_len)
+{
+ struct test_state *st;
+ void *read_buf[1];
+ pj_activesock_t *new_asock;
+ pj_activesock_cb asock_cb = { 0 };
+ pj_status_t status;
+
+ PJ_UNUSED_ARG(src_addr);
+ PJ_UNUSED_ARG(src_addr_len);
+
+ st = (struct test_state*) pj_activesock_get_user_data(asock);
+
+ asock_cb.on_data_read = &asock_on_data_read;
+ status = pj_activesock_create(st->pool, newsock, pj_SOCK_STREAM(), NULL,
+ st->ioqueue, &asock_cb, st, &new_asock);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ /* Start reading data */
+ read_buf[0] = st->read_buf;
+ status = pj_activesock_start_read2(new_asock, st->pool,
+ sizeof(st->read_buf),
+ (void**)read_buf, 0);
+ if (status != PJ_SUCCESS) {
+ app_perror("...ERROR pj_ssl_sock_start_read2()", status);
+ }
+
+on_return:
+ st->err = status;
+
+ if (st->err != PJ_SUCCESS)
+ pj_activesock_close(new_asock);
+
+ return PJ_TRUE;
+}
+
/* Raw TCP socket try to connect to SSL socket server, once
* connection established, it will just do nothing, SSL socket
@@ -903,6 +945,158 @@ on_return:
}
+/* SSL socket try to connect to raw TCP socket server, once
+ * connection established, SSL socket will try to perform SSL
+ * handshake. SSL client socket should be able to close the
+ * connection after specified timeout period (set ms_timeout to
+ * 0 to disable timer).
+ */
+static int server_non_ssl(unsigned ms_timeout)
+{
+ pj_pool_t *pool = NULL;
+ pj_ioqueue_t *ioqueue = NULL;
+ pj_timer_heap_t *timer = NULL;
+ pj_activesock_t *asock_serv = NULL;
+ pj_ssl_sock_t *ssock_cli = NULL;
+ pj_activesock_cb asock_cb = { 0 };
+ pj_sock_t sock = PJ_INVALID_SOCKET;
+ pj_ssl_sock_param param;
+ struct test_state state_serv = { 0 };
+ struct test_state state_cli = { 0 };
+ pj_sockaddr addr, listen_addr;
+ pj_status_t status;
+
+ pool = pj_pool_create(mem, "ssl_connect_raw_tcp", 256, 256, NULL);
+
+ status = pj_ioqueue_create(pool, 4, &ioqueue);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ status = pj_timer_heap_create(pool, 4, &timer);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ /* SERVER */
+ state_serv.pool = pool;
+ state_serv.ioqueue = ioqueue;
+
+ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ /* Init bind address */
+ {
+ pj_str_t tmp_st;
+ pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
+ }
+
+ status = pj_sock_bind(sock, (pj_sockaddr_t*)&listen_addr,
+ pj_sockaddr_get_len((pj_sockaddr_t*)&listen_addr));
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ status = pj_sock_listen(sock, PJ_SOMAXCONN);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ asock_cb.on_accept_complete = &asock_on_accept_complete;
+ status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL,
+ ioqueue, &asock_cb, &state_serv, &asock_serv);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ status = pj_activesock_start_accept(asock_serv, pool);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Update listener address */
+ {
+ int addr_len;
+
+ addr_len = sizeof(listen_addr);
+ pj_sock_getsockname(sock, (pj_sockaddr_t*)&listen_addr, &addr_len);
+ }
+
+ /* CLIENT */
+ pj_ssl_sock_param_default(&param);
+ param.cb.on_connect_complete = &ssl_on_connect_complete;
+ param.cb.on_data_read = &ssl_on_data_read;
+ param.cb.on_data_sent = &ssl_on_data_sent;
+ param.ioqueue = ioqueue;
+ param.timer_heap = timer;
+ param.timeout.sec = 0;
+ param.timeout.msec = ms_timeout;
+ pj_time_val_normalize(&param.timeout);
+ param.user_data = &state_cli;
+
+ state_cli.pool = pool;
+ state_cli.is_server = PJ_FALSE;
+ state_cli.is_verbose = PJ_TRUE;
+
+ status = pj_ssl_sock_create(pool, &param, &ssock_cli);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ /* Init default bind address */
+ {
+ pj_str_t tmp_st;
+ pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
+ }
+
+ status = pj_ssl_sock_start_connect(ssock_cli, pool,
+ (pj_sockaddr_t*)&addr,
+ (pj_sockaddr_t*)&listen_addr,
+ pj_sockaddr_get_len(&listen_addr));
+ if (status != PJ_EPENDING) {
+ goto on_return;
+ }
+
+ /* Wait until everything has been sent/received or error */
+ while ((!state_serv.err && !state_serv.done) || (!state_cli.err && !state_cli.done))
+ {
+#ifdef PJ_SYMBIAN
+ pj_symbianos_poll(-1, 1000);
+#else
+ pj_time_val delay = {0, 100};
+ pj_ioqueue_poll(ioqueue, &delay);
+ pj_timer_heap_poll(timer, &delay);
+#endif
+ }
+
+ if (state_serv.err || state_cli.err) {
+ if (state_cli.err != PJ_SUCCESS)
+ status = state_cli.err;
+ else
+ status = state_serv.err;
+
+ goto on_return;
+ }
+
+ PJ_LOG(3, ("", "...Done!"));
+
+on_return:
+ if (asock_serv)
+ pj_activesock_close(asock_serv);
+ if (ssock_cli && !state_cli.err && !state_cli.done)
+ pj_ssl_sock_close(ssock_cli);
+ if (timer)
+ pj_timer_heap_destroy(timer);
+ if (ioqueue)
+ pj_ioqueue_destroy(ioqueue);
+ if (pool)
+ pj_pool_release(pool);
+
+ return status;
+}
+
+
/* Test will perform multiple clients trying to connect to single server.
* Once SSL connection established, echo test will be performed.
*/
@@ -1152,6 +1346,11 @@ int ssl_sock_test(void)
//return ret;
#ifndef PJ_SYMBIAN
+
+ /* On Symbian platforms, SSL socket is implemented using CSecureSocket,
+ * and it hasn't supported server mode, so exclude the following tests,
+ * which require SSL server, for now.
+ */
PJ_LOG(3,("", "..echo test w/ TLSv1 and PJ_TLS_RSA_WITH_DES_CBC_SHA cipher"));
ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1, PJ_SSL_SOCK_PROTO_TLS1,
@@ -1195,18 +1394,24 @@ int ssl_sock_test(void)
if (ret != 0)
return ret;
- PJ_LOG(3,("", "..client non-SSL (handshake timeout 5 secs)"));
- ret = client_non_ssl(5000);
+ PJ_LOG(3,("", "..performance test"));
+ ret = perf_test(PJ_IOQUEUE_MAX_HANDLES/2 - 1, 0);
if (ret != 0)
return ret;
- PJ_LOG(3,("", "..performance test"));
- ret = perf_test(PJ_IOQUEUE_MAX_HANDLES/2 - 1, 0);
+ PJ_LOG(3,("", "..client non-SSL (handshake timeout 5 secs)"));
+ ret = client_non_ssl(5000);
+ /* PJ_TIMEDOUT won't be returned as accepted socket is deleted silently */
if (ret != 0)
return ret;
#endif
+ PJ_LOG(3,("", "..server non-SSL (handshake timeout 5 secs)"));
+ ret = server_non_ssl(5000);
+ if (ret != PJ_ETIMEDOUT)
+ return ret;
+
return 0;
}