From 214853702f03e3cb22f6d051478a2609b06082be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 2 Nov 2011 22:56:50 +0000 Subject: [PATCH] * Put ServerConnection into the BPrivate namespace as it should have been. * Fixed completely broken error reporting; Write()/Read() will now return the proper error code (and ssize_t instead of int32). * Reimplemented WaitForData() using poll() which is more efficient. * Now uses BNetworkAddress to resolve the server address which also should now work with IPv6. * Removed some unused headers. * Minor coding style cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@43141 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/mail/ServerConnection.h | 25 ++- src/kits/mail/Jamfile | 4 +- src/kits/mail/ServerConnection.cpp | 198 +++++++++++++++--------- 3 files changed, 134 insertions(+), 93 deletions(-) diff --git a/headers/private/mail/ServerConnection.h b/headers/private/mail/ServerConnection.h index 5d812852c0..041f1b6223 100644 --- a/headers/private/mail/ServerConnection.h +++ b/headers/private/mail/ServerConnection.h @@ -1,5 +1,5 @@ /* - * Copyright 2010, Haiku Inc. All Rights Reserved. + * Copyright 2010-2011, Haiku Inc. All Rights Reserved. * Copyright 2010 Clemens Zeidler. All rights reserved. * * Distributed under the terms of the MIT License. @@ -11,18 +11,10 @@ #include "SupportDefs.h" -class AbstractConnection { -public: - virtual ~AbstractConnection(); +namespace BPrivate { - virtual status_t Connect(const char* server, uint32 port) = 0; - virtual status_t Disconnect() = 0; - virtual status_t WaitForData(bigtime_t timeout) = 0; - - virtual int32 Read(char* buffer, uint32 nBytes) = 0; - virtual int32 Write(const char* buffer, uint32 nBytes) = 0; -}; +class AbstractConnection; class ServerConnection { @@ -39,11 +31,18 @@ public: status_t WaitForData(bigtime_t timeout); - int32 Read(char* buffer, uint32 nBytes); - int32 Write(const char* buffer, uint32 nBytes); + ssize_t Read(char* buffer, uint32 length); + ssize_t Write(const char* buffer, uint32 length); private: AbstractConnection* fConnection; }; + +} // namespace BPrivate + + +using BPrivate::ServerConnection; + + #endif // SERVER_CONNECTION_H diff --git a/src/kits/mail/Jamfile b/src/kits/mail/Jamfile index bda4a2655a..442c18bd04 100644 --- a/src/kits/mail/Jamfile +++ b/src/kits/mail/Jamfile @@ -53,9 +53,7 @@ AddResources libmail.so : libmail.rdef ; SharedLibrary libmail.so : $(sources) : - be - libtextencoding.so - tracker + be libbnetapi.so libtextencoding.so tracker $(TARGET_LIBSTDC++) $(TARGET_NETWORK_LIBS) $(TARGET_SELECT_UNAME_ETC_LIB) diff --git a/src/kits/mail/ServerConnection.cpp b/src/kits/mail/ServerConnection.cpp index fefc317cf4..f7d34de3f2 100644 --- a/src/kits/mail/ServerConnection.cpp +++ b/src/kits/mail/ServerConnection.cpp @@ -1,31 +1,52 @@ +/* + * Copyright 2010-2011, Haiku, Inc. All rights reserved. + * Copyright 2010, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ + + #include "ServerConnection.h" -#include -#include +#include +#include #include #ifdef USE_SSL -#include -#include -#else -#include -#include +# include +# include #endif #include #include +#include #define DEBUG_SERVER_CONNECTION - #ifdef DEBUG_SERVER_CONNECTION -#include -#define TRACE(x...) printf(x) +# include +# define TRACE(x...) printf(x) #else -#define TRACE(x...) /* nothing */ +# define TRACE(x...) ; #endif +namespace BPrivate { + + +class AbstractConnection { +public: + virtual ~AbstractConnection(); + + virtual status_t Connect(const char* server, uint32 port) = 0; + virtual status_t Disconnect() = 0; + + virtual status_t WaitForData(bigtime_t timeout) = 0; + + virtual ssize_t Read(char* buffer, uint32 length) = 0; + virtual ssize_t Write(const char* buffer, uint32 length) = 0; +}; + + class SocketConnection : public AbstractConnection { public: SocketConnection(); @@ -35,8 +56,8 @@ public: status_t WaitForData(bigtime_t timeout); - int32 Read(char* buffer, uint32 nBytes); - int32 Write(const char* buffer, uint32 nBytes); + ssize_t Read(char* buffer, uint32 length); + ssize_t Write(const char* buffer, uint32 length); protected: int fSocket; @@ -44,6 +65,8 @@ protected: #ifdef USE_SSL + + class InitSSL { public: InitSSL() @@ -62,8 +85,7 @@ public: }; - status_t - InitCheck() + status_t InitCheck() { return fInit ? B_OK : B_ERROR; } @@ -73,9 +95,6 @@ private: }; -static InitSSL gInitSSL; - - class SSLConnection : public SocketConnection { public: SSLConnection(); @@ -85,34 +104,40 @@ public: status_t WaitForData(bigtime_t timeout); - int32 Read(char* buffer, uint32 nBytes); - int32 Write(const char* buffer, uint32 nBytes); + ssize_t Read(char* buffer, uint32 length); + ssize_t Write(const char* buffer, uint32 length); private: SSL_CTX* fCTX; SSL* fSSL; BIO* fBIO; }; -#endif + + +static InitSSL gInitSSL; + + +#endif // USE_SSL AbstractConnection::~AbstractConnection() { - } +// #pragma mark - + + ServerConnection::ServerConnection() : fConnection(NULL) { - } ServerConnection::~ServerConnection() { - if (fConnection) + if (fConnection != NULL) fConnection->Disconnect(); delete fConnection; } @@ -158,7 +183,7 @@ ServerConnection::WaitForData(bigtime_t timeout) } -int32 +ssize_t ServerConnection::Read(char* buffer, uint32 nBytes) { if (fConnection == NULL) @@ -167,7 +192,7 @@ ServerConnection::Read(char* buffer, uint32 nBytes) } -int32 +ssize_t ServerConnection::Write(const char* buffer, uint32 nBytes) { if (fConnection == NULL) @@ -176,11 +201,13 @@ ServerConnection::Write(const char* buffer, uint32 nBytes) } +// #pragma mark - + + SocketConnection::SocketConnection() : fSocket(-1) { - } @@ -191,29 +218,20 @@ SocketConnection::Connect(const char* server, uint32 port) Disconnect(); TRACE("SocketConnection to server %s:%i\n", server, (int)port); - uint32 hostIP = inet_addr(server); - // first see if we can parse it as a numeric address - if (hostIP == 0 || hostIP == (uint32)-1) { - struct hostent *he = gethostbyname(server); - hostIP = he ? *((uint32*)he->h_addr) : 0; - } - if (hostIP == 0) - return B_ERROR; - fSocket = socket(AF_INET, SOCK_STREAM, 0); + BNetworkAddress address; + status_t status = address.SetTo(server, port); + if (status != B_OK) + return status; + + fSocket = socket(address.Family(), SOCK_STREAM, 0); if (fSocket < 0) - return B_ERROR; + return errno; - sockaddr_in saAddr; - memset(&saAddr, 0, sizeof(saAddr)); - saAddr.sin_family = AF_INET; - saAddr.sin_port = htons(port); - saAddr.sin_addr.s_addr = hostIP; - int result = connect(fSocket, (struct sockaddr*)&saAddr, - sizeof(saAddr)); + int result = connect(fSocket, address, address.Length()); if (result < 0) { close(fSocket); - return B_ERROR; + return errno; } TRACE("SocketConnection: connected\n"); @@ -234,47 +252,58 @@ SocketConnection::Disconnect() status_t SocketConnection::WaitForData(bigtime_t timeout) { - timeval tv; - fd_set fds; - tv.tv_sec = long(timeout / 1e6); - tv.tv_usec = long(timeout - (tv.tv_sec * 1e6)); + struct pollfd entry; + entry.fd = fSocket; + entry.events = POLLIN; - /* Initialize (clear) the socket mask. */ - FD_ZERO(&fds); - /* Set the socket in the mask. */ - FD_SET(fSocket, &fds); + int timeoutMillis = -1; + if (timeout > 0) + timeoutMillis = timeout / 1000; - int result = select(fSocket + 1, &fds, NULL, NULL, &tv); + int result = poll(&entry, 1, timeoutMillis); if (result == 0) return B_TIMED_OUT; if (result < 0) - return B_ERROR; + return errno; + return B_OK; } -int32 -SocketConnection::Read(char* buffer, uint32 nBytes) +ssize_t +SocketConnection::Read(char* buffer, uint32 length) { - return recv(fSocket, buffer, nBytes, 0); + ssize_t bytesReceived = recv(fSocket, buffer, length, 0); + if (bytesReceived < 0) + return errno; + + return bytesReceived; } -int32 -SocketConnection::Write(const char* buffer, uint32 nBytes) +ssize_t +SocketConnection::Write(const char* buffer, uint32 length) { - return send(fSocket, buffer, nBytes, 0); + ssize_t bytesWritten = send(fSocket, buffer, length, 0); + if (bytesWritten < 0) + return errno; + + return bytesWritten; } +// #pragma mark - + + #ifdef USE_SSL + + SSLConnection::SSLConnection() : fCTX(NULL), fSSL(NULL), fBIO(NULL) { - } @@ -329,31 +358,46 @@ SSLConnection::Disconnect() status_t SSLConnection::WaitForData(bigtime_t timeout) { - if (!fSSL) - return B_ERROR; - if (SSL_pending(fSSL) > 0) { + if (fSSL == NULL) + return B_NO_INIT; + if (SSL_pending(fSSL) > 0) return B_OK; - } + return SocketConnection::WaitForData(timeout); } -int32 -SSLConnection::Read(char* buffer, uint32 nBytes) +ssize_t +SSLConnection::Read(char* buffer, uint32 length) { - if (!fSSL) - return B_ERROR; - return SSL_read(fSSL, buffer, nBytes); + if (fSSL == NULL) + return B_NO_INIT; + + int bytesRead = SSL_read(fSSL, buffer, length); + if (bytesRead > 0) + return bytesRead; + + // TODO: translate SSL error codes! + return B_ERROR; } -int32 -SSLConnection::Write(const char* buffer, uint32 nBytes) +ssize_t +SSLConnection::Write(const char* buffer, uint32 length) { - if (!fSSL) - return B_ERROR; - return SSL_write(fSSL, buffer, nBytes); + if (fSSL == NULL) + return B_NO_INIT; + + int bytesWritten = SSL_write(fSSL, buffer, length); + if (bytesWritten > 0) + return bytesWritten; + + // TODO: translate SSL error codes! + return B_ERROR; } -#endif +#endif // USE_SSL + + +} // namespace BPrivate