├── InterruptibleBlockingSocketAcceptors ├── InterruptibleBlockingTCPAcceptor.h └── InterruptibleBlockingTCPAcceptor.cpp └── InterruptibleBlockingSockets ├── InterruptibleBlockingUDPSocket.h ├── InterruptibleBlockingTCPSocket.h ├── InterruptibleBlockingUDPSocket.cpp └── InterruptibleBlockingTCPSocket.cpp /InterruptibleBlockingSocketAcceptors/InterruptibleBlockingTCPAcceptor.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTIBLE_BLOCKING_TCP_ACCEPTOR_H 2 | #define INTERRUPTIBLE_BLOCKING_TCP_ACCEPTOR_H 3 | 4 | //System includes 5 | #ifdef _WIN32 6 | #include 7 | 8 | #ifndef int64_t 9 | typedef __int64 int64_t; 10 | #endif 11 | 12 | #ifndef uint64_t 13 | typedef unsigned __int64 uint64_t; 14 | #endif 15 | 16 | #else 17 | #include 18 | #endif 19 | 20 | //Library includes: 21 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 22 | #include 23 | #include 24 | #include 25 | #include 26 | #endif 27 | 28 | //Local includes 29 | #include "../InterruptibleBlockingSockets/InterruptibleBlockingTCPSocket.h" 30 | 31 | class cInterruptibleBlockingTCPAcceptor 32 | { 33 | private: 34 | //The serial port and io service for the port 35 | boost::asio::io_service m_oIOService; 36 | boost::asio::ip::tcp::acceptor m_oAcceptor; 37 | 38 | //Timer for deterining timeouts 39 | boost::asio::deadline_timer m_oTimer; 40 | 41 | boost::asio::ip::tcp::resolver m_oResolver; 42 | 43 | //Flag for determining read errors 44 | bool m_bError; 45 | 46 | //Info about about last transaction 47 | uint32_t m_u32NBytesLastTransferred; 48 | boost::system::error_code m_oLastError; 49 | 50 | //Optional label for this socket. May be useful for debugging. 51 | std::string m_strName; 52 | 53 | //Internal callback functions for serial port 54 | void callback_complete(const boost::system::error_code& oError); 55 | void callback_timeOut(const boost::system::error_code& oError); 56 | 57 | public: 58 | cInterruptibleBlockingTCPAcceptor(const std::string &strName = ""); 59 | cInterruptibleBlockingTCPAcceptor(const std::string &strLocalInterface, uint16_t u16LocalPort, const std::string &strName = ""); 60 | 61 | void openAndListen(const std::string &strLocalInterface, uint16_t u16Port); 62 | void close(); 63 | 64 | bool isOpen(); 65 | 66 | bool accept(cInterruptibleBlockingTCPSocket &oSocket, std::string &strPeerAddress, uint32_t u32Timeout_ms = 0); 67 | bool accept(boost::shared_ptr pSocket, std::string &strPeerAddress, uint32_t u32Timeout_ms = 0); 68 | 69 | void cancelCurrrentOperations(); 70 | 71 | boost::asio::ip::tcp::endpoint createEndpoint(std::string strHostAddress, uint16_t u16Port); 72 | std::string getEndpointHostAddress(boost::asio::ip::tcp::endpoint oEndPoint); 73 | uint16_t getEndpointPort(boost::asio::ip::tcp::endpoint oEndPoint); 74 | 75 | //Some accessors 76 | boost::asio::ip::tcp::endpoint getLocalEndpoint(); 77 | std::string getLocalInterface(); 78 | uint16_t getLocalPort(); 79 | 80 | std::string getName(); 81 | 82 | boost::system::error_code getLastError(); 83 | }; 84 | 85 | #endif // INTERRUPTIBLE_BLOCKING_TCP_SOCKET_H 86 | -------------------------------------------------------------------------------- /InterruptibleBlockingSockets/InterruptibleBlockingUDPSocket.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTIBLE_BLOCKING_UDP_SOCKET_H 2 | #define INTERRUPTIBLE_BLOCKING_UDP_SOCKET_H 3 | 4 | //System includes 5 | #ifdef _WIN32 6 | #include 7 | 8 | #ifndef int64_t 9 | typedef __int64 int64_t; 10 | #endif 11 | 12 | #ifndef uint64_t 13 | typedef unsigned __int64 uint64_t; 14 | #endif 15 | 16 | #else 17 | #include 18 | #endif 19 | 20 | //Library includes: 21 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 22 | #include 23 | #include 24 | #include 25 | #endif 26 | 27 | //Local includes 28 | 29 | class cInterruptibleBlockingUDPSocket 30 | { 31 | 32 | public: 33 | cInterruptibleBlockingUDPSocket(const std::string &strName = ""); 34 | cInterruptibleBlockingUDPSocket(const std::string &strLocalInterface, uint16_t u16LocalPort, const std::string &strPeerAddress = "", uint16_t u16PeerPort = 60001, const std::string &strName = ""); 35 | 36 | ~cInterruptibleBlockingUDPSocket(); 37 | 38 | bool openAndBind(const std::string &strLocalAddress, uint16_t u16LocalPort); 39 | bool openBindAndConnect(const std::string &strLocalAddress, uint16_t u16LocalPort, const std::string &strPeerAddress, uint16_t u16PeerPort); 40 | void close(); 41 | 42 | bool send(const char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms = 0); 43 | bool sendTo(const char *cpBuffer, uint32_t u32NBytes, const std::string &strPeerAddress, uint16_t u16PeerPort, uint32_t u32Timeout_ms = 0); 44 | bool sendTo(const char *cpBuffer, uint32_t u32NBytes, const boost::asio::ip::udp::endpoint &oPeerEndpoint, uint32_t u32Timeout_ms = 0); 45 | 46 | bool receive(char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms = 0); 47 | bool receiveFrom(char *cpBuffer, uint32_t u32NBytes, std::string &strPeerAddress, uint16_t &u16PeerPort, uint32_t u32Timeout_ms = 0); 48 | bool receiveFrom(char *cpBuffer, uint32_t u32NBytes, boost::asio::ip::udp::endpoint &oPeerEndpoint, uint32_t u32Timeout_ms = 0); 49 | 50 | void cancelCurrrentOperations(); 51 | 52 | //Some utility functions 53 | boost::asio::ip::udp::endpoint createEndpoint(std::string strHostAddress, uint16_t u16Port); 54 | std::string getEndpointHostAddress(boost::asio::ip::udp::endpoint oEndpoint) const; 55 | uint16_t getEndpointPort(boost::asio::ip::udp::endpoint oEndpoint) const; 56 | 57 | //Some accessors 58 | boost::asio::ip::udp::endpoint getLocalEndpoint() const; 59 | std::string getLocalInterface() const; 60 | uint16_t getLocalPort() const ; 61 | 62 | boost::asio::ip::udp::endpoint getPeerEndpoint() const; 63 | std::string getPeerAddress() const; 64 | uint16_t getPeerPort() const; 65 | 66 | std::string getName() const; 67 | 68 | uint32_t getNBytesLastTransferred() const; 69 | boost::system::error_code getLastError() const; 70 | 71 | //Pass through some boost socket functionality: 72 | uint32_t getBytesAvailable() const; 73 | boost::asio::ip::udp::socket* getBoostSocketPointer(); 74 | 75 | private: 76 | //The serial port and io service for the port 77 | boost::asio::io_service m_oIOService; 78 | boost::asio::ip::udp::socket m_oSocket; 79 | boost::asio::ip::udp::endpoint m_oLocalEndpoint; 80 | boost::asio::ip::udp::endpoint m_oPeerEndpoint; 81 | 82 | //Timer for deterining timeouts 83 | boost::asio::deadline_timer m_oTimer; 84 | 85 | boost::asio::ip::udp::resolver m_oResolver; 86 | 87 | //Flag for determining read errors 88 | bool m_bError; 89 | 90 | //Info about about last transaction 91 | uint32_t m_u32NBytesLastTransferred; 92 | boost::system::error_code m_oLastError; 93 | 94 | //Optional label for this socket. May be useful for debugging. 95 | std::string m_strName; 96 | 97 | //Internal callback functions for serial port 98 | void callback_complete(const boost::system::error_code& oError, uint32_t u32NBytesTransferred); 99 | void callback_timeOut(const boost::system::error_code& oError); 100 | 101 | }; 102 | 103 | #endif // INTERRUPTIBLE_BLOCKING_UDP_SOCKET_H 104 | -------------------------------------------------------------------------------- /InterruptibleBlockingSocketAcceptors/InterruptibleBlockingTCPAcceptor.cpp: -------------------------------------------------------------------------------- 1 | 2 | //System includes 3 | #include 4 | 5 | //Library includes 6 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 7 | #include 8 | #include 9 | #endif 10 | 11 | //Local includes 12 | #include "InterruptibleBlockingTCPAcceptor.h" 13 | 14 | using namespace std; 15 | 16 | cInterruptibleBlockingTCPAcceptor::cInterruptibleBlockingTCPAcceptor(const string &strName) : 17 | m_oAcceptor(m_oIOService), 18 | m_oTimer(m_oIOService), 19 | m_oResolver(m_oIOService), 20 | m_bError(true), 21 | m_strName(strName) 22 | { 23 | 24 | } 25 | 26 | cInterruptibleBlockingTCPAcceptor::cInterruptibleBlockingTCPAcceptor(const string &strLocalInterface, uint16_t u16Port, const string &strName) : 27 | m_oAcceptor(m_oIOService), 28 | m_oTimer(m_oIOService), 29 | m_oResolver(m_oIOService), 30 | m_bError(true), 31 | m_strName(strName) 32 | { 33 | openAndListen(strLocalInterface, u16Port); 34 | } 35 | 36 | void cInterruptibleBlockingTCPAcceptor::openAndListen(const string &strLocalInterface, uint16_t u16Port) 37 | { 38 | m_oAcceptor.open(boost::asio::ip::tcp::v4()); //Use only IPv4 39 | m_oAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); //Set Listening socket to reuse address. 40 | m_oAcceptor.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(strLocalInterface), u16Port)); 41 | m_oAcceptor.listen(); 42 | } 43 | 44 | void cInterruptibleBlockingTCPAcceptor::close() 45 | { 46 | //If the socket is open close it 47 | if(m_oAcceptor.is_open()) 48 | { 49 | cout << "cInterruptibleBlockingTCPAcceptor::close(): Closing TCP Acceptor." << endl; 50 | m_oAcceptor.cancel(); 51 | m_oAcceptor.close(); 52 | } 53 | } 54 | 55 | bool cInterruptibleBlockingTCPAcceptor::isOpen() 56 | { 57 | return m_oAcceptor.is_open(); 58 | } 59 | 60 | 61 | bool cInterruptibleBlockingTCPAcceptor::accept(cInterruptibleBlockingTCPSocket &oSocket, string &strPeerAddress, uint32_t u32Timeout_ms) 62 | { 63 | //Necessary after a timeout: 64 | m_oAcceptor.get_io_service().reset(); 65 | boost::asio::ip::tcp::endpoint oPeerEndpoint; 66 | 67 | //Asynchronously accept socket connections 68 | m_oAcceptor.async_accept(*oSocket.getBoostSocketPointer(), oPeerEndpoint, 69 | boost::bind(&cInterruptibleBlockingTCPAcceptor::callback_complete, 70 | this, 71 | boost::asio::placeholders::error ) ); 72 | 73 | // Setup a deadline time to implement our timeout. 74 | if(u32Timeout_ms) 75 | { 76 | m_oTimer.expires_from_now( boost::posix_time::milliseconds(u32Timeout_ms) ); 77 | 78 | m_oTimer.async_wait( boost::bind(&cInterruptibleBlockingTCPAcceptor::callback_timeOut, 79 | this, boost::asio::placeholders::error) ); 80 | } 81 | 82 | // This will block until a new connection has been accepted 83 | // or until the it is cancelled. 84 | m_oAcceptor.get_io_service().run(); 85 | 86 | if(m_bError) 87 | strPeerAddress = string(""); 88 | else 89 | strPeerAddress = getEndpointHostAddress(oPeerEndpoint); 90 | 91 | return !m_bError; 92 | } 93 | 94 | 95 | bool cInterruptibleBlockingTCPAcceptor::accept(boost::shared_ptr pSocket, string &strPeerAddress, uint32_t u32Timeout_ms) 96 | { 97 | return accept(*pSocket.get(), strPeerAddress, u32Timeout_ms); 98 | } 99 | 100 | void cInterruptibleBlockingTCPAcceptor::callback_complete(const boost::system::error_code& oError) 101 | { 102 | m_bError = true; 103 | if (boost::system::errc::success == oError) 104 | { 105 | m_bError = false; 106 | } 107 | //RE: m_bError = oError; 108 | m_oTimer.cancel(); 109 | 110 | m_oLastError = oError; 111 | } 112 | 113 | void cInterruptibleBlockingTCPAcceptor::callback_timeOut(const boost::system::error_code& oError) 114 | { 115 | if (oError) 116 | { 117 | m_oLastError = oError; 118 | return; 119 | } 120 | 121 | cout << "!!! Time out reached on socket acceptor \"" << m_strName << "\" (" << this << ")" << endl; 122 | 123 | m_oAcceptor.cancel(); 124 | } 125 | 126 | void cInterruptibleBlockingTCPAcceptor::cancelCurrrentOperations() 127 | { 128 | m_oTimer.cancel(); 129 | m_oAcceptor.cancel(); 130 | } 131 | 132 | boost::asio::ip::tcp::endpoint cInterruptibleBlockingTCPAcceptor::createEndpoint(string strHostAddress, uint16_t u16Port) 133 | { 134 | stringstream oSS; 135 | oSS << u16Port; 136 | 137 | return *m_oResolver.resolve(boost::asio::ip::tcp::resolver::query(boost::asio::ip::tcp::v4(), strHostAddress, oSS.str())); 138 | } 139 | 140 | string cInterruptibleBlockingTCPAcceptor::getEndpointHostAddress(boost::asio::ip::tcp::endpoint oEndPoint) 141 | { 142 | return oEndPoint.address().to_string(); 143 | } 144 | 145 | uint16_t cInterruptibleBlockingTCPAcceptor::getEndpointPort(boost::asio::ip::tcp::endpoint oEndPoint) 146 | { 147 | return oEndPoint.port(); 148 | } 149 | 150 | boost::asio::ip::tcp::endpoint cInterruptibleBlockingTCPAcceptor::getLocalEndpoint() 151 | { 152 | return m_oAcceptor.local_endpoint(); 153 | } 154 | 155 | string cInterruptibleBlockingTCPAcceptor::getLocalInterface() 156 | { 157 | return getEndpointHostAddress(m_oAcceptor.local_endpoint()); 158 | } 159 | 160 | uint16_t cInterruptibleBlockingTCPAcceptor::getLocalPort() 161 | { 162 | return getEndpointPort(m_oAcceptor.local_endpoint()); 163 | } 164 | 165 | string cInterruptibleBlockingTCPAcceptor::getName() 166 | { 167 | return m_strName; 168 | } 169 | 170 | boost::system::error_code cInterruptibleBlockingTCPAcceptor::getLastError() 171 | { 172 | return m_oLastError; 173 | } 174 | 175 | -------------------------------------------------------------------------------- /InterruptibleBlockingSockets/InterruptibleBlockingTCPSocket.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERRUPTIBLE_BLOCKING_TCP_SOCKET_H 2 | #define INTERRUPTIBLE_BLOCKING_TCP_SOCKET_H 3 | 4 | //System includes 5 | #ifdef _WIN32 6 | #include 7 | 8 | #ifndef int64_t 9 | typedef __int64 int64_t; 10 | #endif 11 | 12 | #ifndef uint64_t 13 | typedef unsigned __int64 uint64_t; 14 | #endif 15 | 16 | #else 17 | #include 18 | #endif 19 | 20 | #include 21 | 22 | //Library includes: 23 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 24 | #include 25 | #include 26 | #include 27 | #include 28 | #endif 29 | 30 | //Local includes 31 | 32 | class cInterruptibleBlockingTCPSocket 33 | { 34 | 35 | public: 36 | cInterruptibleBlockingTCPSocket(const std::string &strName = ""); 37 | cInterruptibleBlockingTCPSocket(const std::string &strPeerAddress, uint16_t u16PeerPort, const std::string &strName = ""); 38 | 39 | ~cInterruptibleBlockingTCPSocket(); 40 | 41 | bool openAndConnect(std::string strPeerAddress, uint16_t u16PeerPort, uint32_t u32Timeout_ms = 0); 42 | void close(); 43 | 44 | //Do not guarantee all bytes sent 45 | bool send(const char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms = 0); 46 | bool receive(char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms = 0); 47 | 48 | //Guarantee all bytes sent 49 | bool write(const char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms = 0); 50 | bool write(const std::string &strData, uint32_t u32Timeout_ms = 0); //Convenience function for sending of text 51 | bool read(char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms = 0); 52 | bool readUntil(std::string &strBuffer, const std::string &strDelimiter, uint32_t u32Timeout_ms = 0); //Convenience function, read until a delimeter is found. 53 | 54 | void cancelCurrrentOperations(); 55 | 56 | //Some utility functions 57 | boost::asio::ip::tcp::endpoint createEndpoint(std::string strHostAddress, uint16_t u16Port); 58 | std::string getEndpointHostAddress(boost::asio::ip::tcp::endpoint oEndPoint) const; 59 | uint16_t getEndpointPort(boost::asio::ip::tcp::endpoint oEndPoint) const; 60 | 61 | //Some accessors 62 | boost::asio::ip::tcp::endpoint getLocalEndpoint() const; 63 | std::string getLocalInterface() const; 64 | uint16_t getLocalPort() const; 65 | 66 | boost::asio::ip::tcp::endpoint getPeerEndpoint() const; 67 | std::string getPeerAddress() const; 68 | uint16_t getPeerPort() const; 69 | 70 | std::string getName() const; 71 | 72 | uint32_t getNBytesLastRead() const; 73 | uint32_t getNBytesLastWritten() const; 74 | boost::system::error_code getLastReadError() const; 75 | boost::system::error_code getLastWriteError() const; 76 | boost::system::error_code getLastOpenAndConnectError() const; 77 | 78 | //Pass through some boost socket functionality: 79 | uint32_t getBytesAvailable() const; 80 | boost::asio::ip::tcp::socket* getBoostSocketPointer(); 81 | 82 | private: 83 | //The serial port and io service for the port 84 | boost::asio::io_service m_oIOService; 85 | boost::asio::ip::tcp::socket m_oSocket; 86 | 87 | //Timer for determining timeouts 88 | boost::asio::deadline_timer m_oOpenAndConnectTimer; 89 | boost::asio::deadline_timer m_oReadTimer; 90 | boost::asio::deadline_timer m_oWriteTimer; 91 | 92 | boost::asio::ip::tcp::resolver m_oResolver; 93 | 94 | //Flag for determining read errors 95 | bool m_bOpenAndConnectError; 96 | bool m_bReadError; 97 | bool m_bWriteError; 98 | 99 | //Info about about last transaction 100 | uint32_t m_u32NBytesLastRead; 101 | uint32_t m_u32NBytesLastWritten; 102 | boost::system::error_code m_oLastReadError; 103 | boost::system::error_code m_oLastReadTimeoutError; 104 | boost::system::error_code m_oLastWriteError; 105 | boost::system::error_code m_oLastopenAndConnectError; 106 | 107 | //Receive string used by readUntil function 108 | //(Require persistence across calls) 109 | std::string m_strReadUntilBuff; 110 | 111 | //Optional label for this socket. May be useful for debugging. 112 | std::string m_strName; 113 | 114 | //Boost sockets are not thread safe so lock access during reading/writing 115 | boost::mutex m_oMutex; 116 | 117 | //Internal callback functions for TCP socket port called by boost asynchronous socket API 118 | void callback_connectComplete(const boost::system::error_code& oError); 119 | void callback_connectTimeOut(const boost::system::error_code& oError); 120 | void callback_readComplete(const boost::system::error_code& oError, uint32_t u32NBytesTransferred); 121 | void callback_readTimeOut(const boost::system::error_code& oError); 122 | void callback_writeComplete(const boost::system::error_code& oError, uint32_t u32NBytesTransferred); 123 | void callback_writeTimeOut(const boost::system::error_code& oError); 124 | }; 125 | 126 | #endif // INTERRUPTIBLE_BLOCKING_TCP_SOCKET_H 127 | -------------------------------------------------------------------------------- /InterruptibleBlockingSockets/InterruptibleBlockingUDPSocket.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //System includes 4 | #include 5 | 6 | //Library includes 7 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 8 | #include 9 | #include 10 | #endif 11 | 12 | //Local includes 13 | #include "InterruptibleBlockingUDPSocket.h" 14 | 15 | using namespace std; 16 | 17 | cInterruptibleBlockingUDPSocket::cInterruptibleBlockingUDPSocket(const string &strName) : 18 | m_oSocket(m_oIOService), 19 | m_oTimer(m_oIOService), 20 | m_oResolver(m_oIOService), 21 | m_bError(true), 22 | m_strName(strName) 23 | { 24 | } 25 | 26 | cInterruptibleBlockingUDPSocket::cInterruptibleBlockingUDPSocket(const string &strLocalInterface, uint16_t u16LocalPort, const string &strPeerAddress, uint16_t u16PeerPort, const string &strName) : 27 | m_oSocket(m_oIOService), 28 | m_oTimer(m_oIOService), 29 | m_oResolver(m_oIOService), 30 | m_bError(true), 31 | m_strName(strName) 32 | { 33 | if(strPeerAddress.length()) 34 | openBindAndConnect(strLocalInterface, u16LocalPort, strPeerAddress, u16PeerPort); 35 | else 36 | openAndBind(strLocalInterface, u16LocalPort); 37 | 38 | } 39 | 40 | cInterruptibleBlockingUDPSocket::~cInterruptibleBlockingUDPSocket() 41 | { 42 | close(); 43 | } 44 | 45 | bool cInterruptibleBlockingUDPSocket::openAndBind(const string &strLocalAddress, uint16_t u16LocalPort) 46 | { 47 | //Error code to check returns of socket functions 48 | boost::system::error_code oEC; 49 | 50 | //If the socket is already open close it 51 | close(); 52 | 53 | //Open the socket 54 | m_oSocket.open(boost::asio::ip::udp::v4(), oEC); 55 | 56 | //Set some socket options 57 | m_oSocket.set_option( boost::asio::socket_base::receive_buffer_size(64 * 1024 * 1024) ); //Set buffer to 64 MB 58 | m_oSocket.set_option( boost::asio::socket_base::reuse_address(true) ); 59 | 60 | m_oLocalEndpoint = createEndpoint(strLocalAddress, u16LocalPort); 61 | 62 | if(oEC) 63 | { 64 | cout << "cInterruptibleBlockingUDPSocket::openAndBind(): Error opening socket: " << oEC.message() << endl; 65 | return false; 66 | } 67 | else 68 | { 69 | cout << "cInterruptibleBlockingUDPSocket::openAndBind(): Successfully opened UDP socket." << endl; 70 | } 71 | 72 | m_oSocket.bind(m_oLocalEndpoint, oEC); 73 | if (oEC) 74 | { 75 | m_oLastError = oEC; 76 | cout << "Error binding socket: " << oEC.message() << endl; 77 | return false; 78 | } 79 | else 80 | { 81 | cout << "cInterruptibleBlockingUDPSocket::openAndBind(): Successfully bound UDP socket to " << getLocalInterface() << ":" << getLocalPort() << endl; 82 | } 83 | return true; 84 | } 85 | 86 | bool cInterruptibleBlockingUDPSocket::openBindAndConnect(const string &strLocalInterface, uint16_t u16LocalPort, const string &strPeerAddress, uint16_t u16PeerPort) 87 | { 88 | boost::system::error_code oEC; 89 | 90 | openAndBind(strLocalInterface, u16LocalPort); 91 | 92 | m_oPeerEndpoint = createEndpoint(strPeerAddress, u16PeerPort); 93 | 94 | if(oEC) 95 | { 96 | cout << "Error opening socket: " << oEC.message() << endl; 97 | return false; 98 | } 99 | else 100 | { 101 | cout << "Successfully opened UDP socket." << endl; 102 | } 103 | 104 | m_oSocket.connect(m_oPeerEndpoint, oEC); 105 | if (oEC) 106 | { 107 | m_oLastError = oEC; 108 | cout << "Error binding socket: " << oEC.message() << endl; 109 | return false; 110 | } 111 | else 112 | { 113 | cout << "Successfully created virtual UDP connection to " << getPeerAddress() << ":" << getPeerPort() << endl; 114 | } 115 | return true; 116 | } 117 | 118 | void cInterruptibleBlockingUDPSocket::close() 119 | { 120 | cout << "cInterruptibleBlockingUDPSocket::close(): Cancelling all current socket operations." << endl; 121 | cancelCurrrentOperations(); 122 | 123 | //If the socket is open close it 124 | if(m_oSocket.is_open()) 125 | { 126 | try 127 | { 128 | m_oSocket.close(); 129 | } 130 | catch(boost::system::system_error &e) 131 | { 132 | //Catch special conditions where socket is trying to be opened etc. 133 | //Prevents crash. 134 | } 135 | } 136 | } 137 | 138 | bool cInterruptibleBlockingUDPSocket::send(const char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms) 139 | { 140 | //Note this function sends to the specific endpoint set in the constructor or with the openAndBind function 141 | 142 | //Necessary after a timeout: 143 | m_oSocket.get_io_service().reset(); 144 | 145 | //Asynchronously write characters 146 | m_oSocket.async_send( boost::asio::buffer(cpBuffer, u32NBytes), 147 | boost::bind(&cInterruptibleBlockingUDPSocket::callback_complete, 148 | this, 149 | boost::asio::placeholders::error, 150 | boost::asio::placeholders::bytes_transferred) ); 151 | 152 | // Setup a deadline time to implement our timeout. 153 | if(u32Timeout_ms) 154 | { 155 | m_oTimer.expires_from_now( boost::posix_time::milliseconds(u32Timeout_ms) ); 156 | m_oTimer.async_wait( boost::bind(&cInterruptibleBlockingUDPSocket::callback_timeOut, 157 | this, boost::asio::placeholders::error) ); 158 | } 159 | 160 | // This will block until a character is read 161 | // or until the it is cancelled. 162 | m_oSocket.get_io_service().run(); 163 | 164 | return !m_bError; 165 | } 166 | 167 | bool cInterruptibleBlockingUDPSocket::sendTo(const char *cpBuffer, uint32_t u32NBytes, const std::string &strPeerAddress, uint16_t u16PeerPort, uint32_t u32Timeout_ms) 168 | { 169 | return cInterruptibleBlockingUDPSocket::sendTo(cpBuffer, u32NBytes, createEndpoint(strPeerAddress, u16PeerPort), u32Timeout_ms); 170 | } 171 | 172 | bool cInterruptibleBlockingUDPSocket::sendTo(const char *cpBuffer, uint32_t u32NBytes, const boost::asio::ip::udp::endpoint &oPeerEndpoint, uint32_t u32Timeout_ms) 173 | { 174 | //Note this function sends to the specific endpoint set in the constructor or with the openAndBind function 175 | 176 | //Necessary after a timeout: 177 | m_oSocket.get_io_service().reset(); 178 | 179 | //Asynchronously write characters 180 | m_oSocket.async_send_to( boost::asio::buffer(cpBuffer, u32NBytes), 181 | oPeerEndpoint, 182 | boost::bind(&cInterruptibleBlockingUDPSocket::callback_complete, 183 | this, 184 | boost::asio::placeholders::error, 185 | boost::asio::placeholders::bytes_transferred) ); 186 | 187 | // Setup a deadline time to implement our timeout. 188 | if(u32Timeout_ms) 189 | { 190 | m_oTimer.expires_from_now( boost::posix_time::milliseconds(u32Timeout_ms) ); 191 | m_oTimer.async_wait( boost::bind(&cInterruptibleBlockingUDPSocket::callback_timeOut, 192 | this, boost::asio::placeholders::error) ); 193 | } 194 | 195 | // This will block until a character is read 196 | // or until the it is cancelled. 197 | m_oSocket.get_io_service().run(); 198 | 199 | return !m_bError; 200 | } 201 | 202 | bool cInterruptibleBlockingUDPSocket::receive(char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms) 203 | { 204 | //Necessary after a timeout: 205 | m_oSocket.get_io_service().reset(); 206 | 207 | //Asynchronously read characters into string 208 | m_oSocket.async_receive( boost::asio::buffer(cpBuffer, u32NBytes), 209 | boost::bind(&cInterruptibleBlockingUDPSocket::callback_complete, 210 | this, 211 | boost::asio::placeholders::error, 212 | boost::asio::placeholders::bytes_transferred) ); 213 | 214 | // Setup a deadline time to implement our timeout. 215 | if(u32Timeout_ms) 216 | { 217 | m_oTimer.expires_from_now(boost::posix_time::milliseconds(u32Timeout_ms)); 218 | m_oTimer.async_wait(boost::bind(&cInterruptibleBlockingUDPSocket::callback_timeOut, 219 | this, boost::asio::placeholders::error)); 220 | } 221 | 222 | // This will block until a byte is read 223 | // or until the it is cancelled. 224 | m_oSocket.get_io_service().run(); 225 | 226 | return !m_bError; 227 | } 228 | 229 | bool cInterruptibleBlockingUDPSocket::receiveFrom(char *cpBuffer, uint32_t u32NBytes, std::string &strPeerAddress, uint16_t &u16PeerPort, uint32_t u32Timeout_ms) 230 | { 231 | boost::asio::ip::udp::endpoint oPeerEndpoint; 232 | bool bResult = receiveFrom(cpBuffer, u32NBytes, oPeerEndpoint, u32Timeout_ms); 233 | 234 | strPeerAddress = getEndpointHostAddress(oPeerEndpoint); 235 | u16PeerPort = getEndpointPort(oPeerEndpoint); 236 | 237 | return bResult; 238 | } 239 | 240 | bool cInterruptibleBlockingUDPSocket::receiveFrom(char *cpBuffer, uint32_t u32NBytes, boost::asio::ip::udp::endpoint &oPeerEndpoint, uint32_t u32Timeout_ms) 241 | { 242 | //Necessary after a timeout: 243 | m_oSocket.get_io_service().reset(); 244 | 245 | //Asynchronously read characters into string 246 | m_oSocket.async_receive_from( boost::asio::buffer(cpBuffer, u32NBytes), 247 | oPeerEndpoint, 248 | boost::bind(&cInterruptibleBlockingUDPSocket::callback_complete, 249 | this, 250 | boost::asio::placeholders::error, 251 | boost::asio::placeholders::bytes_transferred) ); 252 | 253 | // Setup a deadline time to implement our timeout. 254 | if(u32Timeout_ms) 255 | { 256 | m_oTimer.expires_from_now(boost::posix_time::milliseconds(u32Timeout_ms)); 257 | m_oTimer.async_wait(boost::bind(&cInterruptibleBlockingUDPSocket::callback_timeOut, 258 | this, boost::asio::placeholders::error)); 259 | } 260 | 261 | // This will block until a byte is read 262 | // or until the it is cancelled. 263 | m_oSocket.get_io_service().run(); 264 | 265 | return !m_bError; 266 | } 267 | 268 | 269 | void cInterruptibleBlockingUDPSocket::callback_complete(const boost::system::error_code& oError, uint32_t u32NBytesTransferred) 270 | { 271 | m_bError = oError || (u32NBytesTransferred == 0); 272 | m_oTimer.cancel(); 273 | 274 | m_u32NBytesLastTransferred = u32NBytesTransferred; 275 | m_oLastError = oError; 276 | } 277 | 278 | void cInterruptibleBlockingUDPSocket::callback_timeOut(const boost::system::error_code& oError) 279 | { 280 | if (oError) 281 | { 282 | m_oLastError = oError; 283 | return; 284 | } 285 | 286 | std::cout << "!!! Time out reached on socket \"" << m_strName << "\" (" << this << ")" << std::endl; 287 | 288 | m_oSocket.cancel(); 289 | } 290 | 291 | void cInterruptibleBlockingUDPSocket::cancelCurrrentOperations() 292 | { 293 | try 294 | { 295 | m_oSocket.get_io_service().stop(); 296 | m_oSocket.cancel(); 297 | m_oTimer.cancel(); 298 | } 299 | catch(boost::system::system_error &e) 300 | { 301 | //Catch special conditions where socket is trying to be opened etc. 302 | //Prevents crash. 303 | } 304 | } 305 | 306 | boost::asio::ip::udp::endpoint cInterruptibleBlockingUDPSocket::createEndpoint(string strHostAddress, uint16_t u16Port) 307 | { 308 | stringstream oSS; 309 | oSS << u16Port; 310 | 311 | return *m_oResolver.resolve(boost::asio::ip::udp::resolver::query(boost::asio::ip::udp::v4(), strHostAddress, oSS.str())); 312 | } 313 | 314 | std::string cInterruptibleBlockingUDPSocket::getEndpointHostAddress(boost::asio::ip::udp::endpoint oEndpoint) const 315 | { 316 | return oEndpoint.address().to_string(); 317 | } 318 | 319 | uint16_t cInterruptibleBlockingUDPSocket::getEndpointPort(boost::asio::ip::udp::endpoint oEndpoint) const 320 | { 321 | return oEndpoint.port(); 322 | } 323 | 324 | boost::asio::ip::udp::endpoint cInterruptibleBlockingUDPSocket::getLocalEndpoint() const 325 | { 326 | return m_oLocalEndpoint; 327 | } 328 | 329 | std::string cInterruptibleBlockingUDPSocket::getLocalInterface() const 330 | { 331 | return getEndpointHostAddress(m_oLocalEndpoint); 332 | } 333 | 334 | uint16_t cInterruptibleBlockingUDPSocket::getLocalPort() const 335 | { 336 | return getEndpointPort(m_oLocalEndpoint); 337 | } 338 | 339 | boost::asio::ip::udp::endpoint cInterruptibleBlockingUDPSocket::getPeerEndpoint() const 340 | { 341 | return m_oPeerEndpoint; 342 | } 343 | 344 | std::string cInterruptibleBlockingUDPSocket::getPeerAddress() const 345 | { 346 | return getEndpointHostAddress(m_oPeerEndpoint); 347 | } 348 | 349 | uint16_t cInterruptibleBlockingUDPSocket::getPeerPort() const 350 | { 351 | return getEndpointPort(m_oPeerEndpoint); 352 | } 353 | 354 | std::string cInterruptibleBlockingUDPSocket::getName() const 355 | { 356 | return m_strName; 357 | } 358 | 359 | uint32_t cInterruptibleBlockingUDPSocket::getNBytesLastTransferred() const 360 | { 361 | return m_u32NBytesLastTransferred; 362 | } 363 | 364 | boost::system::error_code cInterruptibleBlockingUDPSocket::getLastError() const 365 | { 366 | return m_oLastError; 367 | } 368 | 369 | uint32_t cInterruptibleBlockingUDPSocket::getBytesAvailable() const 370 | { 371 | return m_oSocket.available(); 372 | } 373 | 374 | boost::asio::ip::udp::socket* cInterruptibleBlockingUDPSocket::getBoostSocketPointer() 375 | { 376 | return &m_oSocket; 377 | } 378 | 379 | -------------------------------------------------------------------------------- /InterruptibleBlockingSockets/InterruptibleBlockingTCPSocket.cpp: -------------------------------------------------------------------------------- 1 | 2 | //System includes 3 | #include 4 | 5 | //Library includes 6 | #ifndef Q_MOC_RUN //Qt's MOC and Boost have some issues don't let MOC process boost headers 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #endif 14 | 15 | //Local includes 16 | #include "InterruptibleBlockingTCPSocket.h" 17 | 18 | using namespace std; 19 | 20 | cInterruptibleBlockingTCPSocket::cInterruptibleBlockingTCPSocket(const string &strName) : 21 | m_oSocket(m_oIOService), 22 | m_oOpenAndConnectTimer(m_oIOService), 23 | m_oReadTimer(m_oIOService), 24 | m_oWriteTimer(m_oIOService), 25 | m_oResolver(m_oIOService), 26 | m_bOpenAndConnectError(true), 27 | m_bReadError(true), 28 | m_bWriteError(true), 29 | m_strName(strName) 30 | { 31 | } 32 | 33 | cInterruptibleBlockingTCPSocket::cInterruptibleBlockingTCPSocket(const string &strRemoteAddress, uint16_t u16RemotePort, const string &strName) : 34 | m_oSocket(m_oIOService), 35 | m_oOpenAndConnectTimer(m_oIOService), 36 | m_oReadTimer(m_oIOService), 37 | m_oWriteTimer(m_oIOService), 38 | m_oResolver(m_oIOService), 39 | m_bOpenAndConnectError(true), 40 | m_bReadError(true), 41 | m_bWriteError(true), 42 | m_strName(strName) 43 | { 44 | openAndConnect(strRemoteAddress, u16RemotePort); 45 | } 46 | 47 | cInterruptibleBlockingTCPSocket::~cInterruptibleBlockingTCPSocket() 48 | { 49 | close(); 50 | } 51 | 52 | bool cInterruptibleBlockingTCPSocket::openAndConnect(string strPeerAddress, uint16_t u16PeerPort, uint32_t u32Timeout_ms) 53 | { 54 | if(m_oSocket.get_io_service().stopped()) 55 | { 56 | //Necessary after a timeout or previously finished run: 57 | m_oSocket.get_io_service().reset(); 58 | } 59 | 60 | //If the socket is already open close it 61 | close(); 62 | 63 | //Open the socket 64 | m_oSocket.open(boost::asio::ip::tcp::v4(), m_oLastopenAndConnectError); 65 | 66 | if(m_oLastopenAndConnectError) 67 | { 68 | cout << "cInterruptibleBlockingTCPSocket::openAndConnect(): Error opening socket: " << m_oLastopenAndConnectError.message() << endl; 69 | return false; 70 | } 71 | else 72 | { 73 | cout << "cInterruptibleBlockingTCPSocket::openAndConnect(): Successfully opened TCP socket. Attempting to connect..." << endl; 74 | } 75 | fflush(stdout); 76 | 77 | //Set some socket options 78 | m_oSocket.set_option( boost::asio::socket_base::receive_buffer_size(64 * 1024 * 1024) ); //Set buffer to 64 MB 79 | m_oSocket.set_option( boost::asio::socket_base::reuse_address(true) ); 80 | 81 | boost::asio::ip::tcp::endpoint oPeerEndPoint; 82 | try 83 | { 84 | oPeerEndPoint = createEndpoint(strPeerAddress, u16PeerPort); 85 | } 86 | catch(boost::system::system_error &e) 87 | { 88 | //Typically thrown when hostname cannot be resolved. 89 | return false; 90 | } 91 | 92 | //Async connect can have timeout or be cancelled at any point 93 | m_oSocket.async_connect(oPeerEndPoint, 94 | boost::bind(&cInterruptibleBlockingTCPSocket::callback_connectComplete, 95 | this, 96 | boost::asio::placeholders::error) 97 | ); 98 | 99 | 100 | // Setup a deadline time to implement our timeout. 101 | if(u32Timeout_ms) 102 | { 103 | m_oOpenAndConnectTimer.expires_from_now( boost::posix_time::milliseconds(u32Timeout_ms) ); 104 | m_oOpenAndConnectTimer.async_wait( boost::bind(&cInterruptibleBlockingTCPSocket::callback_connectTimeOut, 105 | this, boost::asio::placeholders::error) ); 106 | } 107 | 108 | m_oSocket.get_io_service().run(); 109 | 110 | if(!m_bOpenAndConnectError) 111 | cout << "cInterruptibleBlockingTCPSocket::openAndConnect(): Successfully connected TCP socket to " << strPeerAddress << ":" << u16PeerPort << endl; 112 | 113 | return !m_bOpenAndConnectError; 114 | } 115 | 116 | void cInterruptibleBlockingTCPSocket::close() 117 | { 118 | //If the socket is open close it 119 | if(m_oSocket.is_open()) 120 | { 121 | m_oSocket.cancel(); 122 | 123 | try 124 | { 125 | m_oSocket.close(); 126 | } 127 | catch(boost::system::system_error &e) 128 | { 129 | //Catch special conditions where socket is trying to be opened etc. 130 | //Prevents crash. 131 | } 132 | } 133 | } 134 | 135 | bool cInterruptibleBlockingTCPSocket::send(const char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms) 136 | { 137 | //Note this function sends to the specific endpoint set in the constructor or with the openAndBind function 138 | 139 | boost::unique_lock oLock(m_oMutex); 140 | 141 | if(m_oSocket.get_io_service().stopped()) 142 | { 143 | //Necessary after a timeout or previously finished run: 144 | m_oSocket.get_io_service().reset(); 145 | } 146 | 147 | //Asynchronously write characters 148 | m_oSocket.async_send( boost::asio::buffer(cpBuffer, u32NBytes), 149 | boost::bind(&cInterruptibleBlockingTCPSocket::callback_writeComplete, 150 | this, 151 | boost::asio::placeholders::error, 152 | boost::asio::placeholders::bytes_transferred) ); 153 | 154 | // Setup a deadline time to implement our timeout. 155 | if(u32Timeout_ms) 156 | { 157 | m_oWriteTimer.expires_from_now( boost::posix_time::milliseconds(u32Timeout_ms) ); 158 | m_oWriteTimer.async_wait( boost::bind(&cInterruptibleBlockingTCPSocket::callback_writeTimeOut, 159 | this, boost::asio::placeholders::error) ); 160 | } 161 | 162 | // This will block until at least a byte is written 163 | // or until it is cancelled. 164 | m_oSocket.get_io_service().run(); 165 | 166 | return !m_bWriteError; 167 | } 168 | 169 | bool cInterruptibleBlockingTCPSocket::receive(char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms) 170 | { 171 | boost::unique_lock oLock(m_oMutex); 172 | 173 | if(m_oSocket.get_io_service().stopped()) 174 | { 175 | //Necessary after a timeout or previously finished run: 176 | m_oSocket.get_io_service().reset(); 177 | } 178 | 179 | //Asynchronously read characters into string 180 | m_oSocket.async_receive( boost::asio::buffer(cpBuffer, u32NBytes), 181 | boost::bind(&cInterruptibleBlockingTCPSocket::callback_readComplete, 182 | this, 183 | boost::asio::placeholders::error, 184 | boost::asio::placeholders::bytes_transferred) ); 185 | 186 | // Setup a deadline time to implement our timeout. 187 | if(u32Timeout_ms) 188 | { 189 | m_oReadTimer.expires_from_now(boost::posix_time::milliseconds(u32Timeout_ms)); 190 | m_oReadTimer.async_wait(boost::bind(&cInterruptibleBlockingTCPSocket::callback_readTimeOut, 191 | this, boost::asio::placeholders::error)); 192 | } 193 | 194 | // This will block until at least a byte is read 195 | // or until it is cancelled. 196 | m_oSocket.get_io_service().run(); 197 | 198 | return !m_bReadError; 199 | } 200 | 201 | bool cInterruptibleBlockingTCPSocket::write(const char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms) 202 | { 203 | boost::unique_lock oLock(m_oMutex); 204 | 205 | //The write function guarantees deliver of all u32NBytes bytes in send buffer unless and error is encountered 206 | 207 | if(m_oSocket.get_io_service().stopped()) 208 | { 209 | //Necessary after a timeout or previously finished run: 210 | m_oSocket.get_io_service().reset(); 211 | } 212 | 213 | //Asynchronously write all data 214 | boost::asio::async_write(m_oSocket, boost::asio::buffer(cpBuffer, u32NBytes), 215 | boost::bind(&cInterruptibleBlockingTCPSocket::callback_writeComplete, 216 | this, 217 | boost::asio::placeholders::error, 218 | boost::asio::placeholders::bytes_transferred) ); 219 | 220 | // Setup a deadline time to implement our timeout. 221 | if(u32Timeout_ms) 222 | { 223 | m_oWriteTimer.expires_from_now(boost::posix_time::milliseconds(u32Timeout_ms)); 224 | m_oWriteTimer.async_wait(boost::bind(&cInterruptibleBlockingTCPSocket::callback_writeTimeOut, 225 | this, boost::asio::placeholders::error)); 226 | } 227 | 228 | // This will block until all bytes are written 229 | // or until it is cancelled. 230 | m_oSocket.get_io_service().run(); 231 | 232 | return !m_bWriteError; 233 | } 234 | 235 | bool cInterruptibleBlockingTCPSocket::write(const std::string &strData, uint32_t u32Timeout_ms) 236 | { 237 | return write(strData.c_str(), strData.length(), u32Timeout_ms); 238 | } 239 | 240 | bool cInterruptibleBlockingTCPSocket::read(char *cpBuffer, uint32_t u32NBytes, uint32_t u32Timeout_ms) 241 | { 242 | boost::unique_lock oLock(m_oMutex); 243 | 244 | //The read function guarantees reading of all u32NBytes bytes to buffer unless an error is encountered 245 | 246 | if(m_oSocket.get_io_service().stopped()) 247 | { 248 | //Necessary after a timeout or previously finished run: 249 | m_oSocket.get_io_service().reset(); 250 | } 251 | 252 | //Asynchronously read until the delimiting character is found 253 | boost::asio::async_read(m_oSocket, boost::asio::buffer(cpBuffer, u32NBytes), 254 | boost::bind(&cInterruptibleBlockingTCPSocket::callback_readComplete, 255 | this, 256 | boost::asio::placeholders::error, 257 | boost::asio::placeholders::bytes_transferred) ); 258 | 259 | // Setup a deadline time to implement our timeout. 260 | if(u32Timeout_ms) 261 | { 262 | m_oReadTimer.expires_from_now(boost::posix_time::milliseconds(u32Timeout_ms)); 263 | m_oReadTimer.async_wait(boost::bind(&cInterruptibleBlockingTCPSocket::callback_readTimeOut, 264 | this, boost::asio::placeholders::error)); 265 | } 266 | 267 | // This will block until all bytes are read 268 | // or until it is cancelled. 269 | m_oSocket.get_io_service().run(); 270 | 271 | return !m_bReadError; 272 | } 273 | 274 | bool cInterruptibleBlockingTCPSocket::readUntil(string &strBuffer, const string &strDelimiter, uint32_t u32Timeout_ms) 275 | { 276 | boost::unique_lock oLock(m_oMutex); 277 | 278 | //Check if we have already read up the delimeter if so return this string 279 | if(m_strReadUntilBuff.find_first_of(strDelimiter) != string::npos) 280 | { 281 | uint32_t u32DelimPos = m_strReadUntilBuff.find_first_of(strDelimiter); 282 | strBuffer.append(m_strReadUntilBuff.substr(0, u32DelimPos + 1)); 283 | m_strReadUntilBuff.erase(0, u32DelimPos + 1); 284 | 285 | return true; 286 | } 287 | 288 | if(m_oSocket.get_io_service().stopped()) 289 | { 290 | //Necessary after a timeout or previously finished run: 291 | m_oSocket.get_io_service().reset(); 292 | } 293 | 294 | boost::asio::streambuf oStreamBuf; 295 | 296 | //Asynchronously read until the delimiting character is found 297 | boost::asio::async_read_until(m_oSocket, oStreamBuf, strDelimiter, 298 | boost::bind(&cInterruptibleBlockingTCPSocket::callback_readComplete, 299 | this, 300 | boost::asio::placeholders::error, 301 | boost::asio::placeholders::bytes_transferred) ); 302 | 303 | // Setup a deadline time to implement our timeout. 304 | if(u32Timeout_ms) 305 | { 306 | m_oReadTimer.expires_from_now(boost::posix_time::milliseconds(u32Timeout_ms)); 307 | m_oReadTimer.async_wait(boost::bind(&cInterruptibleBlockingTCPSocket::callback_readTimeOut, 308 | this, boost::asio::placeholders::error)); 309 | } 310 | 311 | // This will block until the delimiter is found and read 312 | // or until the it is cancelled. 313 | for(;;) 314 | { 315 | try 316 | { 317 | m_oSocket.get_io_service().run(); 318 | break; 319 | } 320 | catch(...) 321 | { 322 | cout << "cInterruptibleBlockingTCPSocket::readUntil(): Caught exception on io_service::run()" << endl; 323 | } 324 | } 325 | 326 | //Copy the data to the member string. This may contain more than 1 of the delimiter 327 | try 328 | { 329 | m_strReadUntilBuff.append( std::string( (std::istreambuf_iterator(&oStreamBuf)), std::istreambuf_iterator() ) ); 330 | } 331 | catch(...) 332 | { 333 | cout << "cInterruptibleBlockingTCPSocket::readUntil(): Got string convertion error." << endl; 334 | } 335 | 336 | //Move characters up to the first instance of the delimiter to the argument string 337 | uint32_t u32DelimPos = m_strReadUntilBuff.find_first_of(strDelimiter); 338 | strBuffer.append(m_strReadUntilBuff.substr(0, u32DelimPos + 1)); 339 | m_strReadUntilBuff.erase(0, u32DelimPos + 1); 340 | 341 | //Debug: Deallocation of the streambuffer seems segfault sometimes. Try empty first: 342 | oStreamBuf.consume(oStreamBuf.size()); 343 | 344 | return !m_bReadError; 345 | } 346 | 347 | void cInterruptibleBlockingTCPSocket::callback_connectComplete(const boost::system::error_code& oError) 348 | { 349 | m_bOpenAndConnectError= true; 350 | if (boost::system::errc::success == oError) 351 | { 352 | m_bOpenAndConnectError= false; 353 | } 354 | //RE: m_bOpenAndConnectError = oError; 355 | m_oOpenAndConnectTimer.cancel(); 356 | 357 | m_oLastopenAndConnectError = oError; 358 | } 359 | 360 | void cInterruptibleBlockingTCPSocket::callback_connectTimeOut(const boost::system::error_code& oError) 361 | { 362 | if (oError) 363 | { 364 | m_oLastopenAndConnectError = oError; 365 | return; 366 | } 367 | 368 | std::cout << "!!! Time out reached on socket connect\"" << m_strName << "\" (" << this << ")" << std::endl; 369 | 370 | m_oSocket.cancel(); 371 | } 372 | 373 | void cInterruptibleBlockingTCPSocket::callback_readComplete(const boost::system::error_code& oError, uint32_t u32NBytesTransferred) 374 | { 375 | m_bReadError = oError || (u32NBytesTransferred == 0); 376 | m_oReadTimer.cancel(); 377 | 378 | m_u32NBytesLastRead = u32NBytesTransferred; 379 | m_oLastReadError = oError; 380 | } 381 | 382 | void cInterruptibleBlockingTCPSocket::callback_writeComplete(const boost::system::error_code& oError, uint32_t u32NBytesTransferred) 383 | { 384 | m_bWriteError = oError || (u32NBytesTransferred == 0); 385 | m_oWriteTimer.cancel(); 386 | 387 | m_u32NBytesLastWritten = u32NBytesTransferred; 388 | m_oLastWriteError = oError; 389 | } 390 | 391 | void cInterruptibleBlockingTCPSocket::callback_readTimeOut(const boost::system::error_code& oError) 392 | { 393 | if (oError) 394 | { 395 | m_oLastReadTimeoutError = oError; 396 | return; 397 | } 398 | 399 | m_oSocket.cancel(); 400 | } 401 | 402 | void cInterruptibleBlockingTCPSocket::callback_writeTimeOut(const boost::system::error_code& oError) 403 | { 404 | if (oError) 405 | { 406 | m_oLastWriteError = oError; 407 | return; 408 | } 409 | 410 | m_oSocket.cancel(); 411 | } 412 | 413 | void cInterruptibleBlockingTCPSocket::cancelCurrrentOperations() 414 | { 415 | try 416 | { 417 | m_oSocket.get_io_service().stop(); 418 | m_oSocket.cancel(); 419 | } 420 | catch(boost::system::system_error &e) 421 | { 422 | //Catch special conditions where socket is trying to be opened etc. 423 | //Prevents crash. 424 | } 425 | 426 | try 427 | { 428 | m_oReadTimer.cancel(); 429 | } 430 | catch(boost::system::system_error &e) 431 | { 432 | //Catch special conditions where socket is trying to be opened etc. 433 | //Prevents crash. 434 | } 435 | 436 | try 437 | { 438 | m_oWriteTimer.cancel(); 439 | } 440 | catch(boost::system::system_error &e) 441 | { 442 | //Catch special conditions where socket is trying to be opened etc. 443 | //Prevents crash. 444 | } 445 | } 446 | 447 | boost::asio::ip::tcp::endpoint cInterruptibleBlockingTCPSocket::createEndpoint(string strHostAddress, uint16_t u16Port) 448 | { 449 | stringstream oSS; 450 | oSS << u16Port; 451 | 452 | return *m_oResolver.resolve(boost::asio::ip::tcp::resolver::query(boost::asio::ip::tcp::v4(), strHostAddress, oSS.str())); 453 | } 454 | 455 | std::string cInterruptibleBlockingTCPSocket::getEndpointHostAddress(boost::asio::ip::tcp::endpoint oEndPoint) const 456 | { 457 | return oEndPoint.address().to_string(); 458 | } 459 | 460 | uint16_t cInterruptibleBlockingTCPSocket::getEndpointPort(boost::asio::ip::tcp::endpoint oEndPoint) const 461 | { 462 | return oEndPoint.port(); 463 | } 464 | 465 | boost::asio::ip::tcp::endpoint cInterruptibleBlockingTCPSocket::getLocalEndpoint() const 466 | { 467 | return m_oSocket.local_endpoint(); 468 | } 469 | 470 | std::string cInterruptibleBlockingTCPSocket::getLocalInterface() const 471 | { 472 | return getEndpointHostAddress(m_oSocket.local_endpoint()); 473 | } 474 | 475 | uint16_t cInterruptibleBlockingTCPSocket::getLocalPort() const 476 | { 477 | return getEndpointPort(m_oSocket.local_endpoint()); 478 | } 479 | 480 | boost::asio::ip::tcp::endpoint cInterruptibleBlockingTCPSocket::getPeerEndpoint() const 481 | { 482 | return m_oSocket.local_endpoint(); 483 | } 484 | 485 | std::string cInterruptibleBlockingTCPSocket::getPeerAddress() const 486 | { 487 | return getEndpointHostAddress(m_oSocket.remote_endpoint()); 488 | } 489 | 490 | uint16_t cInterruptibleBlockingTCPSocket::getPeerPort() const 491 | { 492 | return getEndpointPort(m_oSocket.remote_endpoint()); 493 | } 494 | 495 | std::string cInterruptibleBlockingTCPSocket::getName() const 496 | { 497 | return m_strName; 498 | } 499 | 500 | uint32_t cInterruptibleBlockingTCPSocket::getNBytesLastRead() const 501 | { 502 | return m_u32NBytesLastRead; 503 | } 504 | 505 | uint32_t cInterruptibleBlockingTCPSocket::getNBytesLastWritten() const 506 | { 507 | return m_u32NBytesLastWritten; 508 | } 509 | 510 | boost::system::error_code cInterruptibleBlockingTCPSocket::getLastWriteError() const 511 | { 512 | return m_oLastWriteError; 513 | } 514 | 515 | boost::system::error_code cInterruptibleBlockingTCPSocket::getLastReadError() const 516 | { 517 | return m_oLastReadError; 518 | } 519 | 520 | uint32_t cInterruptibleBlockingTCPSocket::getBytesAvailable() const 521 | { 522 | return m_oSocket.available(); 523 | } 524 | 525 | boost::asio::ip::tcp::socket* cInterruptibleBlockingTCPSocket::getBoostSocketPointer() 526 | { 527 | return &m_oSocket; 528 | } 529 | --------------------------------------------------------------------------------