void CTlsSocket::OnRead() { m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::OnRead()")); m_canReadFromSocket = true; if (!m_session) return; const int direction = gnutls_record_get_direction(m_session); if (direction && !m_lastReadFailed) { m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::Postponing read")); return; } if (m_tlsState == TlsState::handshake) ContinueHandshake(); if (m_tlsState == TlsState::closing) ContinueShutdown(); else if (m_tlsState == TlsState::conn) { CheckResumeFailedReadWrite(); TriggerEvents(); } }
void CTlsSocket::TrustCurrentCert(bool trusted) { if (m_tlsState != verifycert) { m_pOwner->LogMessage(Debug_Warning, _T("TrustCurrentCert called at wrong time.")); return; } if (trusted) { m_tlsState = conn; if (m_lastWriteFailed) m_lastWriteFailed = false; CheckResumeFailedReadWrite(); if (m_tlsState == conn) { CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::connection); CSocketEventDispatcher::Get().SendEvent(evt); } TriggerEvents(); return; } m_pOwner->LogMessage(::Error, _("Remote certificate not trusted.")); Failure(0, ECONNABORTED); }
void CTlsSocket::TrustCurrentCert(bool trusted) { if (m_tlsState != TlsState::verifycert) { m_pOwner->LogMessage(MessageType::Debug_Warning, _T("TrustCurrentCert called at wrong time.")); return; } if (trusted) { m_tlsState = TlsState::conn; if (m_lastWriteFailed) m_lastWriteFailed = false; CheckResumeFailedReadWrite(); if (m_tlsState == TlsState::conn) { m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::connection, 0); } TriggerEvents(); return; } m_pOwner->LogMessage(MessageType::Error, _("Remote certificate not trusted.")); Failure(0, true); }
int CTlsSocket::Write(const void *buffer, unsigned int len, int& error) { if (m_tlsState == TlsState::handshake || m_tlsState == TlsState::verifycert) { error = EAGAIN; return -1; } else if (m_tlsState != TlsState::conn) { error = ENOTCONN; return -1; } if (m_lastWriteFailed) { error = EAGAIN; return -1; } if (m_writeSkip >= len) { m_writeSkip -= len; return len; } len -= m_writeSkip; buffer = (char*)buffer + m_writeSkip; int res = gnutls_record_send(m_session, buffer, len); while ((res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) && m_canWriteToSocket) res = gnutls_record_send(m_session, 0, 0); if (res >= 0) { error = 0; int written = res + m_writeSkip; m_writeSkip = 0; TriggerEvents(); return written; } if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) { if (m_writeSkip) { error = 0; int written = m_writeSkip; m_writeSkip = 0; return written; } else { error = EAGAIN; m_lastWriteFailed = true; return -1; } } else { Failure(res, false, _T("gnutls_record_send")); error = m_socket_error; return -1; } }
bool EventDispatcher::DispatchEvent(Element* target_element, const String& name, const Dictionary& parameters, bool interruptible) { //Event event(target_element, name, parameters, interruptible); Event* event = Factory::InstanceEvent(target_element, name, parameters, interruptible); if (event == NULL) return false; // Build the element traversal from the tree typedef std::vector<Element*> Elements; Elements elements; Element* walk_element = target_element->GetParentNode(); while (walk_element) { elements.push_back(walk_element); walk_element = walk_element->GetParentNode(); } event->SetPhase(Event::PHASE_CAPTURE); // Capture phase - root, to target (only events that have registered as capture events) // Note: We walk elements in REVERSE as they're placed in the list from the elements parent to the root for (int i = elements.size() - 1; i >= 0 && event->IsPropagating(); i--) { EventDispatcher* dispatcher = elements[i]->GetEventDispatcher(); event->SetCurrentElement(elements[i]); dispatcher->TriggerEvents(event); } // Target phase - direct at the target if (event->IsPropagating()) { event->SetPhase(Event::PHASE_TARGET); event->SetCurrentElement(target_element); TriggerEvents(event); } if (event->IsPropagating()) { event->SetPhase(Event::PHASE_BUBBLE); // Bubble phase - target to root (normal event bindings) for (size_t i = 0; i < elements.size() && event->IsPropagating(); i++) { EventDispatcher* dispatcher = elements[i]->GetEventDispatcher(); event->SetCurrentElement(elements[i]); dispatcher->TriggerEvents(event); } } bool propagating = event->IsPropagating(); event->RemoveReference(); return propagating; }
void CTlsSocket::TrustCurrentCert(bool trusted) { if (m_tlsState != verifycert) { m_pOwner->LogMessage(Debug_Warning, _T("TrustCurrentCert called at wrong time.")); return; } if (trusted) { m_tlsState = conn; wxSocketEvent evt(GetId()); evt.m_event = wxSOCKET_CONNECTION; wxPostEvent(m_pEvtHandler, evt); TriggerEvents(); return; } m_pOwner->LogMessage(::Error, _("Remote certificate not trusted.")); Failure(0); }
void CTlsSocket::OnSend() { m_pOwner->LogMessage(Debug_Debug, _T("CTlsSocket::OnSend()")); m_canWriteToSocket = true; if (!m_session) return; if (!gnutls_record_get_direction(m_session)) return; if (m_tlsState == handshake) Handshake(); else if (m_tlsState == closing) ContinueShutdown(); else if (m_tlsState == conn) { CheckResumeFailedWrite(); TriggerEvents(); } }
int CTlsSocket::Read(void *buffer, unsigned int len, int& error) { if (m_tlsState == handshake || m_tlsState == verifycert) { error = EAGAIN; return -1; } else if (m_tlsState != conn) { error = ENOTCONN; return -1; } else if (m_lastReadFailed) { error = EAGAIN; return -1; } if (m_peekDataLen) { unsigned int min = wxMin(len, m_peekDataLen); memcpy(buffer, m_peekData, min); if (min == m_peekDataLen) { m_peekDataLen = 0; delete [] m_peekData; m_peekData = 0; } else { memmove(m_peekData, m_peekData + min, m_peekDataLen - min); m_peekDataLen -= min; } TriggerEvents(); error = 0; return min; } int res = gnutls_record_recv(m_session, buffer, len); if (res >= 0) { if (res > 0) TriggerEvents(); else { // Peer did already initiate a shutdown, reply to it gnutls_bye(m_session, GNUTLS_SHUT_WR); // Note: Theoretically this could return a write error. // But we ignore it, since it is perfectly valid for peer // to close the connection after sending its shutdown // notification. } error = 0; return res; } if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) { error = EAGAIN; m_lastReadFailed = true; } else { Failure(res, 0, _T("gnutls_record_recv")); error = ECONNABORTED; } return -1; }
void CTlsSocket::Write(const void *buffer, unsigned int len) { if (m_tlsState == handshake) { m_lastError = wxSOCKET_WOULDBLOCK; m_lastSuccessful = false; return; } else if (m_tlsState != conn) { m_lastError = wxSOCKET_IOERR; m_lastSuccessful = false; return; } if (m_lastWriteFailed) { m_lastError = wxSOCKET_WOULDBLOCK; m_lastSuccessful = false; return; } if (m_writeSkip >= len) { m_writeSkip -= len; m_lastCount = len; m_lastSuccessful = true; return; } len -= m_writeSkip; buffer = (char*)buffer + m_writeSkip; int res = gnutls_record_send(m_session, buffer, len); if (res >= 0) { m_lastSuccessful = true; m_lastCount = res + m_writeSkip; m_writeSkip = 0; TriggerEvents(); return; } if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) { if (m_writeSkip) { m_lastSuccessful = true; m_lastCount = m_writeSkip; m_writeSkip = 0; } else { m_lastSuccessful = false; m_lastError = wxSOCKET_WOULDBLOCK; m_lastWriteFailed = true; } } else { m_lastSuccessful = false; Failure(res); m_lastError = wxSOCKET_IOERR; } }
void CTlsSocket::Read(void *buffer, unsigned int len) { if (m_tlsState == handshake) { m_lastError = wxSOCKET_WOULDBLOCK; m_lastSuccessful = false; return; } else if (m_tlsState != conn) { m_lastError = wxSOCKET_IOERR; m_lastSuccessful = false; return; } m_canTriggerRead = true; if (m_peekDataLen) { unsigned int min = wxMin(len, m_peekDataLen); memcpy(buffer, m_peekData, min); if (min == m_peekDataLen) { m_peekDataLen = 0; delete [] m_peekData; m_peekData = 0; } else { memmove(m_peekData, m_peekData + min, m_peekDataLen - min); m_peekDataLen -= min; } TriggerEvents(); m_lastSuccessful = true; m_lastCount = min; return; } int res = gnutls_record_recv(m_session, buffer, len); if (res >= 0) { m_lastSuccessful = true; m_lastCount = res; if (res > 0) TriggerEvents(); return; } if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) m_lastError = wxSOCKET_WOULDBLOCK; else { Failure(res); m_lastError = wxSOCKET_IOERR; } m_lastSuccessful = false; return; }
int CTlsSocket::Handshake(const CTlsSocket* pPrimarySocket /*=0*/) { m_pOwner->LogMessage(Debug_Verbose, _T("CTlsSocket::Handshake()")); wxASSERT(m_session); m_tlsState = handshake; if (pPrimarySocket) { // Implicitly trust certificate of primary socket unsigned int cert_list_size; const gnutls_datum_t* const cert_list = gnutls_certificate_get_peers(pPrimarySocket->m_session, &cert_list_size); if (cert_list && cert_list_size) { m_implicitTrustedCert.data = new unsigned char[cert_list[0].size]; memcpy(m_implicitTrustedCert.data, cert_list[0].data, cert_list[0].size); m_implicitTrustedCert.size = cert_list[0].size; } } int res = gnutls_handshake(m_session); if (!res) { m_pOwner->LogMessage(Debug_Info, _T("Handshake successful")); wxString cipherName; const char* cipher = gnutls_cipher_get_name(gnutls_cipher_get(m_session)); if (cipher) cipherName = wxString(cipher, wxConvUTF8); else cipherName = _T("unknown"); wxString macName; const char* mac = gnutls_mac_get_name(gnutls_mac_get(m_session)); if (mac) macName = wxString(mac, wxConvUTF8); else macName = _T("unknown"); m_pOwner->LogMessage(Debug_Info, _T("Cipher: %s, MAC: %s"), cipherName.c_str(), macName.c_str()); res = VerifyCertificate(); if (res != FZ_REPLY_OK) return res; m_tlsState = conn; wxSocketEvent evt(GetId()); evt.m_event = wxSOCKET_CONNECTION; wxPostEvent(m_pEvtHandler, evt); TriggerEvents(); if (m_shutdown_requested) { Shutdown(); if (!Error() || LastError() != wxSOCKET_WOULDBLOCK) { wxSocketEvent evt(GetId()); evt.m_event = wxSOCKET_LOST; wxPostEvent(m_pEvtHandler, evt); } } return FZ_REPLY_OK; } else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) return FZ_REPLY_WOULDBLOCK; Failure(res); return FZ_REPLY_ERROR; }