diff options
Diffstat (limited to 'remote-processor')
-rw-r--r-- | remote-processor/Message.cpp | 48 | ||||
-rw-r--r-- | remote-processor/Message.h | 23 | ||||
-rw-r--r-- | remote-processor/RemoteProcessorServer.cpp | 44 | ||||
-rw-r--r-- | remote-processor/Socket.cpp | 44 | ||||
-rw-r--r-- | remote-processor/Socket.h | 56 |
5 files changed, 169 insertions, 46 deletions
diff --git a/remote-processor/Message.cpp b/remote-processor/Message.cpp index 8efec1f..8591847 100644 --- a/remote-processor/Message.cpp +++ b/remote-processor/Message.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2011-2014, Intel Corporation * All rights reserved. * @@ -33,6 +33,7 @@ #include "RemoteProcessorProtocol.h" #include <string.h> #include <assert.h> +#include <errno.h> CMessage::CMessage(uint8_t ucMsgId) : _ucMsgId(ucMsgId), _pucData(NULL), _uiDataSize(0), _uiIndex(0) { @@ -123,7 +124,7 @@ uint32_t CMessage::getRemainingDataSize() const } // Send/Receive -bool CMessage::serialize(CSocket* pSocket, bool bOut) +CMessage::Result CMessage::serialize(CSocket* pSocket, bool bOut, string& strError) { if (bOut) { @@ -141,7 +142,10 @@ bool CMessage::serialize(CSocket* pSocket, bool bOut) if (!pSocket->write(&uiSyncWord, sizeof(uiSyncWord))) { - return false; + if (pSocket->hasPeerDisconnected()) { + return peerDisconnected; + } + return error; } // Size @@ -149,19 +153,22 @@ bool CMessage::serialize(CSocket* pSocket, bool bOut) if (!pSocket->write(&uiSize, sizeof(uiSize))) { - return false; + strError += string("Size write failed: ") + strerror(errno); + return error; } // Msg Id if (!pSocket->write(&_ucMsgId, sizeof(_ucMsgId))) { - return false; + strError += string("Msg write failed: ") + strerror(errno); + return error; } // Data if (!pSocket->write(_pucData, _uiDataSize)) { - return false; + strError = string("Data write failed: ") + strerror(errno); + return error; } // Checksum @@ -169,7 +176,8 @@ bool CMessage::serialize(CSocket* pSocket, bool bOut) if (!pSocket->write(&ucChecksum, sizeof(ucChecksum))) { - return false; + strError = string("Checksum write failed: ") + strerror(errno); + return error; } } else { @@ -178,13 +186,18 @@ bool CMessage::serialize(CSocket* pSocket, bool bOut) if (!pSocket->read(&uiSyncWord, sizeof(uiSyncWord))) { - return false; + strError = string("Sync read failed: ") + strerror(errno); + if (pSocket->hasPeerDisconnected()) { + return peerDisconnected; + } + return error; } // Check Sync word if (uiSyncWord != SYNC_WORD) { - return false; + strError = "Sync word incorrect"; + return error; } // Size @@ -192,13 +205,15 @@ bool CMessage::serialize(CSocket* pSocket, bool bOut) if (!pSocket->read(&uiSize, sizeof(uiSize))) { - return false; + strError = string("Size read failed: ") + strerror(errno); + return error; } // Msg Id if (!pSocket->read(&_ucMsgId, sizeof(_ucMsgId))) { - return false; + strError = string("Msg id read failed: ") + strerror(errno); + return error; } // Data @@ -209,7 +224,8 @@ bool CMessage::serialize(CSocket* pSocket, bool bOut) // Data receive if (!pSocket->read(_pucData, _uiDataSize)) { - return false; + strError = string("Data read failed: ") + strerror(errno); + return error; } // Checksum @@ -217,19 +233,21 @@ bool CMessage::serialize(CSocket* pSocket, bool bOut) if (!pSocket->read(&ucChecksum, sizeof(ucChecksum))) { - return false; + strError = string("Checksum read failed: ") + strerror(errno); + return error; } // Compare if (ucChecksum != computeChecksum()) { - return false; + strError = "Received checksum != computed checksum"; + return error; } // Collect data in derived collectReceivedData(); } - return true; + return success; } // Checksum diff --git a/remote-processor/Message.h b/remote-processor/Message.h index 799a525..feafc83 100644 --- a/remote-processor/Message.h +++ b/remote-processor/Message.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2011-2014, Intel Corporation * All rights reserved. * @@ -43,8 +43,25 @@ public: CMessage(); virtual ~CMessage(); - // Send/Receive - bool serialize(CSocket* pSocket, bool bOut); + enum Result { + success, + peerDisconnected, + error + }; + + /** Write or read the message on pSocket. + * + * @param[in,out] pSocket is the socket on wich IO operation will be made. + * @param[in] bOut if true message should be read, + * if false it should be written. + * @param[out] strError on failure, a string explaining the error, + * on success, undefined. + * + * @return success if a correct message could be recv/send + * peerDisconnected if the peer disconnected before the first socket access. + * error if the message could not be read/write for any other reason + */ + Result serialize(CSocket* pSocket, bool bOut, std::string &strError); protected: // Msg Id diff --git a/remote-processor/RemoteProcessorServer.cpp b/remote-processor/RemoteProcessorServer.cpp index daa4894..8c66109 100644 --- a/remote-processor/RemoteProcessorServer.cpp +++ b/remote-processor/RemoteProcessorServer.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2011-2014, Intel Corporation * All rights reserved. * @@ -29,6 +29,8 @@ */ #include "RemoteProcessorServer.h" #include "ListeningSocket.h" +#include <iostream> +#include <memory> #include <assert.h> #include <poll.h> #include <unistd.h> @@ -146,15 +148,15 @@ void CRemoteProcessorServer::run() // New connection void CRemoteProcessorServer::handleNewConnection() { - CSocket* pClientSocket = _pListeningSocket->accept(); + const auto_ptr<CSocket> clientSocket(_pListeningSocket->accept()); - if (!pClientSocket) { + if (clientSocket.get() == NULL) { return; } // Set timeout - pClientSocket->setTimeout(5000); + clientSocket->setTimeout(5000); // Process all incoming requests from the client while (true) { @@ -163,11 +165,20 @@ void CRemoteProcessorServer::handleNewConnection() // Create command message CRequestMessage requestMessage; + string strError; ///// Receive command - if (!requestMessage.serialize(pClientSocket, false)) { - - // Bail out - break; + CRequestMessage::Result res; + res = requestMessage.serialize(clientSocket.get(), false, strError); + + switch (res) { + case CRequestMessage::error: + cout << "Error while receiving message: " << strError << endl; + // fall through + case CRequestMessage::peerDisconnected: + // Consider peer disconnection as normal, no log + return; // Bail out + case CRequestMessage::success: + break; // No error, continue } // Actually process the request @@ -191,12 +202,17 @@ void CRemoteProcessorServer::handleNewConnection() CAnswerMessage answerMessage(strResult, bSuccess); ///// Send answer - if (!answerMessage.serialize(pClientSocket, true)) { - - // Bail out - break; + res = answerMessage.serialize(clientSocket.get(), true, strError); + + switch (res) { + case CRequestMessage::peerDisconnected: + // Peer should not disconnect while waiting for an answer + // Fall through to log the error and bail out + case CRequestMessage::error: + cout << "Error while receiving message: " << strError << endl; + return; // Bail out + case CRequestMessage::success: + break; // No error, continue } } - // Remove client socket - delete pClientSocket; } diff --git a/remote-processor/Socket.cpp b/remote-processor/Socket.cpp index d79b45a..b36d32f 100644 --- a/remote-processor/Socket.cpp +++ b/remote-processor/Socket.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2011-2014, Intel Corporation * All rights reserved. * @@ -34,6 +34,7 @@ #include <assert.h> #include <netdb.h> #include <strings.h> +#include <errno.h> #include <fcntl.h> #include <netinet/in.h> #include <netinet/tcp.h> @@ -109,12 +110,24 @@ bool CSocket::read(void* pvData, uint32_t uiSize) int32_t iAccessedSize = ::recv(_iSockFd, &pucData[uiOffset], uiSize, MSG_NOSIGNAL); - if (!iAccessedSize || iAccessedSize == -1) { - + switch (iAccessedSize) { + case 0: + // recv return value is 0 when the peer has performed an orderly shutdown. + _disconnected = true; + errno = ECONNRESET; // Warn the client that the client disconnected. return false; + + case -1: + // errno == EINTR => The recv system call was interrupted, try again + if (errno != EINTR) { + return false; + } + break; + + default: + uiSize -= iAccessedSize; + uiOffset += iAccessedSize; } - uiSize -= iAccessedSize; - uiOffset += iAccessedSize; } return true; } @@ -129,12 +142,19 @@ bool CSocket::write(const void* pvData, uint32_t uiSize) int32_t iAccessedSize = ::send(_iSockFd, &pucData[uiOffset], uiSize, MSG_NOSIGNAL); - if (!iAccessedSize || iAccessedSize == -1) { - - return false; + if (iAccessedSize == -1) { + if (errno == ECONNRESET) { + // Peer has disconnected + _disconnected = true; + } + // errno == EINTR => The send system call was interrupted, try again + if (errno != EINTR) { + return false; + } + } else { + uiSize -= iAccessedSize; + uiOffset += iAccessedSize; } - uiSize -= iAccessedSize; - uiOffset += iAccessedSize; } return true; } @@ -144,3 +164,7 @@ int CSocket::getFd() const { return _iSockFd; } + +bool CSocket::hasPeerDisconnected() { + return _disconnected; +} diff --git a/remote-processor/Socket.h b/remote-processor/Socket.h index 9ecc38a..e8d360f 100644 --- a/remote-processor/Socket.h +++ b/remote-processor/Socket.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2011-2014, Intel Corporation * All rights reserved. * @@ -37,6 +37,14 @@ using namespace std; struct sockaddr_in; struct in_addr; +/** Readable and writable socket. + * + * The class does not encapsulate completely it's internal file descriptor as + * it can be retrieve by the getFd method. + * + * This "feature" means that it's state consistency can not + * be enforced by the class but rather by clients. + */ class CSocket { public: @@ -50,16 +58,56 @@ public: // Communication timeout void setTimeout(uint32_t uiMilliseconds); - // Read + /* Read data + * + * On failure errno will be set appropriately (see send). + * If the client disconnects, false will be returned and + * - hasPeerDisconnected will return true + * - errno is set to ECONNRESET. + * @param[in] pvData - on success: will contain the sent data + * - on failure: undefined + * @param[in] uiSize size of the data to receive. + * + * @return true if all data could be read, false otherwise. + */ bool read(void* pvData, uint32_t uiSize); - // Write + + /* Write data + * + * On failure errno will be set (see recv) + * @param[in] pvData data to send. + * @param[in] uiSize is the size of the data to send. + * + * @return true if all data could be read, false otherwise. + */ bool write(const void* pvData, uint32_t uiSize); - // Fd + /** @return the managed file descriptor. + * + * The client can then bind/connect/accept/listen/... the socket. + */ int getFd() const; + + /** @return true if the peer has disconnected. + * + * The internal fd is returned by getFd and clients can use it for + * bind/connect/read/write/... as a result it's state can not be tracked. + * + * Thus hasPeerDisconnected returns true only if the disconnection + * was notified during a call to CSocket::write or CSocket::read. + */ + bool hasPeerDisconnected(); + protected: // Socket address init void initSockAddrIn(struct sockaddr_in* pSockAddrIn, uint32_t uiInAddr, uint16_t uiPort) const; private: int _iSockFd; + /** If the peer disconnected. + * + * This is not the state of _iSockFd (connected/disconnected) + * + * See hasPeerDisconnected for more details. + */ + bool _disconnected; }; |