Index: pjproject/trunk/pjsip-apps/src/swig/symbols.i
===================================================================
--- pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5517)
+++ pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5518)
@@ -34,4 +34,8 @@
 
 typedef enum pj_ssl_sock_proto {PJ_SSL_SOCK_PROTO_DEFAULT = 0, PJ_SSL_SOCK_PROTO_SSL2 = 1 << 0, PJ_SSL_SOCK_PROTO_SSL3 = 1 << 1, PJ_SSL_SOCK_PROTO_TLS1 = 1 << 2, PJ_SSL_SOCK_PROTO_TLS1_1 = 1 << 3, PJ_SSL_SOCK_PROTO_TLS1_2 = 1 << 4, PJ_SSL_SOCK_PROTO_SSL23 = (1 << 16) - 1, PJ_SSL_SOCK_PROTO_DTLS1 = 1 << 16} pj_ssl_sock_proto;
+
+typedef enum pj_ssl_cert_name_type {PJ_SSL_CERT_NAME_UNKNOWN = 0, PJ_SSL_CERT_NAME_RFC822, PJ_SSL_CERT_NAME_DNS, PJ_SSL_CERT_NAME_URI, PJ_SSL_CERT_NAME_IP} pj_ssl_cert_name_type;
+
+typedef enum pj_ssl_cert_verify_flag_t {PJ_SSL_CERT_ESUCCESS = 0, PJ_SSL_CERT_EISSUER_NOT_FOUND = (1 << 0), PJ_SSL_CERT_EUNTRUSTED = (1 << 1), PJ_SSL_CERT_EVALIDITY_PERIOD = (1 << 2), PJ_SSL_CERT_EINVALID_FORMAT = (1 << 3), PJ_SSL_CERT_EINVALID_PURPOSE = (1 << 4), PJ_SSL_CERT_EISSUER_MISMATCH = (1 << 5), PJ_SSL_CERT_ECRL_FAILURE = (1 << 6), PJ_SSL_CERT_EREVOKED = (1 << 7), PJ_SSL_CERT_ECHAIN_TOO_LONG = (1 << 8), PJ_SSL_CERT_EIDENTITY_NOT_MATCH = (1 << 30), PJ_SSL_CERT_EUNKNOWN = (1 << 31)} pj_ssl_cert_verify_flag_t;
 
 typedef enum pj_stun_nat_type {PJ_STUN_NAT_TYPE_UNKNOWN, PJ_STUN_NAT_TYPE_ERR_UNKNOWN, PJ_STUN_NAT_TYPE_OPEN, PJ_STUN_NAT_TYPE_BLOCKED, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP, PJ_STUN_NAT_TYPE_FULL_CONE, PJ_STUN_NAT_TYPE_SYMMETRIC, PJ_STUN_NAT_TYPE_RESTRICTED, PJ_STUN_NAT_TYPE_PORT_RESTRICTED} pj_stun_nat_type;
Index: pjproject/trunk/pjsip-apps/src/swig/symbols.lst
===================================================================
--- pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5517)
+++ pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5518)
@@ -3,5 +3,5 @@
 pj/log.h			pj_log_decoration
 pj/sock_qos.h			pj_qos_type pj_qos_flag pj_qos_wmm_prio pj_qos_params
-pj/ssl_sock.h			pj_ssl_cipher pj_ssl_sock_proto
+pj/ssl_sock.h			pj_ssl_cipher pj_ssl_sock_proto pj_ssl_cert_name_type pj_ssl_cert_verify_flag_t
 
 pjnath/nat_detect.h          	pj_stun_nat_type
