Fixed issue #139: thread-safe exception handling.
This commit is contained in:
parent
4d1a6ad2f2
commit
4e28af3a21
@ -71,11 +71,7 @@ TLSSocket_GnuTLS::TLSSocket_GnuTLS(shared_ptr <TLSSession_GnuTLS> session, share
|
|||||||
|
|
||||||
TLSSocket_GnuTLS::~TLSSocket_GnuTLS()
|
TLSSocket_GnuTLS::~TLSSocket_GnuTLS()
|
||||||
{
|
{
|
||||||
if (m_ex)
|
resetException();
|
||||||
{
|
|
||||||
delete m_ex;
|
|
||||||
m_ex = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -194,12 +190,13 @@ size_t TLSSocket_GnuTLS::receiveRaw(byte_t* buffer, const size_t count)
|
|||||||
{
|
{
|
||||||
m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
|
m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
|
||||||
|
|
||||||
|
resetException();
|
||||||
|
|
||||||
const ssize_t ret = gnutls_record_recv
|
const ssize_t ret = gnutls_record_recv
|
||||||
(*m_session->m_gnutlsSession,
|
(*m_session->m_gnutlsSession,
|
||||||
buffer, static_cast <size_t>(count));
|
buffer, static_cast <size_t>(count));
|
||||||
|
|
||||||
if (m_ex)
|
throwException();
|
||||||
internalThrow();
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
@ -226,12 +223,13 @@ void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count)
|
|||||||
|
|
||||||
for (size_t size = count ; size > 0 ; )
|
for (size_t size = count ; size > 0 ; )
|
||||||
{
|
{
|
||||||
|
resetException();
|
||||||
|
|
||||||
ssize_t ret = gnutls_record_send
|
ssize_t ret = gnutls_record_send
|
||||||
(*m_session->m_gnutlsSession,
|
(*m_session->m_gnutlsSession,
|
||||||
buffer, static_cast <size_t>(size));
|
buffer, static_cast <size_t>(size));
|
||||||
|
|
||||||
if (m_ex)
|
throwException();
|
||||||
internalThrow();
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
@ -260,12 +258,13 @@ size_t TLSSocket_GnuTLS::sendRawNonBlocking(const byte_t* buffer, const size_t c
|
|||||||
{
|
{
|
||||||
m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
|
m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
|
||||||
|
|
||||||
|
resetException();
|
||||||
|
|
||||||
ssize_t ret = gnutls_record_send
|
ssize_t ret = gnutls_record_send
|
||||||
(*m_session->m_gnutlsSession,
|
(*m_session->m_gnutlsSession,
|
||||||
buffer, static_cast <size_t>(count));
|
buffer, static_cast <size_t>(count));
|
||||||
|
|
||||||
if (m_ex)
|
throwException();
|
||||||
internalThrow();
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
@ -307,10 +306,11 @@ void TLSSocket_GnuTLS::handshake()
|
|||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
resetException();
|
||||||
|
|
||||||
const int ret = gnutls_handshake(*m_session->m_gnutlsSession);
|
const int ret = gnutls_handshake(*m_session->m_gnutlsSession);
|
||||||
|
|
||||||
if (m_ex)
|
throwException();
|
||||||
internalThrow();
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
@ -498,38 +498,21 @@ shared_ptr <security::cert::certificateChain> TLSSocket_GnuTLS::getPeerCertifica
|
|||||||
// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions
|
// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions
|
||||||
// thrown by the socket can not be caught.
|
// thrown by the socket can not be caught.
|
||||||
|
|
||||||
#ifndef VMIME_BUILDING_DOC
|
void TLSSocket_GnuTLS::throwException()
|
||||||
|
|
||||||
class TLSSocket_DeleteExWrapper : public object
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
|
|
||||||
TLSSocket_DeleteExWrapper(exception* ex) : m_ex(ex) { }
|
|
||||||
~TLSSocket_DeleteExWrapper() { delete m_ex; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
exception* m_ex;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // VMIME_BUILDING_DOC
|
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_GnuTLS::internalThrow()
|
|
||||||
{
|
|
||||||
static std::vector <shared_ptr <TLSSocket_DeleteExWrapper> > exToDelete;
|
|
||||||
|
|
||||||
if (m_ex)
|
if (m_ex)
|
||||||
{
|
{
|
||||||
// Reset the current exception pointer to prevent the same
|
throw *m_ex;
|
||||||
// exception from being thrown again later
|
}
|
||||||
exception* ex = m_ex;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TLSSocket_GnuTLS::resetException()
|
||||||
|
{
|
||||||
|
if (m_ex)
|
||||||
|
{
|
||||||
|
delete m_ex;
|
||||||
m_ex = NULL;
|
m_ex = NULL;
|
||||||
|
|
||||||
// To avoid memory leaks
|
|
||||||
exToDelete.push_back(make_shared <TLSSocket_DeleteExWrapper>(ex));
|
|
||||||
|
|
||||||
throw *ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void internalThrow();
|
void resetException();
|
||||||
|
void throwException();
|
||||||
|
|
||||||
#ifdef LIBGNUTLS_VERSION
|
#ifdef LIBGNUTLS_VERSION
|
||||||
static ssize_t gnutlsPushFunc(gnutls_transport_ptr_t trspt, const void* data, size_t len);
|
static ssize_t gnutlsPushFunc(gnutls_transport_ptr_t trspt, const void* data, size_t len);
|
||||||
|
Loading…
Reference in New Issue
Block a user