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;
    }
}