Index: pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp
===================================================================
--- pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 5517)
+++ pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 5518)
@@ -125,4 +125,138 @@
 
 /**
+ * SSL certificate type and name structure.
+ */
+struct SslCertName
+{
+    pj_ssl_cert_name_type  type;    	    /**< Name type		*/
+    string		   name;    	    /**< The name		*/
+};
+
+/**
+ * SSL certificate information.
+ */
+struct SslCertInfo
+{
+    unsigned		version;	    /**< Certificate version	*/
+    unsigned char	serialNo[20];	    /**< Serial number, array
+				         	 of octets, first index
+					 	 is MSB			*/
+    string		subjectCn;	    /**< Subject common name	*/
+    string		subjectInfo;	    /**< One line subject, fields
+					 	 are separated by slash, e.g:
+					 	 "CN=sample.org/OU=HRD" */
+
+    string		issuerCn;	    /**< Issuer common name	*/
+    string		issuerInfo;	    /**< One line subject, fields
+					 	 are separated by slash */
+
+    TimeVal		validityStart;	    /**< Validity start		*/
+    TimeVal		validityEnd;	    /**< Validity end		*/
+    bool		validityGmt;	    /**< Flag if validity 
+					 	 date/time use GMT	*/
+
+    vector<SslCertName> subjectAltName;     /**< Subject alternative
+					 	 name extension		*/
+
+    string 		raw;		    /**< Raw certificate in PEM
+    						 format, only available
+					 	 for remote certificate */
+
+public:
+    /**
+     * Check if the info is set with empty values.
+     *
+     * @return      	True if the info is empty.
+     */
+    bool isEmpty() const;
+
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pj_ssl_cert_info &info);
+};
+
+/**
+ * TLS transport information.
+ */
+struct TlsInfo
+{
+    /**
+     * Describes whether secure socket connection is established, i.e: TLS/SSL 
+     * handshaking has been done successfully.
+     */
+    bool 		established;
+
+    /**
+     * Describes secure socket protocol being used, see #pj_ssl_sock_proto. 
+     * Use bitwise OR operation to combine the protocol type.
+     */
+    unsigned 		protocol;
+
+    /**
+     * Describes cipher suite being used, this will only be set when connection
+     * is established.
+     */
+    pj_ssl_cipher	cipher;
+
+    /**
+     * Describes cipher name being used, this will only be set when connection
+     * is established.
+     */
+    string		cipherName;
+
+    /**
+     * Describes local address.
+     */
+    SocketAddress 	localAddr;
+
+    /**
+     * Describes remote address.
+     */
+    SocketAddress 	remoteAddr;
+   
+    /**
+     * Describes active local certificate info. Use SslCertInfo.isEmpty()
+     * to check if the local cert info is available.
+     */
+    SslCertInfo 	localCertInfo;
+   
+    /**
+     * Describes active remote certificate info. Use SslCertInfo.isEmpty()
+     * to check if the remote cert info is available.
+     */
+    SslCertInfo 	remoteCertInfo;
+
+    /**
+     * Status of peer certificate verification.
+     */
+    unsigned		verifyStatus;
+
+    /**
+     * Error messages (if any) of peer certificate verification, based on
+     * the field verifyStatus above.
+     */
+    StringVector	verifyMsgs;
+
+public:
+    /**
+     * Constructor.
+     */
+    TlsInfo();
+
+    /**
+     * Check if the info is set with empty values.
+     *
+     * @return      	True if the info is empty.
+     */
+    bool isEmpty() const;
+
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsip_tls_state_info &info);
+};
+
+/**
  * Parameter of Endpoint::onTransportState() callback.
  */
@@ -133,4 +267,9 @@
      */
     TransportHandle	hnd;
+    
+    /**
+     * The transport type.
+     */
+    string		type;
 
     /**
@@ -143,4 +282,10 @@
      */
     pj_status_t		lastError;
+    
+    /**
+     * TLS transport info, only used if transport type is TLS. Use 
+     * TlsInfo.isEmpty() to check if this info is available.
+     */
+    TlsInfo		tlsInfo;
 };
 
@@ -1030,4 +1175,19 @@
      */
     void transportClose(TransportId id) throw(Error);
