Author: axeld Date: 2011-11-02 23:56:50 +0100 (Wed, 02 Nov 2011) New Revision: 43141 Changeset: https://dev.haiku-os.org/changeset/43141 Modified: haiku/trunk/headers/private/mail/ServerConnection.h haiku/trunk/src/kits/mail/Jamfile haiku/trunk/src/kits/mail/ServerConnection.cpp Log: * 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. Modified: haiku/trunk/headers/private/mail/ServerConnection.h =================================================================== --- haiku/trunk/headers/private/mail/ServerConnection.h 2011-11-02 22:56:20 UTC (rev 43140) +++ haiku/trunk/headers/private/mail/ServerConnection.h 2011-11-02 22:56:50 UTC (rev 43141) @@ -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,20 +11,12 @@ #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; +class AbstractConnection; - virtual int32 Read(char* buffer, uint32 nBytes) = 0; - virtual int32 Write(const char* buffer, uint32 nBytes) = 0; -}; - class ServerConnection { public: ServerConnection(); @@ -39,11 +31,18 @@ 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 Modified: haiku/trunk/src/kits/mail/Jamfile =================================================================== --- haiku/trunk/src/kits/mail/Jamfile 2011-11-02 22:56:20 UTC (rev 43140) +++ haiku/trunk/src/kits/mail/Jamfile 2011-11-02 22:56:50 UTC (rev 43141) @@ -53,9 +53,7 @@ SharedLibrary libmail.so : $(sources) : - be - libtextencoding.so - tracker + be libbnetapi.so libtextencoding.so tracker $(TARGET_LIBSTDC++) $(TARGET_NETWORK_LIBS) $(TARGET_SELECT_UNAME_ETC_LIB) Modified: haiku/trunk/src/kits/mail/ServerConnection.cpp =================================================================== --- haiku/trunk/src/kits/mail/ServerConnection.cpp 2011-11-02 22:56:20 UTC (rev 43140) +++ haiku/trunk/src/kits/mail/ServerConnection.cpp 2011-11-02 22:56:50 UTC (rev 43141) @@ -1,31 +1,52 @@ +/* + * Copyright 2010-2011, Haiku, Inc. All rights reserved. + * Copyright 2010, Clemens Zeidler <haiku@xxxxxxxxxxxxxxxxxx> + * Distributed under the terms of the MIT License. + */ + + #include "ServerConnection.h" -#include <arpa/inet.h> -#include <netdb.h> +#include <errno.h> +#include <sys/poll.h> #include <unistd.h> #ifdef USE_SSL -#include <openssl/ssl.h> -#include <openssl/rand.h> -#else -#include <string.h> -#include <sys/time.h> +# include <openssl/ssl.h> +# include <openssl/rand.h> #endif #include <Autolock.h> #include <Locker.h> +#include <NetworkAddress.h> #define DEBUG_SERVER_CONNECTION - #ifdef DEBUG_SERVER_CONNECTION -#include <stdio.h> -#define TRACE(x...) printf(x) +# include <stdio.h> +# 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 @@ 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 @@ #ifdef USE_SSL + + class InitSSL { public: InitSSL() @@ -62,8 +85,7 @@ }; - status_t - InitCheck() + status_t InitCheck() { return fInit ? B_OK : B_ERROR; } @@ -73,9 +95,6 @@ }; -static InitSSL gInitSSL; - - class SSLConnection : public SocketConnection { public: SSLConnection(); @@ -85,34 +104,40 @@ 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 @@ } -int32 +ssize_t ServerConnection::Read(char* buffer, uint32 nBytes) { if (fConnection == NULL) @@ -167,7 +192,7 @@ } -int32 +ssize_t ServerConnection::Write(const char* buffer, uint32 nBytes) { if (fConnection == NULL) @@ -176,11 +201,13 @@ } +// #pragma mark - + + SocketConnection::SocketConnection() : fSocket(-1) { - } @@ -191,29 +218,20 @@ 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 @@ 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 @@ 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