summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2010-02-24 05:43:34 +0000
committerNanang Izzuddin <nanang@teluu.com>2010-02-24 05:43:34 +0000
commitbb2fc905eb58b9ebdf66e89330599be996821db7 (patch)
treef6bedef48655a824a1393efbb667a3b8af560b63 /pjsip
parentdf622f00fa10e2cbcde9df6169ad628fe3e72226 (diff)
Ticket #1032:
- Initial version of server domain name verification: - Updated SSL certificate info, especially identities info - Updated verification mechanism as in the specifications in ticket desc. - Added server domain name info in pjsip_tx_data. - Added alternative API for acquiring transport and creating transport of transport factory to include pjsip_tx_data param. - Server identity match criteria: - full host name match - wild card not accepted - if identity is URI, it must be SIP/SIPS URI - Initial version of transport state notifications: - Added new API to set transport state callback in PJSIP and PJSUA. - Defined states: connected/disconnected, accepted/rejected, verification errors. - Minors: - Updated SSL socket test: dump verification result, test of requiring client cert, and few minors. - Updated test cert to include subjectAltName extensions. - Added SSL certificate dump function. - Updated max number of socket async operations in Symbian sample apps (RSocketServ::Connect()) to 32 (was default 8). git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3106 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h29
-rw-r--r--pjsip/include/pjsip/sip_transport.h143
-rw-r--r--pjsip/include/pjsip/sip_transport_tls.h64
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h19
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c16
-rw-r--r--pjsip/src/pjsip/sip_transport.c94
-rw-r--r--pjsip/src/pjsip/sip_transport_tcp.c87
-rw-r--r--pjsip/src/pjsip/sip_transport_tls.c336
-rw-r--r--pjsip/src/pjsip/sip_util.c20
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c8
10 files changed, 675 insertions, 141 deletions
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index 1938e9d4..2abcf4a4 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -372,6 +372,35 @@ pjsip_endpt_acquire_transport( pjsip_endpoint *endpt,
pjsip_transport **p_tp);
+/**
+ * Find a SIP transport suitable for sending SIP message to the specified
+ * address by also considering the outgoing SIP message data. If transport
+ * selector ("sel") is set, then the function will check if the transport
+ * selected is suitable to send requests to the specified address.
+ *
+ * @see pjsip_tpmgr_acquire_transport
+ *
+ * @param endpt The SIP endpoint instance.
+ * @param type The type of transport to be acquired.
+ * @param remote The remote address to send message to.
+ * @param addr_len Length of the remote address.
+ * @param sel Optional pointer to transport selector instance which is
+ * used to find explicit transport, if required.
+ * @param tdata Optional pointer to SIP message data to be sent.
+ * @param p_tp Pointer to receive the transport instance, if one is found.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pjsip_endpt_acquire_transport2(pjsip_endpoint *endpt,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_t *remote,
+ int addr_len,
+ const pjsip_tpselector *sel,
+ pjsip_tx_data *tdata,
+ pjsip_transport **p_tp);
+
+
/*****************************************************************************
*
* Capabilities Management
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index 6592fc98..9f6534cd 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -540,6 +540,10 @@ struct pjsip_tx_data
*/
struct
{
+ /** Server name.
+ */
+ pj_str_t name;
+
/** Server addresses resolved.
*/
pjsip_server_addresses addr;
@@ -689,6 +693,11 @@ typedef struct pjsip_transport_key
long type;
/**
+ * Hash of host name.
+ */
+ pj_uint32_t hname;
+
+ /**
* Destination address.
*/
pj_sockaddr rem_addr;
@@ -918,7 +927,8 @@ struct pjsip_tpfactory
pjsip_host_port addr_name; /**< Published name. */
/**
- * Create new outbound connection.
+ * Create new outbound connection suitable for sending SIP message
+ * to specified remote address.
* Note that the factory is responsible for both creating the
* transport and registering it to the transport manager.
*/
@@ -930,6 +940,21 @@ struct pjsip_tpfactory
pjsip_transport **transport);
/**
+ * Create new outbound connection suitable for sending SIP message
+ * to specified remote address by also considering outgoing SIP
+ * message data.
+ * Note that the factory is responsible for both creating the
+ * transport and registering it to the transport manager.
+ */
+ pj_status_t (*create_transport2)(pjsip_tpfactory *factory,
+ pjsip_tpmgr *mgr,
+ pjsip_endpoint *endpt,
+ const pj_sockaddr *rem_addr,
+ int addr_len,
+ pjsip_tx_data *tdata,
+ pjsip_transport **transport);
+
+ /**
* Destroy the listener.
*/
pj_status_t (*destroy)(pjsip_tpfactory *factory);
@@ -1100,6 +1125,34 @@ PJ_DECL(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
pjsip_transport **tp);
/**
+ * Find suitable transport for sending SIP message to specified remote
+ * destination by also considering the outgoing SIP message. If no suitable
+ * transport is found, a new one will be created.
+ *
+ * This is an internal function since normally application doesn't have access
+ * to transport manager. Application should use pjsip_endpt_acquire_transport()
+ * instead.
+ *
+ * @param mgr The transport manager instance.
+ * @param type The type of transport to be acquired.
+ * @param remote The remote address to send message to.
+ * @param addr_len Length of the remote address.
+ * @param sel Optional pointer to transport selector instance which is
+ * used to find explicit transport, if required.
+ * @param tdata Optional pointer to data to be sent.
+ * @param tp Pointer to receive the transport instance, if one is found.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_t *remote,
+ int addr_len,
+ const pjsip_tpselector *sel,
+ pjsip_tx_data *tdata,
+ pjsip_transport **tp);
+
+/**
* Type of callback to receive notification when message or raw data
* has been sent.
*
@@ -1187,6 +1240,94 @@ PJ_DECL(pj_status_t) pjsip_tpmgr_send_raw(pjsip_tpmgr *mgr,
void *token,
pjsip_tp_send_callback cb);
+
+/**
+ * Enumeration of transport state types.
+ */
+typedef enum pjsip_transport_state_type {
+
+ /** Transport connected. */
+ PJSIP_TP_STATE_CONNECTED = (1 << 0),
+
+ /** Transport accepted. */
+ PJSIP_TP_STATE_ACCEPTED = (1 << 1),
+
+ /** Transport disconnected. */
+ PJSIP_TP_STATE_DISCONNECTED = (1 << 2),
+
+ /** Incoming connection rejected. */
+ PJSIP_TP_STATE_REJECTED = (1 << 3),
+
+ /** TLS verification error. */
+ PJSIP_TP_STATE_TLS_VERIF_ERROR = (1 << 8)
+
+} pjsip_transport_state_type;
+
+
+/**
+ * Structure of transport state info.
+ */
+typedef struct pjsip_transport_state_info {
+ /**
+ * The last error code related to the transport state.
+ */
+ pj_status_t status;
+
+ /**
+ * Optional extended info, the content is specific for each transport type.
+ */
+ void *ext_info;
+} pjsip_transport_state_info;
+
+
+/**
+ * Type of callback to receive transport state notifications, such as
+ * transport connected, disconnected or TLS verification error.
+ *
+ * @param tp The transport instance.
+ * @param state The transport state, this may contain single or
+ * combination of transport state types defined in
+ * #pjsip_transport_state_type.
+ * @param info The transport state info.
+ *
+ * @return When TLS verification fails and peer verification in
+ * #pjsip_tls_setting is not set, application may return
+ * PJ_TRUE to ignore the verification result and continue
+ * using the transport. On other cases, this return value
+ * is currently not used and will be ignored.
+ */
+typedef pj_bool_t (*pjsip_tp_state_callback)(
+ pjsip_transport *tp,
+ pj_uint32_t state,
+ const pjsip_transport_state_info *info);
+
+
+/**
+ * Setting callback of transport state notification. The caller will be
+ * notified whenever the state of transport is changed. The type of
+ * events are defined in #pjsip_transport_state_type.
+ *
+ * @param mgr Transport manager.
+ * @param cb Callback to be called to notify caller about transport
+ * status changing.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_tpmgr_set_status_cb(pjsip_tpmgr *mgr,
+ pjsip_tp_state_callback *cb);
+
+
+/**
+ * Getting the callback of transport state notification.
+ *
+ * @param mgr Transport manager.
+ *
+ * @return The transport state callback or NULL if it is not set.
+ */
+PJ_DECL(pjsip_tp_state_callback*) pjsip_tpmgr_get_status_cb(
+ const pjsip_tpmgr *mgr);
+
+
/**
* @}
*/
diff --git a/pjsip/include/pjsip/sip_transport_tls.h b/pjsip/include/pjsip/sip_transport_tls.h
index 8c41e167..f97414b3 100644
--- a/pjsip/include/pjsip/sip_transport_tls.h
+++ b/pjsip/include/pjsip/sip_transport_tls.h
@@ -26,6 +26,7 @@
*/
#include <pjsip/sip_transport.h>
+#include <pj/ssl_sock.h>
#include <pj/string.h>
#include <pj/sock_qos.h>
@@ -121,27 +122,44 @@ typedef struct pjsip_tls_setting
pj_str_t server_name;
/**
- * When PJSIP is acting as a client (outgoing TLS connections),
- * it will always receive a certificate from the peer.
- * If \a verify_server is disabled (set to zero), PJSIP will not
- * verifiy the certificate and allows TLS connections to servers
- * which do not present a valid certificate.
- * If \a tls_verify_server is non-zero, PJSIP verifies the server
- * certificate and will close the TLS connection if the server
- * certificate is not valid.
+ * Specifies the action when verification of server TLS certificate
+ * resulting errors:
+ * - If \a verify_server is disabled (set to PJ_FALSE), TLS transport
+ * will just notify the application via #pjsip_tp_state_callback with
+ * state (PJSIP_TP_STATE_CONNECTED | PJSIP_TP_STATE_TLS_VERIF_ERROR)
+ * whenever there is any TLS verification error, the return value of
+ * the callback will be used to decide whether transport should be
+ * shutdown.
+ * - If \a verify_server is enabled (set to PJ_TRUE), TLS transport
+ * will be shutdown and application will be notified with state
+ * (PJSIP_TP_STATE_DISCONNECTED | PJSIP_TP_STATE_TLS_VERIF_ERROR)
+ * whenever there is any TLS verification error.
*
- * This setting corresponds to OpenSSL SSL_VERIFY_PEER flag.
- * Default value is zero.
+ * When the verification resulting success, application will be notified
+ * via #pjsip_tp_state_callback with state PJSIP_TP_STATE_CONNECTED.
+ *
+ * Default value is PJ_FALSE.
*/
pj_bool_t verify_server;
/**
- * When acting as server (incoming TLS connections), setting
- * \a verify_client to non-zero will cause the transport to activate
- * peer verification upon receiving incoming TLS connection.
+ * Specifies the action when verification of server TLS certificate
+ * resulting errors:
+ * - If \a verify_client is disabled (set to PJ_FALSE), TLS transport
+ * will just notify the application via #pjsip_tp_state_callback with
+ * state (PJSIP_TP_STATE_ACCEPTED | PJSIP_TP_STATE_TLS_VERIF_ERROR)
+ * whenever there is any TLS verification error, the return value of
+ * the callback will be used to decide whether transport should be
+ * shutdown.
+ * - If \a verify_client is enabled (set to PJ_TRUE), TLS transport
+ * will be shutdown and application will be notified with state
+ * (PJSIP_TP_STATE_REJECTED | PJSIP_TP_STATE_TLS_VERIF_ERROR)
+ * whenever there is any TLS verification error.
+ *
+ * When the verification resulting success, application will be notified
+ * via #pjsip_tp_state_callback with state PJSIP_TP_STATE_ACCEPTED.
*
- * This setting corresponds to OpenSSL SSL_VERIFY_PEER flag.
- * Default value is zero.
+ * Default value is PJ_FALSE.
*/
pj_bool_t verify_client;
@@ -150,7 +168,7 @@ typedef struct pjsip_tls_setting
* connection if client doesn't have a valid certificate.
*
* This setting corresponds to SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag.
- * Default value is zero.
+ * Default value is PJ_FALSE.
*/
pj_bool_t require_client_cert;
@@ -191,6 +209,20 @@ typedef struct pjsip_tls_setting
/**
+ * This structure defines transport state extended info specifically for
+ * TLS transport.
+ */
+typedef struct pjsip_tls_state_info
+{
+ /**
+ * SSL socket info.
+ */
+ pj_ssl_sock_info *ssl_sock_info;
+
+} pjsip_tls_state_info;
+
+
+/**
* Initialize TLS setting with default values.
*
* @param tls_opt The TLS setting to be initialized.
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index ecafb25d..8d4d0a97 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -843,6 +843,25 @@ typedef struct pjsua_callback
*/
void (*on_mwi_info)(pjsua_acc_id acc_id, pjsua_mwi_info *mwi_info);
+ /**
+ * This callback is called when transport state is changed. See also
+ * #pjsip_tp_state_callback.
+ *
+ * @param tp The transport instance.
+ * @param state The transport state, this may contain single or
+ * combination of transport state types defined in
+ * #pjsip_transport_state_type.
+ * @param info The transport state info.
+ *
+ * @return When TLS verification fails and peer verification in
+ * #pjsip_tls_setting is not set, application may return
+ * PJ_TRUE to ignore the verification result and continue
+ * using the transport. On other cases, this return value
+ * is currently not used and will be ignored.
+ */
+ pj_bool_t (*on_transport_state)(pjsip_transport *tp, pj_uint32_t state,
+ const pjsip_transport_state_info *info);
+
} pjsua_callback;
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index a6861820..e0fe4f08 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -1075,6 +1075,22 @@ PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport(pjsip_endpoint *endpt,
/*
+ * Find/create transport.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_acquire_transport2(pjsip_endpoint *endpt,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_t *remote,
+ int addr_len,
+ const pjsip_tpselector *sel,
+ pjsip_tx_data *tdata,
+ pjsip_transport **transport)
+{
+ return pjsip_tpmgr_acquire_transport2(endpt->transport_mgr, type, remote,
+ addr_len, sel, tdata, transport);
+}
+
+
+/*
* Report error.
*/
PJ_DEF(void) pjsip_endpt_log_error( pjsip_endpoint *endpt,
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index f5d7ee57..92fbaf4d 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -89,6 +89,8 @@ struct pjsip_tpmgr
#endif
void (*on_rx_msg)(pjsip_endpoint*, pj_status_t, pjsip_rx_data*);
pj_status_t (*on_tx_msg)(pjsip_endpoint*, pjsip_tx_data*);
+ pjsip_tp_state_callback *tp_state_cb;
+ void *tp_state_user_data;
};
@@ -864,7 +866,7 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
/*
* Register to hash table (see Trac ticket #42).
*/
- key_len = sizeof(tp->key.type) + tp->addr_len;
+ key_len = sizeof(tp->key.type) + sizeof(tp->key.hname) + tp->addr_len;
pj_lock_acquire(mgr->lock);
/* If entry already occupied, unregister previous entry */
@@ -914,7 +916,7 @@ static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
/*
* Unregister from hash table (see Trac ticket #42).
*/
- key_len = sizeof(tp->key.type) + tp->addr_len;
+ key_len = sizeof(tp->key.type) + sizeof(tp->key.hname) + tp->addr_len;
hval = 0;
entry = pj_hash_get(mgr->table, &tp->key, key_len, &hval);
if (entry == (void*)tp)
@@ -1502,6 +1504,24 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
const pjsip_tpselector *sel,
pjsip_transport **tp)
{
+ return pjsip_tpmgr_acquire_transport2(mgr, type, remote, addr_len, sel,
+ NULL, tp);
+}
+
+/*
+ * pjsip_tpmgr_acquire_transport2()
+ *
+ * Get transport suitable to communicate to remote. Create a new one
+ * if necessary.
+ */
+PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_t *remote,
+ int addr_len,
+ const pjsip_tpselector *sel,
+ pjsip_tx_data *tdata,
+ pjsip_transport **tp)
+{
pjsip_tpfactory *factory;
pj_status_t status;
@@ -1571,19 +1591,43 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
int key_len;
pjsip_transport *transport;
+ /*
+ * Find factory that can create such transport.
+ */
+ factory = mgr->factory_list.next;
+ while (factory != &mgr->factory_list) {
+ if (factory->type == type)
+ break;
+ factory = factory->next;
+ }
+ if (factory == &mgr->factory_list)
+ factory = NULL;
+
pj_bzero(&key, sizeof(key));
- key_len = sizeof(key.type) + addr_len;
+ key_len = sizeof(key.type) + sizeof(key.hname) + addr_len;
/* First try to get exact destination. */
key.type = type;
pj_memcpy(&key.rem_addr, remote, addr_len);
+ if (factory && factory->create_transport2 &&
+ tdata && tdata->dest_info.name.slen)
+ {
+ /* Only include hostname hash in the key when the factory support
+ * create_transport2() and tdata is supplied.
+ */
+ key.hname = pj_hash_calc_tolower(0,
+ (char*)tdata->dest_info.name.ptr,
+ &tdata->dest_info.name);
+ }
transport = (pjsip_transport*)
pj_hash_get(mgr->table, &key, key_len, NULL);
+
if (transport == NULL) {
unsigned flag = pjsip_transport_get_flag_from_type(type);
const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
+
/* Ignore address for loop transports. */
if (type == PJSIP_TRANSPORT_LOOP ||
type == PJSIP_TRANSPORT_LOOP_DGRAM)
@@ -1591,7 +1635,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
pj_sockaddr *addr = &key.rem_addr;
pj_bzero(addr, addr_len);
- key_len = sizeof(key.type) + addr_len;
+ key_len = sizeof(key.type) + sizeof(key.hname) + addr_len;
transport = (pjsip_transport*)
pj_hash_get(mgr->table, &key, key_len, NULL);
}
@@ -1604,7 +1648,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
pj_bzero(addr, addr_len);
addr->addr.sa_family = remote_addr->addr.sa_family;
- key_len = sizeof(key.type) + addr_len;
+ key_len = sizeof(key.type) + sizeof(key.hname) + addr_len;
transport = (pjsip_transport*)
pj_hash_get(mgr->table, &key, key_len, NULL);
}
@@ -1624,31 +1668,28 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
/*
* Transport not found!
- * Find factory that can create such transport.
*/
- factory = mgr->factory_list.next;
- while (factory != &mgr->factory_list) {
- if (factory->type == type)
- break;
- factory = factory->next;
- }
-
- if (factory == &mgr->factory_list) {
+ if (NULL == factory) {
/* No factory can create the transport! */
pj_lock_release(mgr->lock);
TRACE_((THIS_FILE, "No suitable factory was found either"));
return PJSIP_EUNSUPTRANSPORT;
}
-
}
TRACE_((THIS_FILE, "Creating new transport from factory"));
/* Request factory to create transport. */
- status = factory->create_transport(factory, mgr, mgr->endpt,
- (const pj_sockaddr*) remote, addr_len,
- tp);
+ if (factory->create_transport2) {
+ status = factory->create_transport2(factory, mgr, mgr->endpt,
+ (const pj_sockaddr*) remote,
+ addr_len, tdata, tp);
+ } else {
+ status = factory->create_transport(factory, mgr, mgr->endpt,
+ (const pj_sockaddr*) remote,
+ addr_len, tp);
+ }
if (status == PJ_SUCCESS) {
PJ_ASSERT_ON_FAIL(tp!=NULL,
{pj_lock_release(mgr->lock); return PJ_EBUG;});
@@ -1711,3 +1752,20 @@ PJ_DEF(void) pjsip_tpmgr_dump_transports(pjsip_tpmgr *mgr)
#endif
}
+PJ_DEF(pj_status_t) pjsip_tpmgr_set_status_cb(pjsip_tpmgr *mgr,
+ pjsip_tp_state_callback *cb)
+{
+ PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
+
+ mgr->tp_state_cb = cb;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pjsip_tp_state_callback*) pjsip_tpmgr_get_status_cb(
+ const pjsip_tpmgr *mgr)
+{
+ PJ_ASSERT_RETURN(mgr, NULL);
+
+ return mgr->tp_state_cb;
+}
diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c
index 56a4fe8f..a7c7eeba 100644
--- a/pjsip/src/pjsip/sip_transport_tcp.c
+++ b/pjsip/src/pjsip/sip_transport_tcp.c
@@ -166,6 +166,36 @@ static void sockaddr_to_host_port( pj_pool_t *pool,
host_port->port = pj_sockaddr_get_port(addr);
}
+
+static void tcp_init_shutdown(struct tcp_transport *tcp, pj_status_t status)
+{
+ pjsip_tp_state_callback *state_cb;
+
+ if (tcp->close_reason == PJ_SUCCESS)
+ tcp->close_reason = status;
+
+ if (tcp->base.is_shutdown)
+ return;
+
+ /* Notify application of transport disconnected state */
+ state_cb = pjsip_tpmgr_get_status_cb(tcp->base.tpmgr);
+ if (state_cb) {
+ pjsip_transport_state_info state_info;
+
+ pj_bzero(&state_info, sizeof(state_info));
+ state_info.status = tcp->close_reason;
+ (*state_cb)(&tcp->base, PJSIP_TP_STATE_DISCONNECTED, &state_info);
+ }
+
+ /* 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
+ * procedure for this transport.
+ */
+ pjsip_transport_shutdown(&tcp->base);
+}
+
+
/*
* Initialize pjsip_tcp_transport_cfg structure with default values.
*/
@@ -921,6 +951,7 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
struct tcp_listener *listener;
struct tcp_transport *tcp;
char addr[PJ_INET6_ADDRSTRLEN+10];
+ pjsip_tp_state_callback *state_cb;
pj_status_t status;
PJ_UNUSED_ARG(src_addr_len);
@@ -966,6 +997,15 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
tcp->ka_timer.id = PJ_TRUE;
pj_gettimeofday(&tcp->last_activity);
}
+
+ /* Notify application of transport state accepted */
+ state_cb = pjsip_tpmgr_get_status_cb(tcp->base.tpmgr);
+ if (state_cb) {
+ pjsip_transport_state_info state_info;
+
+ pj_bzero(&state_info, sizeof(state_info));
+ (*state_cb)(&tcp->base, PJSIP_TP_STATE_ACCEPTED, &state_info);
+ }
}
}
@@ -1013,8 +1053,8 @@ static pj_bool_t on_data_sent(pj_activesock_t *asock,
status = (bytes_sent == 0) ? PJ_RETURN_OS_ERROR(OSERR_ENOTCONN) :
-bytes_sent;
- if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status;
- pjsip_transport_shutdown(&tcp->base);
+
+ tcp_init_shutdown(tcp, status);
return PJ_FALSE;
}
@@ -1109,8 +1149,8 @@ static pj_status_t tcp_send_msg(pjsip_transport *transport,
if (status == PJ_SUCCESS)
status = PJ_RETURN_OS_ERROR(OSERR_ENOTCONN);
- if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status;
- pjsip_transport_shutdown(&tcp->base);
+
+ tcp_init_shutdown(tcp, status);
}
}
}
@@ -1199,14 +1239,7 @@ static pj_bool_t on_data_read(pj_activesock_t *asock,
/* Transport is closed */
PJ_LOG(4,(tcp->base.obj_name, "TCP connection closed"));
- /* 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
- * procedure for this transport.
- */
- if (tcp->close_reason==PJ_SUCCESS)
- tcp->close_reason = status;
- pjsip_transport_shutdown(&tcp->base);
+ tcp_init_shutdown(tcp, status);
return PJ_FALSE;
@@ -1229,6 +1262,8 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
pj_sockaddr_in addr;
int addrlen;
+ pjsip_tp_state_callback *state_cb;
+
tcp = (struct tcp_transport*) pj_activesock_get_user_data(asock);
/* Mark that pending connect() operation has completed. */
@@ -1252,14 +1287,7 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
on_data_sent(tcp->asock, 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
- * procedure for this transport.
- */
- if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status;
- pjsip_transport_shutdown(&tcp->base);
- return PJ_FALSE;
+ tcp_init_shutdown(tcp, status);
}
PJ_LOG(4,(tcp->base.obj_name,
@@ -1293,16 +1321,19 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
/* Start pending read */
status = tcp_start_read(tcp);
if (status != PJ_SUCCESS) {
- /* 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
- * procedure for this transport.
- */
- if (tcp->close_reason==PJ_SUCCESS) tcp->close_reason = status;
- pjsip_transport_shutdown(&tcp->base);
+ tcp_init_shutdown(tcp, status);
return PJ_FALSE;
}
+ /* Notify application of transport state connected */
+ state_cb = pjsip_tpmgr_get_status_cb(tcp->base.tpmgr);
+ if (state_cb) {
+ pjsip_transport_state_info state_info;
+
+ pj_bzero(&state_info, sizeof(state_info));
+ (*state_cb)(&tcp->base, PJSIP_TP_STATE_CONNECTED, &state_info);
+ }
+
/* Flush all pending send operations */
tcp_flush_pending_tx(tcp);
@@ -1358,7 +1389,7 @@ static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e)
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
tcp_perror(tcp->base.obj_name,
"Error sending keep-alive packet", status);
- pjsip_transport_shutdown(&tcp->base);
+ tcp_init_shutdown(tcp, status);
return;
}
diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c
index ab96ecd9..a135c43f 100644
--- a/pjsip/src/pjsip/sip_transport_tls.c
+++ b/pjsip/src/pjsip/sip_transport_tls.c
@@ -24,6 +24,7 @@
#include <pj/addr_resolv.h>
#include <pj/ssl_sock.h>
#include <pj/assert.h>
+#include <pj/hash.h>
#include <pj/lock.h>
#include <pj/log.h>
#include <pj/os.h>
@@ -80,12 +81,14 @@ struct tls_transport
{
pjsip_transport base;
pj_bool_t is_server;
+ pj_str_t remote_name;
pj_bool_t is_registered;
pj_bool_t is_closing;
pj_status_t close_reason;
pj_ssl_sock_t *ssock;
pj_bool_t has_pending_connect;
+ pj_bool_t verify_server;
/* Keep-alive timer. */
pj_timer_entry ka_timer;
@@ -135,6 +138,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
pjsip_endpoint *endpt,
const pj_sockaddr *rem_addr,
int addr_len,
+ pjsip_tx_data *tdata,
pjsip_transport **transport);
/* Common function to create and initialize transport */
@@ -144,6 +148,7 @@ static pj_status_t tls_create(struct tls_listener *listener,
pj_bool_t is_server,
const pj_sockaddr_in *local,
const pj_sockaddr_in *remote,
+ const pj_str_t *remote_name,
struct tls_transport **p_tls);
@@ -169,6 +174,34 @@ static void sockaddr_to_host_port( pj_pool_t *pool,
}
+static void tls_init_shutdown(struct tls_transport *tls, pj_status_t status)
+{
+ pjsip_tp_state_callback *state_cb;
+
+ if (tls->close_reason == PJ_SUCCESS)
+ tls->close_reason = status;
+
+ if (tls->base.is_shutdown)
+ return;
+
+ /* Notify application of transport disconnected state */
+ state_cb = pjsip_tpmgr_get_status_cb(tls->base.tpmgr);
+ if (state_cb) {
+ pjsip_transport_state_info state_info;
+
+ pj_bzero(&state_info, sizeof(state_info));
+ state_info.status = tls->close_reason;
+ (*state_cb)(&tls->base, PJSIP_TP_STATE_DISCONNECTED, &state_info);
+ }
+
+ /* 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
+ * procedure for this transport.
+ */
+ pjsip_transport_shutdown(&tls->base);
+}
+
/****************************************************************************
* The TLS listener/transport factory.
@@ -243,10 +276,10 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
ssock_param.async_cnt = async_cnt;
ssock_param.ioqueue = pjsip_endpt_get_ioqueue(endpt);
ssock_param.require_client_cert = listener->tls_setting.require_client_cert;
- ssock_param.server_name = listener->tls_setting.server_name;
ssock_param.timeout = listener->tls_setting.timeout;
ssock_param.user_data = listener;
- ssock_param.verify_peer = listener->tls_setting.verify_client;
+ ssock_param.verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
+ * due to verification error */
if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN)
ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
@@ -371,7 +404,7 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
/* Register to transport manager */
listener->endpt = endpt;
listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
- listener->factory.create_transport = lis_create_transport;
+ listener->factory.create_transport2 = lis_create_transport;
listener->factory.destroy = lis_destroy;
listener->is_registered = PJ_TRUE;
status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
@@ -480,6 +513,7 @@ static pj_status_t tls_create( struct tls_listener *listener,
pj_bool_t is_server,
const pj_sockaddr_in *local,
const pj_sockaddr_in *remote,
+ const pj_str_t *remote_name,
struct tls_transport **p_tls)
{
struct tls_transport *tls;
@@ -501,6 +535,7 @@ static pj_status_t tls_create( struct tls_listener *listener,
*/
tls = PJ_POOL_ZALLOC_T(pool, struct tls_transport);
tls->is_server = is_server;
+ tls->verify_server = listener->tls_setting.verify_server;
pj_list_init(&tls->delayed_list);
tls->base.pool = pool;
@@ -517,8 +552,13 @@ static pj_status_t tls_create( struct tls_listener *listener,
goto on_error;
}
+ if (remote_name)
+ pj_strdup(pool, &tls->remote_name, remote_name);
+
tls->base.key.type = PJSIP_TRANSPORT_TLS;
pj_memcpy(&tls->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
+ tls->base.key.hname = pj_hash_calc_tolower(0, (char*)tls->remote_name.ptr,
+ &tls->remote_name);
tls->base.type_name = "tls";
tls->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);
@@ -769,6 +809,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
pjsip_endpoint *endpt,
const pj_sockaddr *rem_addr,
int addr_len,
+ pjsip_tx_data *tdata,
pjsip_transport **p_transport)
{
struct tls_listener *listener;
@@ -777,6 +818,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
pj_ssl_sock_t *ssock;
pj_ssl_sock_param ssock_param;
pj_sockaddr_in local_addr;
+ pj_str_t remote_name;
pj_status_t status;
/* Sanity checks */
@@ -794,6 +836,12 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
POOL_TP_INIT, POOL_TP_INC);
PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
+ /* Get remote host name from tdata */
+ if (tdata)
+ remote_name = tdata->dest_info.name;
+ else
+ pj_bzero(&remote_name, sizeof(remote_name));
+
/* Build SSL socket param */
pj_ssl_sock_param_default(&ssock_param);
ssock_param.cb.on_connect_complete = &on_connect_complete;
@@ -801,12 +849,12 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
ssock_param.cb.on_data_sent = &on_data_sent;
ssock_param.async_cnt = 1;
ssock_param.ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
- PJ_TODO(set_proper_servername_based_on_target);
PJ_TODO(synchronize_tls_cipher_type_with_ssl_sock_cipher_type);
- ssock_param.server_name = listener->tls_setting.server_name;
+ ssock_param.server_name = remote_name;
ssock_param.timeout = listener->tls_setting.timeout;
ssock_param.user_data = NULL; /* pending, must be set later */
- ssock_param.verify_peer = listener->tls_setting.verify_server;
+ ssock_param.verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
+ * due to verification error */
if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN)
ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
@@ -850,7 +898,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Create the transport descriptor */
status = tls_create(listener, pool, ssock, PJ_FALSE, &local_addr,
- (pj_sockaddr_in*)rem_addr, &tls);
+ (pj_sockaddr_in*)rem_addr, &remote_name, &tls);
if (status != PJ_SUCCESS)
return status;
@@ -928,9 +976,13 @@ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock,
{
struct tls_listener *listener;
struct tls_transport *tls;
+ pj_ssl_sock_info ssl_info;
char addr[PJ_INET6_ADDRSTRLEN+10];
pj_status_t status;
+ pjsip_tp_state_callback *state_cb;
+ pj_bool_t tls_verif_ignored;
+
PJ_UNUSED_ARG(src_addr_len);
listener = (struct tls_listener*) pj_ssl_sock_get_user_data(ssock);
@@ -946,32 +998,84 @@ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock,
pj_sockaddr_print(src_addr, addr, sizeof(addr), 3),
new_ssock));
+ /* Retrieve SSL socket info, close the socket if this is failed
+ * as the SSL socket info availability is rather critical here.
+ */
+ status = pj_ssl_sock_get_info(new_ssock, &ssl_info);
+ if (status != PJ_SUCCESS) {
+ pj_ssl_sock_close(new_ssock);
+ return PJ_TRUE;
+ }
+
/*
* Incoming connection!
* Create TLS transport for the new socket.
*/
status = tls_create( listener, NULL, new_ssock, PJ_TRUE,
(const pj_sockaddr_in*)&listener->factory.local_addr,
- (const pj_sockaddr_in*)src_addr, &tls);
+ (const pj_sockaddr_in*)src_addr, NULL, &tls);
- if (status == PJ_SUCCESS) {
- /* Set the "pending" SSL socket user data */
- pj_ssl_sock_set_user_data(new_ssock, tls);
+ if (status != PJ_SUCCESS)
+ return PJ_TRUE;
- status = tls_start_read(tls);
- if (status != PJ_SUCCESS) {
- PJ_LOG(3,(tls->base.obj_name, "New transport cancelled"));
- tls_destroy(&tls->base, status);
+ /* Set the "pending" SSL socket user data */
+ pj_ssl_sock_set_user_data(new_ssock, tls);
+
+ tls_verif_ignored = !listener->tls_setting.verify_client;
+
+ /* Notify transport state to application */
+ state_cb = pjsip_tpmgr_get_status_cb(tls->base.tpmgr);
+ if (state_cb) {
+ pjsip_transport_state_info state_info;
+ pjsip_tls_state_info tls_info;
+ pj_uint32_t tp_state = 0;
+
+ /* Init transport state notification callback */
+ pj_bzero(&tls_info, sizeof(tls_info));
+ pj_bzero(&state_info, sizeof(state_info));
+
+ /* Set transport state based on verification status */
+ if (ssl_info.verify_status) {
+ state_info.status = PJSIP_TLS_EACCEPT;
+ tp_state |= PJSIP_TP_STATE_TLS_VERIF_ERROR;
+ if (listener->tls_setting.verify_client)
+ tp_state |= PJSIP_TP_STATE_REJECTED;
+ else
+ tp_state |= PJSIP_TP_STATE_ACCEPTED;
} else {
- /* Start keep-alive timer */
- if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
- pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0};
- pjsip_endpt_schedule_timer(listener->endpt,
- &tls->ka_timer,
- &delay);
- tls->ka_timer.id = PJ_TRUE;
- pj_gettimeofday(&tls->last_activity);
- }
+ tp_state |= PJSIP_TP_STATE_ACCEPTED;
+ }
+
+ tls_info.ssl_sock_info = &ssl_info;
+ state_info.ext_info = &tls_info;
+
+ tls_verif_ignored = (*state_cb)(&tls->base, tp_state, &state_info);
+ }
+
+ /* Transport should be destroyed when there is TLS verification error
+ * and application doesn't want to ignore it.
+ */
+ if (ssl_info.verify_status &&
+ (listener->tls_setting.verify_client || !tls_verif_ignored))
+ {
+ tls_destroy(&tls->base, PJSIP_TLS_EACCEPT);
+ return PJ_TRUE;
+ }
+
+ status = tls_start_read(tls);
+ if (status != PJ_SUCCESS) {
+ PJ_LOG(3,(tls->base.obj_name, "New transport cancelled"));
+ tls_init_shutdown(tls, status);
+ tls_destroy(&tls->base, status);
+ } else {
+ /* Start keep-alive timer */
+ if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
+ pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0};
+ pjsip_endpt_schedule_timer(listener->endpt,
+ &tls->ka_timer,
+ &delay);
+ tls->ka_timer.id = PJ_TRUE;
+ pj_gettimeofday(&tls->last_activity);
}
}
@@ -1019,8 +1123,8 @@ static pj_bool_t on_data_sent(pj_ssl_sock_t *ssock,
status = (bytes_sent == 0) ? PJ_RETURN_OS_ERROR(OSERR_ENOTCONN) :
-bytes_sent;
- if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
- pjsip_transport_shutdown(&tls->base);
+
+ tls_init_shutdown(tls, status);
return PJ_FALSE;
}
@@ -1115,8 +1219,8 @@ static pj_status_t tls_send_msg(pjsip_transport *transport,
if (status == PJ_SUCCESS)
status = PJ_RETURN_OS_ERROR(OSERR_ENOTCONN);
- if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
- pjsip_transport_shutdown(&tls->base);
+
+ tls_init_shutdown(tls, status);
}
}
}
@@ -1204,15 +1308,8 @@ static pj_bool_t on_data_read(pj_ssl_sock_t *ssock,
/* Transport is closed */
PJ_LOG(4,(tls->base.obj_name, "TLS connection closed"));
-
- /* 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
- * procedure for this transport.
- */
- if (tls->close_reason==PJ_SUCCESS)
- tls->close_reason = status;
- pjsip_transport_shutdown(&tls->base);
+
+ tls_init_shutdown(tls, status);
return PJ_FALSE;
@@ -1232,8 +1329,12 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
pj_status_t status)
{
struct tls_transport *tls;
- pj_ssl_sock_info info;
-
+ pj_ssl_sock_info ssl_info;
+ pj_sockaddr_in addr, *tp_addr;
+
+ pjsip_tp_state_callback *state_cb;
+ pj_bool_t tls_verif_ignored;
+
tls = (struct tls_transport*) pj_ssl_sock_get_user_data(ssock);
/* Check connect() status */
@@ -1254,36 +1355,130 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
on_data_sent(tls->ssock, 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
- * procedure for this transport.
- */
- if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
- pjsip_transport_shutdown(&tls->base);
- return PJ_FALSE;
+ goto on_error;
}
+ /* Retrieve SSL socket info, shutdown the transport if this is failed
+ * as the SSL socket info availability is rather critical here.
+ */
+ status = pj_ssl_sock_get_info(tls->ssock, &ssl_info);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
/* 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?).
*/
+ tp_addr = (pj_sockaddr_in*)&tls->base.local_addr;
+ pj_sockaddr_cp((pj_sockaddr_t*)&addr,
+ (pj_sockaddr_t*)&ssl_info.local_addr);
+ if (tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr) {
+ tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
+ tp_addr->sin_port = addr.sin_port;
+ sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
+ tp_addr);
+ }
- /* Retrieve the bound address */
- status = pj_ssl_sock_get_info(tls->ssock, &info);
- if (status == PJ_SUCCESS) {
- pj_sockaddr_in addr;
- pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tls->base.local_addr;
-
- pj_sockaddr_cp((pj_sockaddr_t*)&addr, (pj_sockaddr_t*)&info.local_addr);
- if (tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr) {
- tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
- tp_addr->sin_port = addr.sin_port;
- sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
- tp_addr);
+ /* Server identity verification based on server certificate. */
+ if (ssl_info.remote_cert_info->version) {
+ pj_str_t *remote_name;
+ pj_ssl_cert_info *serv_cert = ssl_info.remote_cert_info;
+ pj_bool_t matched = PJ_FALSE;
+ unsigned i;
+
+ /* Remote name may be hostname or IP address */
+ if (tls->remote_name.slen)
+ remote_name = &tls->remote_name;
+ else
+ remote_name = &tls->base.remote_name.host;
+
+ /* Start matching remote name with SubjectAltName fields of
+ * server certificate.
+ */
+ for (i = 0; i < serv_cert->subj_alt_name.cnt && !matched; ++i) {
+ pj_str_t *cert_name = &serv_cert->subj_alt_name.entry[i].name;
+
+ switch (serv_cert->subj_alt_name.entry[i].type) {
+ case PJ_SSL_CERT_NAME_DNS:
+ case PJ_SSL_CERT_NAME_IP:
+ matched = !pj_stricmp(remote_name, cert_name);
+ break;
+ case PJ_SSL_CERT_NAME_URI:
+ if (pj_strnicmp2(cert_name, "sip:", 4) == 0 ||
+ pj_strnicmp2(cert_name, "sips:", 5) == 0)
+ {
+ pj_str_t host_part;
+ char *p;
+
+ p = pj_strchr(cert_name, ':') + 1;
+ pj_strset(&host_part, p, cert_name->slen -
+ (p - cert_name->ptr));
+ matched = !pj_stricmp(remote_name, &host_part);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* When still not matched or no SubjectAltName fields in server
+ * certificate, try with Common Name of Subject field.
+ */
+ if (!matched) {
+ matched = !pj_stricmp(remote_name, &serv_cert->subject.cn);
}
+
+ if (!matched)
+ ssl_info.verify_status |= PJ_SSL_CERT_EIDENTITY_NOT_MATCH;
}
+ tls_verif_ignored = !tls->verify_server;
+
+ /* Notify transport state to application */
+ state_cb = pjsip_tpmgr_get_status_cb(tls->base.tpmgr);
+ if (state_cb) {
+ pjsip_transport_state_info state_info;
+ pjsip_tls_state_info tls_info;
+ pj_uint32_t tp_state = 0;
+
+ /* Init transport state notification callback */
+ pj_bzero(&state_info, sizeof(state_info));
+ pj_bzero(&tls_info, sizeof(tls_info));
+
+ /* Set transport state info */
+ state_info.ext_info = &tls_info;
+ tls_info.ssl_sock_info = &ssl_info;
+
+ /* Set transport state based on verification status */
+ if (ssl_info.verify_status) {
+ state_info.status = PJSIP_TLS_ECONNECT;
+ tp_state |= PJSIP_TP_STATE_TLS_VERIF_ERROR;
+ if (tls->verify_server)
+ tp_state |= PJSIP_TP_STATE_DISCONNECTED;
+ else
+ tp_state |= PJSIP_TP_STATE_CONNECTED;
+ } else {
+ tp_state |= PJSIP_TP_STATE_CONNECTED;
+ }
+
+ tls_verif_ignored = (*state_cb)(&tls->base, tp_state, &state_info);
+ }
+
+ /* Transport should be shutdown when there is TLS verification error
+ * and application doesn't want to ignore it.
+ */
+ if (ssl_info.verify_status &&
+ (tls->verify_server || !tls_verif_ignored))
+ {
+ if (tls->close_reason == PJ_SUCCESS)
+ tls->close_reason = PJSIP_TLS_ECONNECT;
+ pjsip_transport_shutdown(&tls->base);
+ return PJ_FALSE;
+ }
+
+ /* Mark that pending connect() operation has completed. */
+ tls->has_pending_connect = PJ_FALSE;
+
PJ_LOG(4,(tls->base.obj_name,
"TLS transport %.*s:%d is connected to %.*s:%d",
(int)tls->base.local_name.host.slen,
@@ -1293,21 +1488,10 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
tls->base.remote_name.host.ptr,
tls->base.remote_name.port));
- /* Mark that pending connect() operation has completed. */
- tls->has_pending_connect = PJ_FALSE;
-
/* Start pending read */
status = tls_start_read(tls);
- if (status != PJ_SUCCESS) {
- /* 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
- * procedure for this transport.
- */
- if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
- pjsip_transport_shutdown(&tls->base);
- return PJ_FALSE;
- }
+ if (status != PJ_SUCCESS)
+ goto on_error;
/* Flush all pending send operations */
tls_flush_pending_tx(tls);
@@ -1322,6 +1506,11 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
}
return PJ_TRUE;
+
+on_error:
+ tls_init_shutdown(tls, status);
+
+ return PJ_FALSE;
}
@@ -1365,7 +1554,8 @@ static void tls_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e)
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
tls_perror(tls->base.obj_name,
"Error sending keep-alive packet", status);
- pjsip_transport_shutdown(&tls->base);
+
+ tls_init_shutdown(tls, status);
return;
}
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index 5bd0f6bf..3b1bc102 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -779,6 +779,10 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
pjsip_hdr_clone(cancel_tdata->pool, req_tdata->saved_strict_route);
}
+ /* Copy the destination host name from the original request */
+ pj_strdup(cancel_tdata->pool, &cancel_tdata->dest_info.name,
+ &req_tdata->dest_info.name);
+
/* Finally copy the destination info from the original request */
pj_memcpy(&cancel_tdata->dest_info, &req_tdata->dest_info,
sizeof(req_tdata->dest_info));
@@ -1134,11 +1138,12 @@ static void stateless_send_transport_cb( void *token,
cur_addr_len = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len;
/* Acquire transport. */
- status = pjsip_endpt_acquire_transport( stateless_data->endpt,
+ status = pjsip_endpt_acquire_transport2(stateless_data->endpt,
cur_addr_type,
cur_addr,
cur_addr_len,
&tdata->tp_sel,
+ tdata,
&stateless_data->cur_transport);
if (status != PJ_SUCCESS) {
sent = -status;
@@ -1319,6 +1324,9 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request_stateless(pjsip_endpoint *endpt,
* proceed to sending the request directly.
*/
if (tdata->dest_info.addr.count == 0) {
+ /* Copy the destination host name to TX data */
+ pj_strdup(tdata->pool, &tdata->dest_info.name, &dest_info.addr.host);
+
pjsip_endpt_resolve( endpt, tdata->pool, &dest_info, stateless_data,
&stateless_send_resolver_callback);
} else {
@@ -1466,6 +1474,9 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_raw_to_uri(pjsip_endpoint *endpt,
pjsip_tpselector_add_ref(sraw_data->sel);
}
+ /* Copy the destination host name to TX data */
+ pj_strdup(tdata->pool, &tdata->dest_info.name, &dest_info.addr.host);
+
/* Resolve destination host.
* The processing then resumed when the resolving callback is called.
*/
@@ -1622,11 +1633,12 @@ static void send_response_resolver_cb( pj_status_t status, void *token,
/* Only handle the first address resolved. */
/* Acquire transport. */
- status = pjsip_endpt_acquire_transport( send_state->endpt,
+ status = pjsip_endpt_acquire_transport2(send_state->endpt,
addr->entry[0].type,
&addr->entry[0].addr,
addr->entry[0].addr_len,
&send_state->tdata->tp_sel,
+ send_state->tdata,
&send_state->cur_transport);
if (status != PJ_SUCCESS) {
if (send_state->app_cb) {
@@ -1702,6 +1714,10 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_response( pjsip_endpoint *endpt,
return status;
}
} else {
+ /* Copy the destination host name to TX data */
+ pj_strdup(tdata->pool, &tdata->dest_info.name,
+ &res_addr->dst_host.addr.host);
+
pjsip_endpt_resolve(endpt, tdata->pool, &res_addr->dst_host,
send_state, &send_response_resolver_cb);
return PJ_SUCCESS;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 52d436e3..8870b87e 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -1810,9 +1810,6 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
/*
* Create TLS transport.
*/
- /*
- * Create TCP transport.
- */
pjsua_transport_config config;
pjsip_host_port a_name;
pjsip_tpfactory *tls;
@@ -1867,6 +1864,11 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
goto on_return;
}
+ /* Set transport state callback */
+ if (pjsua_var.ua_cfg.cb.on_transport_state) {
+ pjsip_tpmgr_set_status_cb(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
+ &pjsua_var.ua_cfg.cb.on_transport_state);
+ }
/* Return the ID */
if (p_id) *p_id = id;