+    
+    /**
+     * Start graceful shutdown procedure for this transport handle. After
+     * graceful shutdown has been initiated, no new reference can be
+     * obtained for the transport. However, existing objects that currently
+     * uses the transport may still use this transport to send and receive
+     * packets. After all objects release their reference to this transport,
+     * the transport will be destroyed immediately.
+     *
+     * Note: application normally uses this API after obtaining the handle
+     * from onTransportState() callback.
+     *
+     * @param tp		The transport.
+     */
+    void transportShutdown(TransportHandle tp) throw(Error);
 
     /*************************************************************************
Index: pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5517)
+++ pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5518)
@@ -45,4 +45,80 @@
 ///////////////////////////////////////////////////////////////////////////////
 
+TlsInfo::TlsInfo()
+{
+    pj_bzero(this, sizeof(TlsInfo));
+}
+
+bool TlsInfo::isEmpty() const
+{
+    TlsInfo dummy;
+
+    pj_bzero(&dummy, sizeof(dummy));
+    return ((pj_memcmp(this, &dummy, sizeof(dummy)) == 0)? true: false);
+}
+
+void TlsInfo::fromPj(const pjsip_tls_state_info &info)
+{
+#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
+    pj_ssl_sock_info *ssock_info = info.ssl_sock_info;
+    char straddr[PJ_INET6_ADDRSTRLEN+10];
+    const char *verif_msgs[32];
+    unsigned verif_msg_cnt;
+    
+    established = PJ2BOOL(ssock_info->established);
+    protocol 	= ssock_info->proto;
+    cipher 	= ssock_info->cipher;
+    cipherName	= pj_ssl_cipher_name(ssock_info->cipher);
+    pj_sockaddr_print(&ssock_info->local_addr, straddr, sizeof(straddr), 3);
+    localAddr 	= straddr;
+    pj_sockaddr_print(&ssock_info->remote_addr, straddr, sizeof(straddr),3);
+    remoteAddr 	= straddr;
+    verifyStatus = ssock_info->verify_status;
+    if (ssock_info->local_cert_info)
+        localCertInfo.fromPj(*ssock_info->local_cert_info);
+    if (ssock_info->remote_cert_info)
+        remoteCertInfo.fromPj(*ssock_info->remote_cert_info);
+    
+    /* Dump server TLS certificate verification result */
+    verif_msg_cnt = PJ_ARRAY_SIZE(verif_msgs);
+    pj_ssl_cert_get_verify_status_strings(ssock_info->verify_status,
+    				      	  verif_msgs, &verif_msg_cnt);
+    for (unsigned i = 0; i < verif_msg_cnt; ++i) {
+        verifyMsgs.push_back(verif_msgs[i]);
+    }
+#endif
+}
+
+bool SslCertInfo::isEmpty() const
+{
+    SslCertInfo dummy;
+
+    pj_bzero(&dummy, sizeof(dummy));
+    return ((pj_memcmp(this, &dummy, sizeof(dummy)) == 0)? true: false);
+}
+
+void SslCertInfo::fromPj(const pj_ssl_cert_info &info)
+{
+    version 	= info.version;
+    pj_memcpy(serialNo, info.serial_no, sizeof(info.serial_no));
+    subjectCn 	= pj2Str(info.subject.cn);
+    subjectInfo = pj2Str(info.subject.info);
+    issuerCn 	= pj2Str(info.issuer.cn);
+    issuerInfo 	= pj2Str(info.issuer.info);
+    validityStart.fromPj(info.validity.start);
+    validityEnd.fromPj(info.validity.end);
+    validityGmt = PJ2BOOL(info.validity.gmt);
+    raw 	= pj2Str(info.raw);
+
+    for (unsigned i = 0; i < info.subj_alt_name.cnt; i++) {
+    	SslCertName cname;
+    	cname.type = info.subj_alt_name.entry[i].type;
+    	cname.name = pj2Str(info.subj_alt_name.entry[i].name);
+    	subjectAltName.push_back(cname);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 UaConfig::UaConfig()
 : mainThreadOnly(false)
@@ -559,6 +635,18 @@
 
     prm.hnd = (TransportHandle)tp;
+    prm.type = tp->type_name;
     prm.state = state;
     prm.lastError = info ? info->status : PJ_SUCCESS;
+    pj_bzero(&prm.tlsInfo, sizeof(TlsInfo));
+
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
+    if (!pj_ansi_stricmp(tp->type_name, "tls") && info->ext_info &&
+	(state == PJSIP_TP_STATE_CONNECTED || 
+	 ((pjsip_tls_state_info*)info->ext_info)->
+			         ssl_sock_info->verify_status != PJ_SUCCESS))
+    {
+    	prm.tlsInfo.fromPj(*((pjsip_tls_state_info*)info->ext_info));
+    }
+#endif
 
     ep.onTransportState(prm);
@@ -1695,4 +1783,9 @@
 }
 
+void Endpoint::transportShutdown(TransportHandle tp) throw(Error)
+{
+    PJSUA2_CHECK_EXPR( pjsip_transport_shutdown((pjsip_transport *)tp) );
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 /*
