Better handling of SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE. Sockets on Windows platform are now non-blocking (thanks to Mehmet Bozkurt).
This commit is contained in:
parent
fc9bc26384
commit
3e9e8c9265
@ -53,7 +53,7 @@ ref <TLSSocket> TLSSocket::wrap(ref <TLSSession> session, ref <socket> sok)
|
|||||||
|
|
||||||
TLSSocket_GnuTLS::TLSSocket_GnuTLS(ref <TLSSession_GnuTLS> session, ref <socket> sok)
|
TLSSocket_GnuTLS::TLSSocket_GnuTLS(ref <TLSSession_GnuTLS> session, ref <socket> sok)
|
||||||
: m_session(session), m_wrapped(sok), m_connected(false),
|
: m_session(session), m_wrapped(sok), m_connected(false),
|
||||||
m_handshaking(false), m_ex(NULL)
|
m_handshaking(false), m_ex(NULL), m_status(0)
|
||||||
{
|
{
|
||||||
gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);
|
gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);
|
||||||
|
|
||||||
@ -131,6 +131,8 @@ void TLSSocket_GnuTLS::send(const string& buffer)
|
|||||||
|
|
||||||
TLSSocket::size_type TLSSocket_GnuTLS::receiveRaw(char* buffer, const size_type count)
|
TLSSocket::size_type TLSSocket_GnuTLS::receiveRaw(char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
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));
|
||||||
@ -141,23 +143,67 @@ TLSSocket::size_type TLSSocket_GnuTLS::receiveRaw(char* buffer, const size_type
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
if (ret == GNUTLS_E_AGAIN)
|
if (ret == GNUTLS_E_AGAIN)
|
||||||
|
{
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
TLSSession_GnuTLS::throwTLSException("gnutls_record_recv", ret);
|
TLSSession_GnuTLS::throwTLSException("gnutls_record_recv", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast <int>(ret);
|
return static_cast <size_type>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_GnuTLS::sendRaw(const char* buffer, const size_type count)
|
void TLSSocket_GnuTLS::sendRaw(const char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
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)
|
if (m_ex)
|
||||||
internalThrow();
|
internalThrow();
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
if (ret == GNUTLS_E_AGAIN)
|
||||||
|
{
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLSSession_GnuTLS::throwTLSException("gnutls_record_send", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TLSSocket::size_type TLSSocket_GnuTLS::sendRawNonBlocking(const char* buffer, const size_type count)
|
||||||
|
{
|
||||||
|
ssize_t ret = gnutls_record_send
|
||||||
|
(*m_session->m_gnutlsSession,
|
||||||
|
buffer, static_cast <size_t>(count));
|
||||||
|
|
||||||
|
if (m_ex)
|
||||||
|
internalThrow();
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
if (ret == GNUTLS_E_AGAIN)
|
||||||
|
{
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLSSession_GnuTLS::throwTLSException("gnutls_record_send", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast <size_type>(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int TLSSocket_GnuTLS::getStatus() const
|
||||||
|
{
|
||||||
|
return m_status | m_wrapped->getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -290,8 +336,8 @@ ssize_t TLSSocket_GnuTLS::gnutlsPullFunc
|
|||||||
(reinterpret_cast <char*>(data),
|
(reinterpret_cast <char*>(data),
|
||||||
static_cast <int>(len)));
|
static_cast <int>(len)));
|
||||||
|
|
||||||
if (n == 0)
|
if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK)
|
||||||
return GNUTLS_E_AGAIN; // This seems like a hack, really...
|
return GNUTLS_E_AGAIN;
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,9 @@ TLSSession_OpenSSL::TLSSession_OpenSSL(ref <vmime::security::cert::certificateVe
|
|||||||
|
|
||||||
m_sslctx = SSL_CTX_new(SSLv23_client_method());
|
m_sslctx = SSL_CTX_new(SSLv23_client_method());
|
||||||
SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
|
SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
|
||||||
|
SSL_CTX_set_mode(m_sslctx, SSL_MODE_AUTO_RETRY);
|
||||||
|
SSL_CTX_set_cipher_list(m_sslctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
|
||||||
|
SSL_CTX_set_session_cache_mode(m_sslctx, SSL_SESS_CACHE_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ ref <TLSSocket> TLSSocket::wrap(ref <TLSSession> session, ref <socket> sok)
|
|||||||
|
|
||||||
|
|
||||||
TLSSocket_OpenSSL::TLSSocket_OpenSSL(ref <TLSSession_OpenSSL> session, ref <socket> sok)
|
TLSSocket_OpenSSL::TLSSocket_OpenSSL(ref <TLSSession_OpenSSL> session, ref <socket> sok)
|
||||||
: m_session(session), m_wrapped(sok), m_connected(false), m_ssl(0)
|
: m_session(session), m_wrapped(sok), m_connected(false), m_ssl(0), m_ex(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,8 +162,10 @@ TLSSocket::size_type TLSSocket_OpenSSL::getBlockSize() const
|
|||||||
|
|
||||||
void TLSSocket_OpenSSL::receive(string& buffer)
|
void TLSSocket_OpenSSL::receive(string& buffer)
|
||||||
{
|
{
|
||||||
const int size = receiveRaw(m_buffer, sizeof(m_buffer));
|
const size_type size = receiveRaw(m_buffer, sizeof(m_buffer));
|
||||||
buffer = vmime::string(m_buffer, size);
|
|
||||||
|
if (size >= 0)
|
||||||
|
buffer = vmime::string(m_buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -175,19 +177,35 @@ void TLSSocket_OpenSSL::send(const string& buffer)
|
|||||||
|
|
||||||
TLSSocket::size_type TLSSocket_OpenSSL::receiveRaw(char* buffer, const size_type count)
|
TLSSocket::size_type TLSSocket_OpenSSL::receiveRaw(char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
int rc = SSL_read(m_ssl, buffer, count);
|
int rc = SSL_read(m_ssl, buffer, static_cast <int>(count));
|
||||||
handleError(rc);
|
handleError(rc);
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_OpenSSL::sendRaw(const char* buffer, const size_type count)
|
void TLSSocket_OpenSSL::sendRaw(const char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
int rc = SSL_write(m_ssl, buffer, count);
|
int rc = SSL_write(m_ssl, buffer, static_cast <int>(count));
|
||||||
handleError(rc);
|
handleError(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TLSSocket_OpenSSL::size_type TLSSocket_OpenSSL::sendRawNonBlocking(const char* buffer, const size_type count)
|
||||||
|
{
|
||||||
|
int rc = SSL_write(m_ssl, buffer, static_cast <int>(count));
|
||||||
|
handleError(rc);
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_OpenSSL::handshake(ref <timeoutHandler> toHandler)
|
void TLSSocket_OpenSSL::handshake(ref <timeoutHandler> toHandler)
|
||||||
{
|
{
|
||||||
if (toHandler)
|
if (toHandler)
|
||||||
@ -260,6 +278,13 @@ ref <security::cert::certificateChain> TLSSocket_OpenSSL::getPeerCertificates()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TLSSocket_OpenSSL::internalThrow()
|
||||||
|
{
|
||||||
|
if (m_ex.get())
|
||||||
|
throw *m_ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSSocket_OpenSSL::handleError(int rc)
|
void TLSSocket_OpenSSL::handleError(int rc)
|
||||||
{
|
{
|
||||||
if (rc > 0) return;
|
if (rc > 0) return;
|
||||||
@ -277,12 +302,14 @@ void TLSSocket_OpenSSL::handleError(int rc)
|
|||||||
if (lastError == 0)
|
if (lastError == 0)
|
||||||
{
|
{
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
|
{
|
||||||
throw exceptions::tls_exception("SSL connection unexpectedly closed");
|
throw exceptions::tls_exception("SSL connection unexpectedly closed");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vmime::string msg;
|
vmime::string msg;
|
||||||
std::ostringstream oss(msg);
|
std::ostringstream oss(msg);
|
||||||
oss << "The BIO reported an error: %d" << rc;
|
oss << "The BIO reported an error: " << rc;
|
||||||
oss.flush();
|
oss.flush();
|
||||||
throw exceptions::tls_exception(oss.str());
|
throw exceptions::tls_exception(oss.str());
|
||||||
}
|
}
|
||||||
@ -290,10 +317,16 @@ void TLSSocket_OpenSSL::handleError(int rc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//// Follwoing errors should not occur
|
|
||||||
// With SSL_MODE_AUTO_RETRY these should not happen
|
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
|
|
||||||
|
BIO_set_retry_read(SSL_get_rbio(m_ssl));
|
||||||
|
break;
|
||||||
|
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
|
||||||
|
BIO_set_retry_write(SSL_get_wbio(m_ssl));
|
||||||
|
break;
|
||||||
|
|
||||||
// This happens only for BIOs of type BIO_s_connect() or BIO_s_accept()
|
// This happens only for BIOs of type BIO_s_connect() or BIO_s_accept()
|
||||||
case SSL_ERROR_WANT_CONNECT:
|
case SSL_ERROR_WANT_CONNECT:
|
||||||
case SSL_ERROR_WANT_ACCEPT:
|
case SSL_ERROR_WANT_ACCEPT:
|
||||||
@ -319,6 +352,12 @@ void TLSSocket_OpenSSL::handleError(int rc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int TLSSocket_OpenSSL::getStatus() const
|
||||||
|
{
|
||||||
|
return m_wrapped->getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Implementation of custom BIO methods
|
// Implementation of custom BIO methods
|
||||||
|
|
||||||
|
|
||||||
@ -330,9 +369,28 @@ int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len)
|
|||||||
|
|
||||||
TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr);
|
TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr);
|
||||||
|
|
||||||
sok->m_wrapped->sendRaw(buf, len);
|
try
|
||||||
|
{
|
||||||
|
BIO_clear_retry_flags(bio);
|
||||||
|
|
||||||
return len;
|
const size_type n = sok->m_wrapped->sendRawNonBlocking(buf, len);
|
||||||
|
|
||||||
|
BIO_clear_retry_flags(bio);
|
||||||
|
|
||||||
|
if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK)
|
||||||
|
{
|
||||||
|
BIO_set_retry_write(bio);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast <int>(len);
|
||||||
|
}
|
||||||
|
catch (exception& e)
|
||||||
|
{
|
||||||
|
// Workaround for passing C++ exceptions from C BIO functions
|
||||||
|
sok->m_ex.reset(e.clone());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -344,21 +402,33 @@ int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len)
|
|||||||
|
|
||||||
TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr);
|
TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(bio->ptr);
|
||||||
|
|
||||||
const int n = sok->m_wrapped->receiveRaw(buf, len);
|
try
|
||||||
|
{
|
||||||
|
const size_type n = sok->m_wrapped->receiveRaw(buf, len);
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
BIO_set_retry_read(bio); // This seems like a hack, really...
|
|
||||||
else
|
|
||||||
BIO_clear_retry_flags(bio);
|
BIO_clear_retry_flags(bio);
|
||||||
|
|
||||||
return n;
|
if (sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK)
|
||||||
|
{
|
||||||
|
BIO_set_retry_read(bio);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast <int>(n);
|
||||||
|
}
|
||||||
|
catch (exception& e)
|
||||||
|
{
|
||||||
|
// Workaround for passing C++ exceptions from C BIO functions
|
||||||
|
sok->m_ex.reset(e.clone());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
int TLSSocket_OpenSSL::bio_puts(BIO* bio, const char* str)
|
int TLSSocket_OpenSSL::bio_puts(BIO* bio, const char* str)
|
||||||
{
|
{
|
||||||
return bio_write(bio, str, strlen(str));
|
return bio_write(bio, str, static_cast <int>(strlen(str)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +43,13 @@
|
|||||||
#include "vmime/exception.hpp"
|
#include "vmime/exception.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(EWOULDBLOCK)
|
||||||
|
# define IS_EAGAIN(x) ((x) == EAGAIN || (x) == EWOULDBLOCK || (x) == EINTR)
|
||||||
|
#else
|
||||||
|
# define IS_EAGAIN(x) ((x) == EAGAIN || (x) == EINTR)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace vmime {
|
namespace vmime {
|
||||||
namespace platforms {
|
namespace platforms {
|
||||||
namespace posix {
|
namespace posix {
|
||||||
@ -53,7 +60,7 @@ namespace posix {
|
|||||||
//
|
//
|
||||||
|
|
||||||
posixSocket::posixSocket(ref <vmime::net::timeoutHandler> th)
|
posixSocket::posixSocket(ref <vmime::net::timeoutHandler> th)
|
||||||
: m_timeoutHandler(th), m_desc(-1)
|
: m_timeoutHandler(th), m_desc(-1), m_status(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,13 +339,15 @@ posixSocket::size_type posixSocket::getBlockSize() const
|
|||||||
|
|
||||||
void posixSocket::receive(vmime::string& buffer)
|
void posixSocket::receive(vmime::string& buffer)
|
||||||
{
|
{
|
||||||
const int size = receiveRaw(m_buffer, sizeof(m_buffer));
|
const size_type size = receiveRaw(m_buffer, sizeof(m_buffer));
|
||||||
buffer = vmime::string(m_buffer, size);
|
buffer = vmime::string(m_buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
posixSocket::size_type posixSocket::receiveRaw(char* buffer, const size_type count)
|
posixSocket::size_type posixSocket::receiveRaw(char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
// Check whether data is available
|
// Check whether data is available
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
@ -348,11 +357,11 @@ posixSocket::size_type posixSocket::receiveRaw(char* buffer, const size_type cou
|
|||||||
tv.tv_sec = 1;
|
tv.tv_sec = 1;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
int ret = ::select(m_desc + 1, &fds, NULL, NULL, &tv);
|
ssize_t ret = ::select(m_desc + 1, &fds, NULL, NULL, &tv);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
if (errno != EAGAIN)
|
if (!IS_EAGAIN(errno))
|
||||||
throwSocketError(errno);
|
throwSocketError(errno);
|
||||||
|
|
||||||
// No data available at this time
|
// No data available at this time
|
||||||
@ -372,6 +381,8 @@ posixSocket::size_type posixSocket::receiveRaw(char* buffer, const size_type cou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
// Continue waiting for data
|
// Continue waiting for data
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -381,9 +392,27 @@ posixSocket::size_type posixSocket::receiveRaw(char* buffer, const size_type cou
|
|||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
if (errno != EAGAIN)
|
if (!IS_EAGAIN(errno))
|
||||||
throwSocketError(errno);
|
throwSocketError(errno);
|
||||||
|
|
||||||
|
// Check if we are timed out
|
||||||
|
if (m_timeoutHandler &&
|
||||||
|
m_timeoutHandler->isTimeOut())
|
||||||
|
{
|
||||||
|
if (!m_timeoutHandler->handleTimeOut())
|
||||||
|
{
|
||||||
|
// Server did not react within timeout delay
|
||||||
|
throwSocketError(errno);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reset timeout
|
||||||
|
m_timeoutHandler->resetTimeOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
// No data available at this time
|
// No data available at this time
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -411,15 +440,17 @@ void posixSocket::send(const vmime::string& buffer)
|
|||||||
|
|
||||||
void posixSocket::sendRaw(const char* buffer, const size_type count)
|
void posixSocket::sendRaw(const char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
size_type size = count;
|
size_type size = count;
|
||||||
|
|
||||||
while (size > 0)
|
while (size > 0)
|
||||||
{
|
{
|
||||||
const int ret = ::send(m_desc, buffer, size, 0);
|
const ssize_t ret = ::send(m_desc, buffer, size, 0);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
if (errno != EAGAIN)
|
if (!IS_EAGAIN(errno))
|
||||||
throwSocketError(errno);
|
throwSocketError(errno);
|
||||||
|
|
||||||
platform::getHandler()->wait();
|
platform::getHandler()->wait();
|
||||||
@ -437,6 +468,27 @@ void posixSocket::sendRaw(const char* buffer, const size_type count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
posixSocket::size_type posixSocket::sendRawNonBlocking(const char* buffer, const size_type count)
|
||||||
|
{
|
||||||
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
|
const ssize_t ret = ::send(m_desc, buffer, count, 0);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
if (!IS_EAGAIN(errno))
|
||||||
|
throwSocketError(errno);
|
||||||
|
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
|
// No data can be written at this time
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void posixSocket::throwSocketError(const int err)
|
void posixSocket::throwSocketError(const int err)
|
||||||
{
|
{
|
||||||
string msg;
|
string msg;
|
||||||
@ -473,6 +525,12 @@ void posixSocket::throwSocketError(const int err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int posixSocket::getStatus() const
|
||||||
|
{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// posixSocketFactory
|
// posixSocketFactory
|
||||||
|
@ -40,11 +40,11 @@ namespace windows {
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// posixSocket
|
// windowsSocket
|
||||||
//
|
//
|
||||||
|
|
||||||
windowsSocket::windowsSocket(ref <vmime::net::timeoutHandler> th)
|
windowsSocket::windowsSocket(ref <vmime::net::timeoutHandler> th)
|
||||||
: m_timeoutHandler(th), m_desc(-1)
|
: m_timeoutHandler(th), m_desc(INVALID_SOCKET), m_status(0)
|
||||||
{
|
{
|
||||||
WSAData wsaData;
|
WSAData wsaData;
|
||||||
WSAStartup(MAKEWORD(1, 1), &wsaData);
|
WSAStartup(MAKEWORD(1, 1), &wsaData);
|
||||||
@ -53,8 +53,9 @@ windowsSocket::windowsSocket(ref <vmime::net::timeoutHandler> th)
|
|||||||
|
|
||||||
windowsSocket::~windowsSocket()
|
windowsSocket::~windowsSocket()
|
||||||
{
|
{
|
||||||
if (m_desc != -1)
|
if (m_desc != INVALID_SOCKET)
|
||||||
::closesocket(m_desc);
|
::closesocket(m_desc);
|
||||||
|
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,10 +63,10 @@ windowsSocket::~windowsSocket()
|
|||||||
void windowsSocket::connect(const vmime::string& address, const vmime::port_t port)
|
void windowsSocket::connect(const vmime::string& address, const vmime::port_t port)
|
||||||
{
|
{
|
||||||
// Close current connection, if any
|
// Close current connection, if any
|
||||||
if (m_desc != -1)
|
if (m_desc != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
::closesocket(m_desc);
|
::closesocket(m_desc);
|
||||||
m_desc = -1;
|
m_desc = INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve address
|
// Resolve address
|
||||||
@ -93,35 +94,64 @@ void windowsSocket::connect(const vmime::string& address, const vmime::port_t po
|
|||||||
// Get a new socket
|
// Get a new socket
|
||||||
m_desc = ::socket(AF_INET, SOCK_STREAM, 0);
|
m_desc = ::socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
if (m_desc == -1)
|
if (m_desc == INVALID_SOCKET)
|
||||||
throw vmime::exceptions::connection_error("Error while creating socket.");
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
throwSocketError(err);
|
||||||
|
}
|
||||||
|
catch (exceptions::socket_exception& e)
|
||||||
|
{
|
||||||
|
throw vmime::exceptions::connection_error
|
||||||
|
("Error while creating socket.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start connection
|
// Start connection
|
||||||
if (::connect(m_desc, reinterpret_cast <sockaddr*>(&addr), sizeof(addr)) == -1)
|
if (::connect(m_desc, reinterpret_cast <sockaddr*>(&addr), sizeof(addr)) == -1)
|
||||||
{
|
{
|
||||||
::closesocket(m_desc);
|
try
|
||||||
m_desc = -1;
|
{
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
throwSocketError(err);
|
||||||
|
}
|
||||||
|
catch (exceptions::socket_exception& e)
|
||||||
|
{
|
||||||
|
::closesocket(m_desc);
|
||||||
|
m_desc = INVALID_SOCKET;
|
||||||
|
|
||||||
// Error
|
// Error
|
||||||
throw vmime::exceptions::connection_error("Error while connecting socket.");
|
throw vmime::exceptions::connection_error
|
||||||
|
("Error while connecting socket.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set socket to non-blocking
|
||||||
|
unsigned long non_blocking = 1;
|
||||||
|
::ioctlsocket(m_desc, FIONBIO, &non_blocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool windowsSocket::isConnected() const
|
bool windowsSocket::isConnected() const
|
||||||
{
|
{
|
||||||
return (m_desc != -1);
|
if (m_desc == INVALID_SOCKET)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char buff;
|
||||||
|
|
||||||
|
return ::recv(m_desc, &buff, 1, MSG_PEEK) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void windowsSocket::disconnect()
|
void windowsSocket::disconnect()
|
||||||
{
|
{
|
||||||
if (m_desc != -1)
|
if (m_desc != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
::shutdown(m_desc, SD_BOTH);
|
::shutdown(m_desc, SD_BOTH);
|
||||||
::closesocket(m_desc);
|
::closesocket(m_desc);
|
||||||
|
|
||||||
m_desc = -1;
|
m_desc = INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,48 +164,200 @@ windowsSocket::size_type windowsSocket::getBlockSize() const
|
|||||||
|
|
||||||
void windowsSocket::receive(vmime::string& buffer)
|
void windowsSocket::receive(vmime::string& buffer)
|
||||||
{
|
{
|
||||||
int ret = ::recv(m_desc, m_buffer, sizeof(m_buffer), 0);
|
const size_type size = receiveRaw(m_buffer, sizeof(m_buffer));
|
||||||
|
buffer = vmime::string(m_buffer, size);
|
||||||
if (ret == -1)
|
|
||||||
{
|
|
||||||
// Error or no data
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (ret > 0)
|
|
||||||
{
|
|
||||||
buffer = vmime::string(m_buffer, ret);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
windowsSocket::size_type windowsSocket::receiveRaw(char* buffer, const size_type count)
|
windowsSocket::size_type windowsSocket::receiveRaw(char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
|
// Check whether data is available
|
||||||
|
bool timedout;
|
||||||
|
waitForData(READ, timedout);
|
||||||
|
|
||||||
|
if (timedout)
|
||||||
|
{
|
||||||
|
// No data available at this time
|
||||||
|
// Check if we are timed out
|
||||||
|
if (m_timeoutHandler &&
|
||||||
|
m_timeoutHandler->isTimeOut())
|
||||||
|
{
|
||||||
|
if (!m_timeoutHandler->handleTimeOut())
|
||||||
|
{
|
||||||
|
// Server did not react within timeout delay
|
||||||
|
throwSocketError(WSAETIMEDOUT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reset timeout
|
||||||
|
m_timeoutHandler->resetTimeOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue waiting for data
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read available data
|
||||||
int ret = ::recv(m_desc, buffer, count, 0);
|
int ret = ::recv(m_desc, buffer, count, 0);
|
||||||
|
|
||||||
if (ret == -1)
|
if (ret == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
|
||||||
|
if (err != WSAEWOULDBLOCK)
|
||||||
|
throwSocketError(err);
|
||||||
|
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
// Error or no data
|
// Error or no data
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
else if (ret == 0)
|
||||||
|
{
|
||||||
|
// Host shutdown
|
||||||
|
throwSocketError(WSAENOTCONN);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (ret);
|
// Data received, reset timeout
|
||||||
|
if (m_timeoutHandler)
|
||||||
|
m_timeoutHandler->resetTimeOut();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void windowsSocket::send(const vmime::string& buffer)
|
void windowsSocket::send(const vmime::string& buffer)
|
||||||
{
|
{
|
||||||
::send(m_desc, buffer.data(), buffer.length(), 0);
|
sendRaw(buffer.data(), buffer.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void windowsSocket::sendRaw(const char* buffer, const size_type count)
|
void windowsSocket::sendRaw(const char* buffer, const size_type count)
|
||||||
{
|
{
|
||||||
::send(m_desc, buffer, count, 0);
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
|
size_type size = count;
|
||||||
|
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
const int ret = ::send(m_desc, buffer, size, 0);
|
||||||
|
|
||||||
|
if (ret == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
|
||||||
|
if (err != WSAEWOULDBLOCK)
|
||||||
|
throwSocketError(err);
|
||||||
|
|
||||||
|
bool timedout;
|
||||||
|
waitForData(WRITE, timedout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer += ret;
|
||||||
|
size -= ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset timeout
|
||||||
|
if (m_timeoutHandler)
|
||||||
|
m_timeoutHandler->resetTimeOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
windowsSocket::size_type windowsSocket::sendRawNonBlocking(const char* buffer, const size_type count, const bool block)
|
||||||
|
{
|
||||||
|
m_status &= ~STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
|
const int ret = ::send(m_desc, buffer, count, 0);
|
||||||
|
|
||||||
|
if (ret == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
|
||||||
|
if (err == WSAEWOULDBLOCK)
|
||||||
|
{
|
||||||
|
m_status |= STATUS_WOULDBLOCK;
|
||||||
|
|
||||||
|
// No data can be written at this time
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throwSocketError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int windowsSocket::getStatus() const
|
||||||
|
{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void windowsSocket::throwSocketError(const int err)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
string msg;
|
||||||
|
|
||||||
|
LPTSTR str;
|
||||||
|
|
||||||
|
if (::FormatMessage(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
|
NULL, err, 0, (LPTSTR) &str, 0, NULL) == 0)
|
||||||
|
{
|
||||||
|
// Failed getting message
|
||||||
|
oss << "Unknown socket error (code " << err << ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oss << str;
|
||||||
|
::LocalFree(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = oss.str();
|
||||||
|
|
||||||
|
throw exceptions::socket_exception(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void windowsSocket::waitForData(const WaitOpType t, bool& timedOut)
|
||||||
|
{
|
||||||
|
// Check whether data is available
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(m_desc, &fds);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (t & READ)
|
||||||
|
ret = ::select(m_desc + 1, &fds, NULL, NULL, &tv);
|
||||||
|
else if (t & WRITE)
|
||||||
|
ret = ::select(m_desc + 1, NULL, &fds, NULL, &tv);
|
||||||
|
else
|
||||||
|
ret = ::select(m_desc + 1, &fds, &fds, NULL, &tv);
|
||||||
|
|
||||||
|
timedOut = (ret == 0);
|
||||||
|
|
||||||
|
if (ret == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
throwSocketError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -177,6 +177,40 @@ void SASLSocket::sendRaw(const char* buffer, const size_type count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SASLSocket::size_type SASLSocket::sendRawNonBlocking(const char* buffer, const size_type count)
|
||||||
|
{
|
||||||
|
byte_t* output = 0;
|
||||||
|
int outputLen = 0;
|
||||||
|
|
||||||
|
m_session->getMechanism()->encode
|
||||||
|
(m_session, reinterpret_cast <const byte_t*>(buffer), count,
|
||||||
|
&output, &outputLen);
|
||||||
|
|
||||||
|
size_type bytesSent = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bytesSent = m_wrapped->sendRawNonBlocking
|
||||||
|
(reinterpret_cast <const char*>(output), outputLen);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
delete [] output;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] output;
|
||||||
|
|
||||||
|
return bytesSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int SASLSocket::getStatus() const
|
||||||
|
{
|
||||||
|
return m_wrapped->getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // sasl
|
} // sasl
|
||||||
} // security
|
} // security
|
||||||
} // vmime
|
} // vmime
|
||||||
|
@ -47,11 +47,17 @@ class socket : public object
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
STATUS_WOULDBLOCK = 0x1 /**< The receive operation would block. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
virtual ~socket() { }
|
virtual ~socket() { }
|
||||||
|
|
||||||
/** Type used for lengths in streams.
|
/** Type used for lengths in streams.
|
||||||
*/
|
*/
|
||||||
typedef int size_type;
|
typedef long size_type;
|
||||||
|
|
||||||
|
|
||||||
/** Connect to the specified address and port.
|
/** Connect to the specified address and port.
|
||||||
@ -84,7 +90,7 @@ public:
|
|||||||
* @param count maximum number of bytes to receive (size of buffer)
|
* @param count maximum number of bytes to receive (size of buffer)
|
||||||
* @return number of bytes received/written into output buffer
|
* @return number of bytes received/written into output buffer
|
||||||
*/
|
*/
|
||||||
virtual int receiveRaw(char* buffer, const size_type count) = 0;
|
virtual size_type receiveRaw(char* buffer, const size_type count) = 0;
|
||||||
|
|
||||||
/** Send (text) data to the socket.
|
/** Send (text) data to the socket.
|
||||||
*
|
*
|
||||||
@ -99,6 +105,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void sendRaw(const char* buffer, const size_type count) = 0;
|
virtual void sendRaw(const char* buffer, const size_type count) = 0;
|
||||||
|
|
||||||
|
/** Send (raw) data to the socket.
|
||||||
|
* Function may returns before all data is sent.
|
||||||
|
*
|
||||||
|
* @param buffer data to send
|
||||||
|
* @param count number of bytes to send (size of buffer)
|
||||||
|
* @return number of bytes sent
|
||||||
|
*/
|
||||||
|
virtual size_type sendRawNonBlocking(const char* buffer, const size_type count) = 0;
|
||||||
|
|
||||||
/** Return the preferred maximum block size when reading
|
/** Return the preferred maximum block size when reading
|
||||||
* from or writing to this stream.
|
* from or writing to this stream.
|
||||||
*
|
*
|
||||||
@ -106,6 +121,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual size_type getBlockSize() const = 0;
|
virtual size_type getBlockSize() const = 0;
|
||||||
|
|
||||||
|
/** Return the current status of this socket.
|
||||||
|
*
|
||||||
|
* @return status flags for this socket
|
||||||
|
*/
|
||||||
|
virtual unsigned int getStatus() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
socket() { }
|
socket() { }
|
||||||
|
@ -70,9 +70,12 @@ public:
|
|||||||
|
|
||||||
void send(const string& buffer);
|
void send(const string& buffer);
|
||||||
void sendRaw(const char* buffer, const size_type count);
|
void sendRaw(const char* buffer, const size_type count);
|
||||||
|
size_type sendRawNonBlocking(const char* buffer, const size_type count);
|
||||||
|
|
||||||
size_type getBlockSize() const;
|
size_type getBlockSize() const;
|
||||||
|
|
||||||
|
unsigned int getStatus() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void internalThrow();
|
void internalThrow();
|
||||||
@ -97,6 +100,8 @@ private:
|
|||||||
ref <timeoutHandler> m_toHandler;
|
ref <timeoutHandler> m_toHandler;
|
||||||
|
|
||||||
exception* m_ex;
|
exception* m_ex;
|
||||||
|
|
||||||
|
unsigned int m_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
#include "vmime/net/tls/TLSSocket.hpp"
|
#include "vmime/net/tls/TLSSocket.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
|
||||||
@ -72,9 +74,12 @@ public:
|
|||||||
|
|
||||||
void send(const string& buffer);
|
void send(const string& buffer);
|
||||||
void sendRaw(const char* buffer, const size_type count);
|
void sendRaw(const char* buffer, const size_type count);
|
||||||
|
size_type sendRawNonBlocking(const char* buffer, const size_type count);
|
||||||
|
|
||||||
size_type getBlockSize() const;
|
size_type getBlockSize() const;
|
||||||
|
|
||||||
|
unsigned int getStatus() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static int bio_write(BIO* bio, const char* buf, int len);
|
static int bio_write(BIO* bio, const char* buf, int len);
|
||||||
@ -87,8 +92,10 @@ private:
|
|||||||
|
|
||||||
void createSSLHandle();
|
void createSSLHandle();
|
||||||
|
|
||||||
|
void internalThrow();
|
||||||
void handleError(int rc);
|
void handleError(int rc);
|
||||||
|
|
||||||
|
|
||||||
ref <TLSSession_OpenSSL> m_session;
|
ref <TLSSession_OpenSSL> m_session;
|
||||||
|
|
||||||
ref <socket> m_wrapped;
|
ref <socket> m_wrapped;
|
||||||
@ -100,6 +107,9 @@ private:
|
|||||||
ref <timeoutHandler> m_toHandler;
|
ref <timeoutHandler> m_toHandler;
|
||||||
|
|
||||||
SSL* m_ssl;
|
SSL* m_ssl;
|
||||||
|
|
||||||
|
// Last exception thrown from C BIO functions
|
||||||
|
std::auto_ptr <std::exception> m_ex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,9 +55,12 @@ public:
|
|||||||
|
|
||||||
void send(const vmime::string& buffer);
|
void send(const vmime::string& buffer);
|
||||||
void sendRaw(const char* buffer, const size_type count);
|
void sendRaw(const char* buffer, const size_type count);
|
||||||
|
size_type sendRawNonBlocking(const char* buffer, const size_type count);
|
||||||
|
|
||||||
size_type getBlockSize() const;
|
size_type getBlockSize() const;
|
||||||
|
|
||||||
|
unsigned int getStatus() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
static void throwSocketError(const int err);
|
static void throwSocketError(const int err);
|
||||||
@ -68,6 +71,8 @@ private:
|
|||||||
|
|
||||||
char m_buffer[65536];
|
char m_buffer[65536];
|
||||||
int m_desc;
|
int m_desc;
|
||||||
|
|
||||||
|
unsigned int m_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ namespace windows {
|
|||||||
class windowsSocket : public vmime::net::socket
|
class windowsSocket : public vmime::net::socket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
windowsSocket();
|
windowsSocket();
|
||||||
windowsSocket(ref <vmime::net::timeoutHandler> th);
|
windowsSocket(ref <vmime::net::timeoutHandler> th);
|
||||||
~windowsSocket();
|
~windowsSocket();
|
||||||
@ -58,15 +59,33 @@ public:
|
|||||||
|
|
||||||
void send(const vmime::string& buffer);
|
void send(const vmime::string& buffer);
|
||||||
void sendRaw(const char* buffer, const size_type count);
|
void sendRaw(const char* buffer, const size_type count);
|
||||||
|
size_type sendRawNonBlocking(const char* buffer, const size_type count);
|
||||||
|
|
||||||
size_type getBlockSize() const;
|
size_type getBlockSize() const;
|
||||||
|
|
||||||
|
unsigned int getStatus() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void throwSocketError(const int err);
|
||||||
|
|
||||||
|
enum WaitOpType
|
||||||
|
{
|
||||||
|
READ = 1,
|
||||||
|
WRITE = 2,
|
||||||
|
BOTH = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
void waitForData(const WaitOpType t, bool& timedOut);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ref <vmime::net::timeoutHandler> m_timeoutHandler;
|
ref <vmime::net::timeoutHandler> m_timeoutHandler;
|
||||||
|
|
||||||
char m_buffer[65536];
|
char m_buffer[65536];
|
||||||
SOCKET m_desc;
|
SOCKET m_desc;
|
||||||
|
|
||||||
|
unsigned int m_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,9 +63,12 @@ public:
|
|||||||
|
|
||||||
void send(const string& buffer);
|
void send(const string& buffer);
|
||||||
void sendRaw(const char* buffer, const size_type count);
|
void sendRaw(const char* buffer, const size_type count);
|
||||||
|
size_type sendRawNonBlocking(const char* buffer, const size_type count);
|
||||||
|
|
||||||
size_type getBlockSize() const;
|
size_type getBlockSize() const;
|
||||||
|
|
||||||
|
unsigned int getStatus() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ref <SASLSession> m_session;
|
ref <SASLSession> m_session;
|
||||||
|
Loading…
Reference in New Issue
Block a user