[Libreoffice-commits] online.git: Branch 'private/Ashod/nonblocking' - net/socket.hpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Sat Feb 18 00:45:13 UTC 2017
net/socket.hpp | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 141 insertions(+), 13 deletions(-)
New commits:
commit a3b6ef4a76aeb5daf4cbca3f25ca0983020bdca6
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Fri Feb 17 19:05:53 2017 -0500
nb: basic SSL socket implementation
Change-Id: Iaa2da47df17f14dfded44a8cf805020e8ef6b1ff
Reviewed-on: https://gerrit.libreoffice.org/34395
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/net/socket.hpp b/net/socket.hpp
index 69d2710..95d4991 100644
--- a/net/socket.hpp
+++ b/net/socket.hpp
@@ -339,11 +339,6 @@ protected:
class StreamSocket : public BufferingSocket
{
public:
- StreamSocket() :
- BufferingSocket()
- {
- }
-
bool readIncomingData() override
{
ssize_t len;
@@ -391,26 +386,74 @@ protected:
class SslStreamSocket : public BufferingSocket
{
public:
- SslStreamSocket() :
- BufferingSocket()
+ bool readIncomingData() override
{
+ ssize_t len;
+ char buf[4096];
+ do
+ {
+ len = SSL_read(_ssl, buf, sizeof(buf));
+ }
+ while (len < 0 && errno == EINTR);
+
+ len = handleSslState(len);
+
+ if (len > 0)
+ {
+ // We have more data, let the application consume it, if possible.
+ assert (len < ssize_t(sizeof(buf)));
+ _inBuffer.insert(_inBuffer.end(), &buf[0], &buf[len]);
+ handleIncomingMessage();
+ }
+ // else poll will handle errors.
+
+ return len != 0; // zero is eof / clean socket close.
}
- bool readIncomingData() override
+ void writeOutgoingData() override
{
- //TODO:
- return true;
+ // Should never call SSL_write with 0 length data.
+ assert (_outBuffer.size() > 0);
+ ssize_t len;
+ do
+ {
+ len = SSL_write(_ssl, &_outBuffer[0], _outBuffer.size());
+ }
+ while (len < 0 && errno == EINTR);
+
+ len = handleSslState(len);
+
+ if (len > 0)
+ {
+ // We've sent some data, remove from the buffer.
+ _outBuffer.erase(_outBuffer.begin(),
+ _outBuffer.begin() + len);
+ }
+ // else poll will handle errors
}
- void writeOutgoingData() override
+ int getPollEvents() override
{
- //TODO;
+ if (_sslWantsTo == SslWantsTo::Read)
+ {
+ // Must read next before attempting to write.
+ return POLLIN;
+ }
+ else if (_sslWantsTo == SslWantsTo::Write)
+ {
+ // Must write next before attempting to read.
+ return POLLOUT;
+ }
+
+ // Do whatever makes sense based on buffer state.
+ return (_outBuffer.empty() ? POLLIN : (POLLIN | POLLOUT));
}
protected:
SslStreamSocket(const int fd) :
BufferingSocket(fd),
- _ssl(nullptr)
+ _ssl(nullptr),
+ _sslWantsTo(SslWantsTo::ReadOrWrite)
{
BIO* bio = BIO_new(BIO_s_socket());
if (bio == nullptr)
@@ -437,7 +480,92 @@ protected:
template<class T> friend class ServerSocket;
private:
+
+ /// The possible next I/O operation that SSL want to do.
+ enum class SslWantsTo
+ {
+ ReadOrWrite,
+ Read,
+ Write
+ };
+
+ /// Handles the state of SSL after read or write.
+ int handleSslState(const int rc)
+ {
+ if (rc > 0)
+ {
+ // Success: Reset so we can do either.
+ _sslWantsTo = SslWantsTo::ReadOrWrite;
+ return rc;
+ }
+
+ // Last operation failed. Find out if SSL was trying
+ // to do something different that failed, or not.
+ const int sslError = SSL_get_error(_ssl, rc);
+ switch (sslError)
+ {
+ case SSL_ERROR_ZERO_RETURN:
+ // Shutdown complete, we're disconnected.
+ return 0;
+
+ case SSL_ERROR_WANT_READ:
+ _sslWantsTo = SslWantsTo::Read;
+ return rc;
+
+ case SSL_ERROR_WANT_WRITE:
+ _sslWantsTo = SslWantsTo::Write;
+ return rc;
+
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ // Unexpected.
+ return rc;
+
+ case SSL_ERROR_SYSCALL:
+ if (errno != 0)
+ {
+ // Posix API error, let the caller handle.
+ return rc;
+ }
+
+ // fallthrough
+ default:
+ {
+ // The error is comming from BIO. Find out what happened.
+ const long lastError = ERR_get_error();
+ if (lastError == 0)
+ {
+ if (rc == 0)
+ {
+ // Socket closed.
+ return 0;
+ }
+ else if (rc == -1)
+ {
+ throw std::runtime_error("SSL Socket closed unexpectedly.");
+ }
+ else
+ {
+ throw std::runtime_error("SSL BIO reported error [" + std::to_string(rc) + "].");
+ }
+ }
+ else
+ {
+ char buf[512];
+ ERR_error_string_n(lastError, buf, sizeof(buf));
+ throw std::runtime_error(buf);
+ }
+ }
+ break;
+ }
+
+ return rc;
+ }
+
+private:
SSL* _ssl;
+ SslWantsTo _sslWantsTo;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
More information about the Libreoffice-commits
mailing list