From cbb6c140cf6e47e65b31b93009cfe39916933009 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Tue, 18 Jul 2006 00:10:53 +0000 Subject: Fixed several bugs related to TCP: git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@610 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib/include/pj/compat/os_win32.h | 2 +- pjlib/src/pj/ioqueue_common_abs.c | 20 ++++++++++++++++---- pjsip/src/pjsip/sip_endpoint.c | 15 ++++++++++++++- pjsip/src/pjsip/sip_transaction.c | 10 ++++++++++ pjsip/src/pjsip/sip_transport_tcp.c | 32 +++++++++++++++++++++++--------- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/pjlib/include/pj/compat/os_win32.h b/pjlib/include/pj/compat/os_win32.h index cf7431d6..95d3cd6e 100644 --- a/pjlib/include/pj/compat/os_win32.h +++ b/pjlib/include/pj/compat/os_win32.h @@ -73,7 +73,7 @@ /* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return * the status of non-blocking connect() operation. */ -#define PJ_HAS_SO_ERROR 0 +#define PJ_HAS_SO_ERROR 1 /* This value specifies the value set in errno by the OS when a non-blocking * socket recv() or send() can not return immediately. diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c index 982c8080..5356f91d 100644 --- a/pjlib/src/pj/ioqueue_common_abs.c +++ b/pjlib/src/pj/ioqueue_common_abs.c @@ -209,8 +209,8 @@ void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h) { int value; socklen_t vallen = sizeof(value); - int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, - &value, &vallen); + int gs_rc = pj_sock_getsockopt(h->fd, SOL_SOCKET, SO_ERROR, + &value, &vallen); if (gs_rc != 0) { /* Argh!! What to do now??? * Just indicate that the socket is connected. The @@ -524,8 +524,20 @@ void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue, pj_mutex_unlock(h->mutex); /* Call callback. */ - if (h->cb.on_connect_complete && !IS_CLOSING(h)) - (*h->cb.on_connect_complete)(h, -1); + if (h->cb.on_connect_complete && !IS_CLOSING(h)) { + pj_status_t status = -1; +#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0) + int value; + socklen_t vallen = sizeof(value); + int gs_rc = pj_sock_getsockopt(h->fd, SOL_SOCKET, SO_ERROR, + &value, &vallen); + if (gs_rc == 0) { + status = PJ_RETURN_OS_ERROR(value); + } +#endif + + (*h->cb.on_connect_complete)(h, status); + } } /* diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c index a00c1af7..aedab9d7 100644 --- a/pjsip/src/pjsip/sip_endpoint.c +++ b/pjsip/src/pjsip/sip_endpoint.c @@ -282,6 +282,15 @@ PJ_DEF(pj_status_t) pjsip_endpt_unregister_module( pjsip_endpoint *endpt, on_return: pj_rwmutex_unlock_write(endpt->mod_mutex); + + if (status != PJ_SUCCESS) { + char errmsg[PJ_ERR_MSG_SIZE]; + + pj_strerror(status, errmsg, sizeof(errmsg)); + PJ_LOG(3,(THIS_FILE, "Module \"%.*s\" can not be unregistered: %s", + (int)mod->name.slen, mod->name.ptr, errmsg)); + } + return status; } @@ -526,8 +535,11 @@ PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt) PJ_LOG(5, (THIS_FILE, "Destroying endpoing instance..")); /* Unregister modules. */ - while ((mod=endpt->module_list.prev) != &endpt->module_list) { + mod = endpt->module_list.prev; + while (mod != &endpt->module_list) { + pjsip_module *prev = mod->prev; pjsip_endpt_unregister_module(endpt, mod); + mod = prev; } /* Shutdown and destroy all transports. */ @@ -595,6 +607,7 @@ PJ_DEF(void) pjsip_endpt_release_pool( pjsip_endpoint *endpt, pj_pool_t *pool ) */ pj_pool_release( pool ); + PJ_UNUSED_ARG(endpt); /* pj_mutex_unlock(endpt->mutex); */ diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c index 17e3ad15..6f714f2a 100644 --- a/pjsip/src/pjsip/sip_transaction.c +++ b/pjsip/src/pjsip/sip_transaction.c @@ -648,6 +648,15 @@ static pj_status_t mod_tsx_layer_stop(void) */ static pj_status_t mod_tsx_layer_unload(void) { + /* Only self destroy when there's no transaction in the table. + * Transaction may refuse to destroy when it has pending + * transmission. If we destroy the module now, application will + * crash when the pending transaction finally got error response + * from transport and when it tries to unregister itself. + */ + if (pj_hash_count(mod_tsx_layer.htable) != 0) + return PJ_EBUSY; + /* Destroy mutex. */ pj_mutex_destroy(mod_tsx_layer.mutex); @@ -927,6 +936,7 @@ static void tsx_destroy( pjsip_transaction *tsx ) /* Refuse to destroy transaction if it has pending resolving. */ if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) { tsx->transport_flag |= TSX_HAS_PENDING_DESTROY; + tsx->tsx_user = NULL; PJ_LOG(4,(tsx->obj_name, "Will destroy later because transport is " "in progress")); return; diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c index dc384d10..c9b92ad4 100644 --- a/pjsip/src/pjsip/sip_transport_tcp.c +++ b/pjsip/src/pjsip/sip_transport_tcp.c @@ -1240,15 +1240,6 @@ static void on_connect_complete(pj_ioqueue_key_t *key, tcp = pj_ioqueue_get_user_data(key); - PJ_LOG(4,(tcp->base.obj_name, - "TCP transport %.*s:%d is connected to %.*s:%d", - (int)tcp->base.local_name.host.slen, - tcp->base.local_name.host.ptr, - tcp->base.local_name.port, - (int)tcp->base.remote_name.host.slen, - tcp->base.remote_name.host.ptr, - tcp->base.remote_name.port)); - /* Mark that pending connect() operation has completed. */ tcp->has_pending_connect = PJ_FALSE; @@ -1257,6 +1248,19 @@ static void on_connect_complete(pj_ioqueue_key_t *key, tcp_perror(tcp->base.obj_name, "TCP connect() error", status); + /* Cancel all delayed transmits */ + while (!pj_list_empty(&tcp->delayed_list)) { + struct delayed_tdata *pending_tx; + pj_ioqueue_op_key_t *op_key; + + pending_tx = tcp->delayed_list.next; + pj_list_erase(pending_tx); + + op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key; + + on_write_complete(tcp->key, op_key, -status); + } + /* We can not destroy the transport since high level objects may * still keep reference to this transport. So we can only * instruct transport manager to gracefully start the shutdown @@ -1267,6 +1271,16 @@ static void on_connect_complete(pj_ioqueue_key_t *key, return; } + PJ_LOG(4,(tcp->base.obj_name, + "TCP transport %.*s:%d is connected to %.*s:%d", + (int)tcp->base.local_name.host.slen, + tcp->base.local_name.host.ptr, + tcp->base.local_name.port, + (int)tcp->base.remote_name.host.slen, + tcp->base.remote_name.host.ptr, + tcp->base.remote_name.port)); + + /* Update (again) local address, just in case local address currently * set is different now that the socket is connected (could happen * on some systems, like old Win32 probably?). -- cgit v1.2.3