├── UDPReceiver ├── UDPReceiver.h └── UDPReceiver.cpp ├── TCPReceiver ├── TCPReceiver.h └── TCPReceiver.cpp ├── TCPServer ├── TCPServer.h ├── ConnectionThread.h ├── TCPServer.cpp └── ConnectionThread.cpp ├── SocketReceiverBase.h └── SocketReceiverBase.cpp /UDPReceiver/UDPReceiver.h: -------------------------------------------------------------------------------- 1 | #ifndef UDP_RECEIVER_H 2 | #define UDP_RECEIVER_H 3 | 4 | //System includes 5 | 6 | //Library includes 7 | 8 | //Local includes 9 | #include "../SocketReceiverBase.h" 10 | #include "../../../AVNUtilLibs/Sockets/InterruptibleBlockingSockets/InterruptibleBlockingUDPSocket.h" 11 | 12 | class cUDPReceiver : public cSocketReceiverBase 13 | { 14 | public: 15 | explicit cUDPReceiver(const std::string &strLocalInterface, uint16_t u16LocalPort = 60000, const std::string &strPeerAddress = std::string(""), uint16_t usPeerPort = 60001); 16 | virtual ~cUDPReceiver(); 17 | 18 | virtual void stopReceiving(); 19 | 20 | protected: 21 | //Socket 22 | cInterruptibleBlockingUDPSocket m_oSocket; 23 | 24 | std::string m_strLocalInterface; 25 | uint16_t m_u16LocalPort; 26 | 27 | //Thread functions 28 | virtual void socketReceivingThreadFunction(); 29 | }; 30 | 31 | #endif // UDP_RECEIVER_H 32 | -------------------------------------------------------------------------------- /TCPReceiver/TCPReceiver.h: -------------------------------------------------------------------------------- 1 | #ifndef TCP_RECEIVER_H 2 | #define TCP_RECEIVER_H 3 | 4 | //System includes 5 | 6 | //Library includes 7 | 8 | //Local includes 9 | #include "../SocketReceiverBase.h" 10 | #include "../../../AVNUtilLibs/Sockets/InterruptibleBlockingSockets/InterruptibleBlockingTCPSocket.h" 11 | 12 | class cTCPReceiver : public cSocketReceiverBase 13 | { 14 | public: 15 | class cNotificationCallbackInterface 16 | { 17 | public: 18 | //Callbacks to notify about connectiviy 19 | virtual void socketConnected_callback() = 0; 20 | virtual void socketDisconnected_callback() = 0; 21 | }; 22 | 23 | explicit cTCPReceiver(const std::string &strPeerAddress, uint16_t usPeerPort = 60001); 24 | virtual ~cTCPReceiver(); 25 | 26 | virtual void stopReceiving(); 27 | 28 | void registerNoticationCallbackHandler(cNotificationCallbackInterface* pNewHandler); 29 | void registerNoticationCallbackHandler(boost::shared_ptr pNewHandler); 30 | void deregisterNotificationCallbackHandler(cNotificationCallbackInterface* pHandler); 31 | void deregisterNotificationCallbackHandler(boost::shared_ptr pHandler); 32 | 33 | protected: 34 | //TCP Socket 35 | cInterruptibleBlockingTCPSocket m_oSocket; 36 | 37 | //Callback handlers 38 | std::vector m_vpNotificationCallbackHandlers; 39 | std::vector > m_vpNotificationCallbackHandlers_shared; 40 | 41 | //Thread functions 42 | virtual void socketReceivingThreadFunction(); 43 | 44 | }; 45 | 46 | #endif // TCP_RECEIVER_H 47 | -------------------------------------------------------------------------------- /TCPServer/TCPServer.h: -------------------------------------------------------------------------------- 1 | #ifndef TCP_SERVER_H 2 | #define TCP_SERVER_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 include: 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 | #include "../../../AVNUtilLibs/DataStructures/ThreadSafeCircularBuffer/ThreadSafeCircularBuffer.h" 32 | #include "../../../AVNUtilLibs/Sockets/InterruptibleBlockingSockets/InterruptibleBlockingUDPSocket.h" 33 | #include "../../../AVNUtilLibs/Sockets/InterruptibleBlockingSocketAcceptors/InterruptibleBlockingTCPAcceptor.h" 34 | #include "ConnectionThread.h" 35 | 36 | class cTCPServer 37 | { 38 | public: 39 | cTCPServer(const std::string &strInterface = std::string("0.0.0.0"), uint16_t usPort = 60001, uint32_t u32MaxConnections = 0); 40 | virtual ~cTCPServer(); 41 | 42 | void writeData(char* cpData, uint32_t u32Size_B); 43 | 44 | void shutdown(); 45 | bool isShutdownRequested(); 46 | 47 | protected: 48 | bool m_bShutdownFlag; 49 | boost::shared_mutex m_bShutdownFlagMutex; 50 | 51 | uint32_t m_u32MaxConnections; 52 | std::string m_strInterface; 53 | uint16_t m_u16Port; 54 | 55 | cInterruptibleBlockingTCPAcceptor m_oTCPAcceptor; 56 | 57 | std::vector > m_vpConnectionThreads; 58 | boost::shared_mutex m_oConnectThreadsMutex; 59 | 60 | void socketListeningThreadFunction(); 61 | 62 | boost::scoped_ptr m_pSocketListeningThread; 63 | }; 64 | 65 | #endif //TCP_SERVER_H 66 | -------------------------------------------------------------------------------- /TCPServer/ConnectionThread.h: -------------------------------------------------------------------------------- 1 | #ifndef CONNECTION_THREAD_H 2 | #define CONNECTION_THREAD_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 include: 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 | #endif 25 | 26 | //Local includes 27 | #include "../../../AVNUtilLibs/DataStructures/ThreadSafeCircularBuffer/ThreadSafeCircularBuffer.h" 28 | #include "../../../AVNUtilLibs/Sockets/InterruptibleBlockingSockets/InterruptibleBlockingTCPSocket.h" 29 | #include "../UDPReceiver/UDPReceiver.h" 30 | 31 | class cConnectionThread 32 | { 33 | public: 34 | explicit cConnectionThread(boost::shared_ptr pClientSocket); 35 | ~cConnectionThread(); 36 | 37 | bool tryAddDataToSend(char* cpData, uint32_t u32Size_B); 38 | void blockingAddDataToSend(char* cpData, uint32_t u32Size_B); 39 | 40 | bool isValid(); 41 | void setInvalid(); 42 | 43 | void shutdown(); 44 | bool isShutdownRequested(); 45 | 46 | std::string getPeerAddress(); 47 | std::string getSocketName(); 48 | 49 | private: 50 | std::string m_strPeerAddress; 51 | 52 | bool m_bShutdownFlag; 53 | boost::shared_mutex m_bShutdownFlagMutex; 54 | 55 | //Thread functions 56 | void socketWritingThreadFunction(); 57 | 58 | //Threads 59 | boost::scoped_ptr m_pSocketWritingThread; 60 | 61 | boost::shared_ptr m_pSocket; 62 | 63 | bool m_bIsValid; 64 | boost::shared_mutex m_bValidMutex; 65 | 66 | //Circular buffers 67 | cThreadSafeCircularBuffer m_oBuffer; 68 | 69 | }; 70 | 71 | #endif //CONNECTION_THREAD_H 72 | -------------------------------------------------------------------------------- /SocketReceiverBase.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RECEIVER_BASE_H 2 | #define SOCKET_RECEIVER_BASE_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 include: 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 | #include "../../AVNUtilLibs/DataStructures/ThreadSafeCircularBuffer/ThreadSafeCircularBuffer.h" 32 | 33 | class cSocketReceiverBase 34 | { 35 | public: 36 | class cDataCallbackInterface 37 | { 38 | public: 39 | virtual void offloadData_callback(char* pData, uint32_t u32Size_B) = 0; 40 | }; 41 | 42 | 43 | explicit cSocketReceiverBase(const std::string &strPeerAddress, uint16_t usPeerPort = 60001); 44 | virtual ~cSocketReceiverBase(); 45 | 46 | void startReceiving(); 47 | virtual void stopReceiving(); 48 | 49 | void startCallbackOffloading(); 50 | void stopCallbackOffloading(); 51 | 52 | bool isReceivingEnabled(); 53 | bool isCallbackOffloadingEnabled(); 54 | 55 | void shutdown(); 56 | bool isShutdownRequested(); 57 | 58 | void clearBuffer(); 59 | 60 | int32_t getNextPacketSize_B(uint32_t u32Timeout_ms = 0); 61 | bool getNextPacket(char *cpData, uint32_t u32Timeout_ms = 0, bool bPopData = true); 62 | 63 | void registerDataCallbackHandler(boost::shared_ptr pNewHandler); 64 | void deregisterDataCallbackHandler(boost::shared_ptr pHandler); 65 | 66 | protected: 67 | std::string m_strPeerAddress; 68 | uint16_t m_u16PeerPort; 69 | 70 | bool m_bReceivingEnabled; 71 | bool m_bCallbackOffloadingEnabled; 72 | bool m_bShutdownFlag; 73 | boost::shared_mutex m_oFlagMutex; 74 | boost::shared_mutex m_oCallbackHandlersMutex; 75 | 76 | //Callback handlers 77 | std::vector > m_vpDataCallbackHandlers; 78 | 79 | //Threads 80 | boost::scoped_ptr m_pSocketReceivingThread; 81 | boost::scoped_ptr m_pDataOffloadingThread; 82 | 83 | //Derived class will need some sort of socket here. 84 | 85 | //Thread functions 86 | virtual void socketReceivingThreadFunction() = 0; //Implement socket receiving here 87 | void dataOffloadingThreadFunction(); 88 | 89 | int32_t m_i32GetRawDataInputBufferIndex; 90 | uint64_t u64TotalBytesProcessed; 91 | 92 | //Circular buffers 93 | cThreadSafeCircularBuffer m_oBuffer; 94 | 95 | }; 96 | 97 | #endif // SOCKET_RECEIVER_BASE_H 98 | -------------------------------------------------------------------------------- /TCPServer/TCPServer.cpp: -------------------------------------------------------------------------------- 1 | 2 | //System includes 3 | #include 4 | 5 | //Library include: 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 "TCPServer.h" 13 | 14 | cTCPServer::cTCPServer(const std::string &strInterface, uint16_t u16Port, uint32_t u32MaxConnections) : 15 | m_bShutdownFlag(false), 16 | m_u32MaxConnections(u32MaxConnections), 17 | m_strInterface(strInterface), 18 | m_u16Port(u16Port) 19 | { 20 | m_pSocketListeningThread.reset(new boost::thread(&cTCPServer::socketListeningThreadFunction, this)); 21 | } 22 | 23 | cTCPServer::~cTCPServer() 24 | { 25 | shutdown(); 26 | 27 | { 28 | boost::unique_lock oLock(m_oConnectThreadsMutex); 29 | m_vpConnectionThreads.clear(); 30 | } 31 | } 32 | 33 | void cTCPServer::shutdown() 34 | { 35 | { 36 | boost::unique_lock oLock(m_bShutdownFlagMutex); 37 | m_bShutdownFlag = true; 38 | } 39 | 40 | if(m_oTCPAcceptor.isOpen()) 41 | m_oTCPAcceptor.close(); 42 | 43 | if(m_pSocketListeningThread.get()) 44 | { 45 | m_pSocketListeningThread->join(); 46 | } 47 | } 48 | 49 | bool cTCPServer::isShutdownRequested() 50 | { 51 | boost::shared_lock oLock(m_bShutdownFlagMutex); 52 | 53 | return m_bShutdownFlag; 54 | } 55 | 56 | void cTCPServer::socketListeningThreadFunction() 57 | { 58 | uint32_t u32ConnectionNumber = 0; 59 | 60 | while(!isShutdownRequested()) 61 | { 62 | //If the listening socket exists already close it 63 | if(m_oTCPAcceptor.isOpen()) 64 | m_oTCPAcceptor.close(); 65 | 66 | //Listen for incoming connects from clients 67 | try 68 | { 69 | m_oTCPAcceptor.openAndListen(m_strInterface, m_u16Port); 70 | 71 | break; 72 | } 73 | 74 | catch(boost::system::system_error const &oSystemError) 75 | { 76 | cout << "cTCPServer::socketListeningThreadFunction(): Failed to bind to port and listen." << endl; 77 | cout << "cTCPServer::socketListeningThreadFunction(): The error was: " << oSystemError.what() << endl; 78 | cout << "cTCPServer::socketListeningThreadFunction(): Retrying in 5 s ..." << endl; 79 | boost::this_thread::sleep(boost::posix_time::milliseconds(5000)); 80 | } 81 | } 82 | 83 | cout << "cTCPServer::socketListeningThreadFunction(): Listening for TCP connections on " << m_strInterface << ":" << m_u16Port << endl; 84 | 85 | while(!isShutdownRequested()) 86 | { 87 | cout << "cTCPServer::socketListeningThreadFunction(): Listening for client connections..." << endl; 88 | 89 | std::stringstream oSS; 90 | oSS << "Connection "; 91 | oSS << u32ConnectionNumber++; 92 | 93 | boost::shared_ptr pClientSocket = boost::make_shared(oSS.str()); //A socket object to store the incoming connection 94 | try 95 | { 96 | string strPeerAddress; 97 | m_oTCPAcceptor.accept(pClientSocket, strPeerAddress); //Accept connection from a client. 98 | 99 | boost::unique_lock oLock(m_oConnectThreadsMutex); 100 | m_vpConnectionThreads.push_back(boost::make_shared(pClientSocket)); 101 | 102 | cout << "cTCPServer::socketListeningThreadFunction(): There are now " << m_vpConnectionThreads.size() << " client(s) connected." << endl; 103 | } 104 | catch(boost::system::system_error const &oSystemError) 105 | { 106 | cout << "cTCPServer::socketListeningThreadFunction(): Caught Exception on accepting incoming connection." << endl; 107 | cout << "cTCPServer::socketListeningThreadFunction(): The error was: " << oSystemError.what() << endl; 108 | continue; //Try again 109 | } 110 | 111 | } 112 | 113 | m_oTCPAcceptor.close(); 114 | 115 | cout << "cTCPServer::socketListeningThreadFunction(): Returning from thread function." << endl; 116 | } 117 | 118 | void cTCPServer::writeData(char* cpData, uint32_t u32Size_B) 119 | { 120 | boost::upgrade_lock oLock(m_oConnectThreadsMutex); 121 | 122 | for(uint32_t ui = 0; ui < m_vpConnectionThreads.size(); ui++) 123 | { 124 | //Send only to valid connections 125 | if(m_vpConnectionThreads[ui]->isValid()) 126 | m_vpConnectionThreads[ui]->tryAddDataToSend(cpData, u32Size_B); 127 | } 128 | 129 | //Clean up any invalid connections 130 | for(uint32_t ui = 0; ui < m_vpConnectionThreads.size();) 131 | { 132 | if(!m_vpConnectionThreads[ui]->isValid()) 133 | { 134 | cout << "cTCPServer::writeData(): Closing connection to client " << m_vpConnectionThreads[ui]->getPeerAddress(); 135 | if(m_vpConnectionThreads[ui]->getSocketName().length()) 136 | cout << " (" << m_vpConnectionThreads[ui]->getSocketName() << ")"; 137 | 138 | cout << endl; 139 | 140 | { 141 | boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(oLock); 142 | m_vpConnectionThreads.erase(m_vpConnectionThreads.begin() + ui); 143 | } 144 | 145 | cout << "cTCPServer::writeData(): There are now " << m_vpConnectionThreads.size() << " client(s) connected." << endl; 146 | } 147 | else 148 | { 149 | ui++; 150 | } 151 | } 152 | } 153 | 154 | 155 | -------------------------------------------------------------------------------- /UDPReceiver/UDPReceiver.cpp: -------------------------------------------------------------------------------- 1 | //System includes 2 | #include 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 "UDPReceiver.h" 13 | 14 | using namespace std; 15 | 16 | cUDPReceiver::cUDPReceiver(const string &strLocalInterface, uint16_t u16LocalPort, const string &strPeerAddress, uint16_t u16PeerPort) : 17 | cSocketReceiverBase(strPeerAddress, u16PeerPort), 18 | m_oSocket(string("UDP socket")), 19 | m_strLocalInterface(strLocalInterface), 20 | m_u16LocalPort(u16LocalPort) 21 | { 22 | m_oBuffer.resize(1024, 1040); //16 packets of 1040 bytes for each complex uint32_t FFT window of 2 channels or or I,Q,U,V uint32_t stokes parameters 23 | } 24 | 25 | cUDPReceiver::~cUDPReceiver() 26 | { 27 | //Base destructor calls shutdown. 28 | 29 | stopReceiving(); 30 | 31 | m_oSocket.close(); 32 | } 33 | 34 | void cUDPReceiver::socketReceivingThreadFunction() 35 | { 36 | cout << "Entered cUDPReceiver::socketReceivingThreadFunction()" << endl; 37 | 38 | //First attempt to bind socket 39 | 40 | //m_oUDPSocket.openBindAndConnect(m_strLocalInterface, m_u16LocalPort, m_strPeerAddress, m_u16PeerPort); 41 | while(!m_oSocket.openAndBind(m_strLocalInterface, m_u16LocalPort)) 42 | { 43 | if(isShutdownRequested() || !isReceivingEnabled()) 44 | { 45 | cout << "cUDPReceiver::socketReceivingThreadFunction(): Got shutdown flag, returning." << endl; 46 | return; 47 | } 48 | 49 | //Wait some time then try to bind again... 50 | boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); 51 | cout << "cUDPReceiver::socketReceivingThreadFunction(): Retrying socket binding to " << m_strLocalInterface << ":" << m_u16LocalPort << endl; 52 | } 53 | 54 | //Enter thread loop, repeated reading into the FIFO 55 | 56 | boost::system::error_code oEC; 57 | 58 | uint32_t u32PacketsReceived = 0; 59 | int32_t i32BytesLastRead; 60 | int32_t i32BytesLeftToRead; 61 | 62 | while(isReceivingEnabled() && !isShutdownRequested()) 63 | { 64 | //Get (or wait for) the next available element to write data to 65 | //If waiting timeout every 500 ms and check for shutdown or stop streaming flags 66 | //This prevents the program locking up in this thread. 67 | int32_t i32Index = -1; 68 | while(i32Index == -1) 69 | { 70 | i32Index = m_oBuffer.getNextWriteIndex(500); 71 | 72 | //Also check for shutdown flag 73 | if(!isReceivingEnabled() || isShutdownRequested()) 74 | { 75 | cout << "cUDPReceiver::socketReceivingThread(): Exiting receiving thread." << endl; 76 | cout << "---- Received " << u32PacketsReceived << " packets. ----" << endl; 77 | return; 78 | } 79 | } 80 | 81 | //Check that our buffer is large enough 82 | uint32_t u32UDPBytesAvailable = m_oSocket.getBytesAvailable(); 83 | if(u32UDPBytesAvailable > m_oBuffer.getElementPointer(i32Index)->allocationSize()) 84 | { 85 | cout << "cUDPReceiver::socketReceivingThread(): Warning: Input buffer element size is too small for UDP packet." << endl; 86 | cout << "Resizing to " << u32UDPBytesAvailable << " bytes" << endl; 87 | 88 | m_oBuffer.resize(m_oBuffer.getNElements(), u32UDPBytesAvailable); 89 | } 90 | 91 | //Read as many packets as can be fitted in to the buffer (it should be empty at this point) 92 | i32BytesLeftToRead = m_oBuffer.getElementPointer(i32Index)->allocationSize(); 93 | 94 | while(i32BytesLeftToRead) 95 | { 96 | string strSender; 97 | uint16_t u16Port; 98 | //if(!m_oUDPSocket.receive(m_oBuffer.getElementDataPointer(i32Index) + m_oBuffer.getElementPointer(i32Index)->dataSize(), i32BytesLeftToRead) ) 99 | if(!m_oSocket.receiveFrom(m_oBuffer.getElementDataPointer(i32Index) + m_oBuffer.getElementPointer(i32Index)->dataSize(), i32BytesLeftToRead, strSender, u16Port) ) 100 | { 101 | cout << "cUDPReceiver::socketReceivingThread(): Warning socket error: " << m_oSocket.getLastError().message() << endl; 102 | } 103 | 104 | i32BytesLastRead = m_oSocket.getNBytesLastTransferred(); 105 | 106 | 107 | u32PacketsReceived++; 108 | 109 | i32BytesLeftToRead -= i32BytesLastRead; 110 | m_oBuffer.getElementPointer(i32Index)->setDataAdded(i32BytesLastRead); 111 | 112 | //Also check for shutdown flag 113 | if(!isReceivingEnabled() || isShutdownRequested()) 114 | { 115 | cout << "cUDPReceiver::socketReceivingThread(): Exiting receiving thread." << endl; 116 | cout << "---- Received " << u32PacketsReceived << " packets. ----" << endl; 117 | return; 118 | } 119 | } 120 | 121 | //Signal we have completely filled an element of the input buffer. 122 | m_oBuffer.elementWritten(); 123 | 124 | } 125 | 126 | cout << "cUDPReceiver::socketReceivingThread(): Exiting receiving thread." << endl; 127 | cout << "---- Received " << u32PacketsReceived << " packets ----" << endl; 128 | fflush(stdout); 129 | } 130 | 131 | void cUDPReceiver::stopReceiving() 132 | { 133 | cSocketReceiverBase::stopReceiving(); 134 | 135 | //Also interrupt the socket which exists only in this derived implmentation 136 | m_oSocket.cancelCurrrentOperations(); 137 | } 138 | -------------------------------------------------------------------------------- /TCPServer/ConnectionThread.cpp: -------------------------------------------------------------------------------- 1 | 2 | //System includes 3 | #include 4 | 5 | //Library include: 6 | 7 | //Local includes 8 | #include "ConnectionThread.h" 9 | 10 | using namespace std; 11 | 12 | cConnectionThread::cConnectionThread(boost::shared_ptr pClientSocket) : 13 | m_bShutdownFlag(false), 14 | m_bIsValid(true), 15 | m_oBuffer(512, 1040) //16 packets of 1040 bytes for each complex uint32_t FFT window of 2 channels or or I,Q,U,V uint32_t stokes parameters. 16 | { 17 | m_pSocket.swap(pClientSocket); 18 | 19 | m_strPeerAddress = m_pSocket->getPeerAddress(); 20 | cout << "cConnectionThread::cConnectionThread(): Got new connection from host: " << getPeerAddress(); 21 | 22 | if(getSocketName().length()) 23 | cout << ". Socket name is \"" << getSocketName() << "\""; 24 | 25 | cout << endl; 26 | 27 | m_pSocketWritingThread.reset(new boost::thread(&cConnectionThread::socketWritingThreadFunction, this)); 28 | } 29 | 30 | cConnectionThread::~cConnectionThread() 31 | { 32 | setInvalid(); 33 | shutdown(); 34 | 35 | m_pSocket->close(); 36 | 37 | if(m_pSocketWritingThread.get()) 38 | { 39 | m_pSocketWritingThread->join(); 40 | } 41 | } 42 | 43 | void cConnectionThread::shutdown() 44 | { 45 | boost::upgrade_lock oLock(m_bShutdownFlagMutex); 46 | boost::upgrade_to_unique_lock oUniqueLock(oLock); 47 | 48 | m_bShutdownFlag = true; 49 | } 50 | 51 | bool cConnectionThread::isValid() 52 | { 53 | boost::shared_lock oLock(m_bValidMutex); 54 | 55 | return m_bIsValid; 56 | } 57 | 58 | void cConnectionThread::setInvalid() 59 | { 60 | boost::upgrade_lock oLock(m_bValidMutex); 61 | boost::upgrade_to_unique_lock oUniqueLock(oLock); 62 | 63 | m_bIsValid = false; 64 | } 65 | 66 | bool cConnectionThread::isShutdownRequested() 67 | { 68 | boost::shared_lock oLock(m_bShutdownFlagMutex); 69 | 70 | return m_bShutdownFlag; 71 | } 72 | 73 | bool cConnectionThread::tryAddDataToSend(char* cpData, uint32_t u32Size_B) 74 | { 75 | //Try to get the next free pointer. (For max 1 ms) 76 | int32_t i32Index = m_oBuffer.tryToGetNextWriteIndex(); 77 | 78 | //If the is not space in the buffer return false. 79 | if(i32Index == -1) 80 | { 81 | return false; 82 | } 83 | 84 | //Otherwise check that our buffer is large enough 85 | if(u32Size_B > m_oBuffer.getElementPointer(i32Index)->allocationSize()) 86 | { 87 | cout << "Warning: Input buffer element size is too small for UDP packet." << endl; 88 | cout << "Resizing to " << u32Size_B << " bytes" << endl; 89 | 90 | m_oBuffer.resize(m_oBuffer.getNElements(), u32Size_B); 91 | } 92 | 93 | memcpy(m_oBuffer.getElementDataPointer(i32Index), cpData, u32Size_B); 94 | m_oBuffer.getElementPointer(i32Index)->setDataAdded(u32Size_B); 95 | 96 | //Signal we have completely filled an element of the input buffer. 97 | m_oBuffer.elementWritten(); 98 | 99 | return true; 100 | } 101 | 102 | void cConnectionThread::blockingAddDataToSend(char* cpData, uint32_t u32Size_B) 103 | { 104 | //Get (or wait for) the next available element to write data to 105 | //If waiting timeout every 500 ms and check for shutdown or stop streaming flags 106 | //This prevents the program locking up in this thread. 107 | int32_t i32Index = -1; 108 | while(i32Index == -1) 109 | { 110 | i32Index = m_oBuffer.getNextWriteIndex(500); 111 | 112 | //Also check for shutdown flag 113 | if(isShutdownRequested()) 114 | { 115 | cout << "cConnectionThread::blockingAddDataToSend() exiting on detection of shutdown flag." << endl; 116 | return; 117 | } 118 | } 119 | 120 | //Check that our buffer is large enough 121 | if(u32Size_B > m_oBuffer.getElementPointer(i32Index)->allocationSize()) 122 | { 123 | cout << "cConnectionThread::blockingAddDataToSend(): Warning: Input buffer element size is too small for UDP packet." << endl; 124 | cout << "Resizing to " << u32Size_B << " bytes" << endl; 125 | 126 | m_oBuffer.resize(m_oBuffer.getNElements(), u32Size_B); 127 | } 128 | 129 | memcpy(m_oBuffer.getElementDataPointer(i32Index), cpData, u32Size_B); 130 | m_oBuffer.getElementPointer(i32Index)->setDataAdded(u32Size_B); 131 | 132 | //Signal we have completely filled an element of the input buffer. 133 | m_oBuffer.elementWritten(); 134 | } 135 | 136 | void cConnectionThread::socketWritingThreadFunction() 137 | { 138 | uint32_t u32BytesToTransfer = 0; 139 | uint32_t u32BytesTransferred = 0; 140 | int32_t i32Index = 0; 141 | bool bSuccess = false; 142 | 143 | while(!isShutdownRequested()) 144 | { 145 | //Get a new buffer element's worth of data and send it. 146 | 147 | //Get (or wait for) the next available element to read data from 148 | //If waiting timeout every 500 ms and check for shutdown or stop streaming flags 149 | //This prevents the program locking up in this thread. 150 | i32Index = -1; 151 | while(i32Index == -1) 152 | { 153 | i32Index = m_oBuffer.getNextReadIndex(500); 154 | 155 | //Also check for shutdown flag 156 | if(isShutdownRequested()) 157 | { 158 | cout << "cConnectionThread::socketWritingThreadFunction(): Shutdown requested, aborting writing next packet to peer " << m_strPeerAddress; 159 | 160 | if(getSocketName().length()) 161 | cout << " (" << getSocketName() << ")"; 162 | 163 | cout << endl; 164 | 165 | return; 166 | } 167 | } 168 | u32BytesToTransfer = m_oBuffer.getElementPointer(i32Index)->allocationSize(); 169 | u32BytesTransferred = 0; 170 | while(u32BytesToTransfer) 171 | { 172 | bSuccess = m_pSocket->send(m_oBuffer.getElementDataPointer(i32Index) + u32BytesTransferred, u32BytesToTransfer); 173 | 174 | if(!bSuccess) 175 | break; 176 | 177 | u32BytesToTransfer -= m_pSocket->getNBytesLastWritten(); 178 | u32BytesTransferred += m_pSocket->getNBytesLastWritten(); 179 | } 180 | 181 | if(!bSuccess) 182 | { 183 | cout << "cConnectionThread::socketWritingThreadFunction(): Write failed to peer " << m_strPeerAddress << ". Error was: " << m_pSocket->getLastWriteError() << endl; 184 | if(m_pSocket->getLastWriteError()) 185 | { 186 | //Mark connection as failed and stop sending data 187 | setInvalid(); 188 | return; 189 | } 190 | else 191 | { 192 | continue; //Otherwise the sending fail for other reasons e.g. timeout, try again from the beginning. 193 | } 194 | } 195 | 196 | 197 | m_oBuffer.elementRead(); //Otherwise write is complete. Signal to pop element off FIFO 198 | //cout << "cConnectionThread::socketWritingThreadFunction(): Wrote data to client " << getPeerAddress() << endl; 199 | } 200 | } 201 | 202 | string cConnectionThread::getPeerAddress() 203 | { 204 | return m_strPeerAddress; 205 | } 206 | 207 | string cConnectionThread::getSocketName() 208 | { 209 | return m_pSocket->getName(); 210 | } 211 | -------------------------------------------------------------------------------- /TCPReceiver/TCPReceiver.cpp: -------------------------------------------------------------------------------- 1 | //System includes 2 | #include 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 "TCPReceiver.h" 13 | 14 | using namespace std; 15 | 16 | cTCPReceiver::cTCPReceiver(const string &strPeerAddress, uint16_t u16PeerPort) : 17 | cSocketReceiverBase(strPeerAddress, u16PeerPort), 18 | m_oSocket(string("TCP socket")) 19 | { 20 | } 21 | 22 | cTCPReceiver::~cTCPReceiver() 23 | { 24 | stopReceiving(); 25 | } 26 | 27 | void cTCPReceiver::socketReceivingThreadFunction() 28 | { 29 | cout << "Entered cTCPReceiver::socketReceivingThreadFunction()" << endl; 30 | 31 | //First attempt to connect socket 32 | if(m_oSocket.openAndConnect(m_strPeerAddress, m_u16PeerPort)) 33 | { 34 | //Notification of socket connection 35 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 36 | 37 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers.size(); ui++) 38 | { 39 | m_vpNotificationCallbackHandlers[ui]->socketConnected_callback(); 40 | } 41 | 42 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers_shared.size(); ui++) 43 | { 44 | m_vpNotificationCallbackHandlers_shared[ui]->socketConnected_callback(); 45 | } 46 | } 47 | else 48 | { 49 | //Notification of socket connection failure 50 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 51 | 52 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers.size(); ui++) 53 | { 54 | m_vpNotificationCallbackHandlers[ui]->socketDisconnected_callback(); 55 | } 56 | 57 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers_shared.size(); ui++) 58 | { 59 | m_vpNotificationCallbackHandlers_shared[ui]->socketDisconnected_callback(); 60 | } 61 | } 62 | 63 | //Enter thread loop, repeated reading into the FIFO 64 | uint32_t u32PacketsReceived = 0; 65 | int32_t i32BytesLastRead; 66 | int32_t i32BytesLeftToRead; 67 | 68 | while(isReceivingEnabled() && !isShutdownRequested()) 69 | { 70 | //Get (or wait for) the next available element to write data to 71 | //If waiting timeout every 500 ms and check for shutdown or stop streaming flags 72 | //This prevents the program locking up in this thread. 73 | int32_t i32Index = -1; 74 | while(i32Index == -1) 75 | { 76 | i32Index = m_oBuffer.getNextWriteIndex(500); 77 | 78 | //Also check for shutdown flag 79 | if(!isReceivingEnabled() || isShutdownRequested()) 80 | { 81 | cout << "cTCPReceiver::socketReceivingThread(): Exiting receiving thread." << endl; 82 | cout << "---- Received " << u32PacketsReceived << " packets. ----" << endl; 83 | return; 84 | } 85 | } 86 | 87 | //Read as many packets as can be fitted in to the buffer (it should be empty at this point) 88 | i32BytesLeftToRead = m_oBuffer.getElementPointer(i32Index)->allocationSize(); 89 | 90 | while(i32BytesLeftToRead) 91 | { 92 | if(!m_oSocket.receive(m_oBuffer.getElementDataPointer(i32Index) + m_oBuffer.getElementPointer(i32Index)->dataSize(), i32BytesLeftToRead) ) 93 | { 94 | cout << "cTCPReceiver::socketReceivingThread(): Warning socket error: " << m_oSocket.getLastReadError().message() << endl; 95 | cout << "cTCPReceiver::socketReceivingThread(): Warning socket error value: " << m_oSocket.getLastReadError().value() << endl; 96 | 97 | //Check for errors from socket disconnection 98 | //TODO: This should probably be done with error codes as apposed string matching 99 | 100 | if(m_oSocket.getLastReadError().message().find("End of file") != string::npos 101 | || m_oSocket.getLastReadError().message().find("Bad file descriptor") != string::npos ) 102 | { 103 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 104 | 105 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers.size(); ui++) 106 | { 107 | m_vpNotificationCallbackHandlers[ui]->socketDisconnected_callback(); 108 | } 109 | 110 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers_shared.size(); ui++) 111 | { 112 | m_vpNotificationCallbackHandlers_shared[ui]->socketDisconnected_callback(); 113 | } 114 | 115 | cout << "cTCPReceiver::socketReceivingThread(): socket disconnected." << endl; 116 | stopReceiving(); 117 | m_oSocket.close(); 118 | break; 119 | } 120 | } 121 | 122 | i32BytesLastRead = m_oSocket.getNBytesLastRead(); 123 | 124 | u32PacketsReceived++; 125 | 126 | i32BytesLeftToRead -= i32BytesLastRead; 127 | m_oBuffer.getElementPointer(i32Index)->setDataAdded(i32BytesLastRead); 128 | 129 | //Also check for shutdown flag 130 | if(!isReceivingEnabled() || isShutdownRequested()) 131 | { 132 | cout << "cTCPReceiver::socketReceivingThread(): Exiting receiving thread." << endl; 133 | cout << "---- Received " << u32PacketsReceived << " packets. ----" << endl; 134 | return; 135 | } 136 | } 137 | //Signal we have completely filled an element of the input buffer. 138 | m_oBuffer.elementWritten(); 139 | } 140 | 141 | cout << "cTCPReceiver::socketReceivingThread(): Exiting receiving thread." << endl; 142 | cout << "---- Received " << u32PacketsReceived << " packets ----" << endl; 143 | fflush(stdout); 144 | } 145 | 146 | void cTCPReceiver::stopReceiving() 147 | { 148 | cSocketReceiverBase::stopReceiving(); 149 | 150 | //Also interrupt the socket which exists only in this derived implmentation 151 | m_oSocket.cancelCurrrentOperations(); 152 | } 153 | 154 | void cTCPReceiver::registerNoticationCallbackHandler(cNotificationCallbackInterface* pNewHandler) 155 | { 156 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 157 | 158 | m_vpNotificationCallbackHandlers.push_back(pNewHandler); 159 | 160 | cout << "cTCPReceiver::registerNoticationCallbackHandler(): Successfully registered callback handler: " << pNewHandler << endl; 161 | } 162 | 163 | void cTCPReceiver::registerNoticationCallbackHandler(boost::shared_ptr pNewHandler) 164 | { 165 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 166 | 167 | m_vpNotificationCallbackHandlers_shared.push_back(pNewHandler); 168 | 169 | cout << "cTCPReceiver::registerNoticationCallbackHandler(): Successfully registered callback handler: " << pNewHandler.get() << endl; 170 | } 171 | 172 | void cTCPReceiver::deregisterNotificationCallbackHandler(cNotificationCallbackInterface* pHandler) 173 | { 174 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 175 | bool bSuccess = false; 176 | 177 | //Search for matching pointer values and erase 178 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers.size();) 179 | { 180 | if(m_vpNotificationCallbackHandlers[ui] == pHandler) 181 | { 182 | m_vpNotificationCallbackHandlers.erase(m_vpNotificationCallbackHandlers.begin() + ui); 183 | 184 | cout << "cTCPReceiver::deregisterNotificationCallbackHandler(): Deregistered callback handler: " << pHandler << endl; 185 | bSuccess = true; 186 | } 187 | else 188 | { 189 | ui++; 190 | } 191 | } 192 | 193 | if(!bSuccess) 194 | { 195 | cout << "cTCPReceiver::deregisterNotificationCallbackHandler(): Warning: Deregistering callback handler: " << pHandler << " failed. Object instance not found." << endl; 196 | } 197 | } 198 | 199 | void cTCPReceiver::deregisterNotificationCallbackHandler(boost::shared_ptr pHandler) 200 | { 201 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 202 | bool bSuccess = false; 203 | 204 | //Search for matching pointer values and erase 205 | for(uint32_t ui = 0; ui < m_vpNotificationCallbackHandlers_shared.size();) 206 | { 207 | if(m_vpNotificationCallbackHandlers_shared[ui].get() == pHandler.get()) 208 | { 209 | m_vpNotificationCallbackHandlers_shared.erase(m_vpNotificationCallbackHandlers_shared.begin() + ui); 210 | 211 | cout << "cTCPReceiver::deregisterNotificationCallbackHandler(): Deregistered callback handler: " << pHandler.get() << endl; 212 | bSuccess = true; 213 | } 214 | else 215 | { 216 | ui++; 217 | } 218 | } 219 | 220 | if(!bSuccess) 221 | { 222 | cout << "cTCPReceiver::deregisterNotificationCallbackHandler(): Warning: Deregistering callback handler: " << pHandler.get() << " failed. Object instance not found." << endl; 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /SocketReceiverBase.cpp: -------------------------------------------------------------------------------- 1 | //System includes 2 | #include 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 "SocketReceiverBase.h" 13 | 14 | using namespace std; 15 | 16 | cSocketReceiverBase::cSocketReceiverBase(const string &strPeerAddress, uint16_t u16PeerPort) : 17 | m_strPeerAddress(strPeerAddress), 18 | m_u16PeerPort(u16PeerPort), 19 | m_bReceivingEnabled(false), 20 | m_bCallbackOffloadingEnabled(false), 21 | m_bShutdownFlag(false), 22 | m_pSocketReceivingThread(NULL), 23 | m_pDataOffloadingThread(NULL), 24 | m_i32GetRawDataInputBufferIndex(-1), 25 | m_oBuffer(1024, 1040) 26 | { 27 | } 28 | 29 | cSocketReceiverBase::~cSocketReceiverBase() 30 | { 31 | shutdown(); 32 | } 33 | 34 | void cSocketReceiverBase::clearBuffer() 35 | { 36 | m_oBuffer.clear(); 37 | } 38 | 39 | void cSocketReceiverBase::startReceiving() 40 | { 41 | cout << "cSocketReceiverBase::startReceiving()" << endl; 42 | 43 | u64TotalBytesProcessed = 0; 44 | 45 | { 46 | boost::unique_lock oLock(m_oFlagMutex); 47 | m_bReceivingEnabled = true; 48 | } 49 | 50 | m_i32GetRawDataInputBufferIndex = -1; 51 | 52 | clearBuffer(); 53 | 54 | m_pSocketReceivingThread.reset(new boost::thread(&cSocketReceiverBase::socketReceivingThreadFunction, this)); 55 | } 56 | 57 | void cSocketReceiverBase::stopReceiving() 58 | { 59 | cout << "cSocketReceiverBase::stopReceiving()" << endl; 60 | 61 | boost::unique_lock oLock(m_oFlagMutex); 62 | m_bReceivingEnabled = false; 63 | } 64 | 65 | void cSocketReceiverBase::startCallbackOffloading() 66 | { 67 | cout << "cSocketReceiverBase::startCallbackOffloading()" << endl; 68 | 69 | { 70 | boost::unique_lock oLock(m_oFlagMutex); 71 | m_bCallbackOffloadingEnabled = true; 72 | } 73 | 74 | m_i32GetRawDataInputBufferIndex = -1; 75 | 76 | clearBuffer(); 77 | 78 | m_pSocketReceivingThread.reset(new boost::thread(&cSocketReceiverBase::dataOffloadingThreadFunction, this)); 79 | } 80 | 81 | void cSocketReceiverBase::stopCallbackOffloading() 82 | { 83 | //Thread safe flag mutator 84 | 85 | cout << "cSocketReceiverBase::stopCallbackOffloading()" << endl; 86 | 87 | boost::unique_lock oLock(m_oFlagMutex); 88 | m_bCallbackOffloadingEnabled = false; 89 | } 90 | 91 | bool cSocketReceiverBase::isReceivingEnabled() 92 | { 93 | //Thread safe accessor 94 | 95 | boost::shared_lock oLock(m_oFlagMutex); 96 | return m_bReceivingEnabled; 97 | } 98 | 99 | bool cSocketReceiverBase::isCallbackOffloadingEnabled() 100 | { 101 | //Thread safe accessor 102 | 103 | boost::shared_lock oLock(m_oFlagMutex); 104 | return m_bCallbackOffloadingEnabled; 105 | } 106 | 107 | void cSocketReceiverBase::shutdown() 108 | { 109 | //Thread safe flag mutator 110 | 111 | { 112 | boost::unique_lock oLock(m_oFlagMutex); 113 | m_bShutdownFlag = true; 114 | } 115 | 116 | if(m_pSocketReceivingThread.get()) 117 | { 118 | m_pSocketReceivingThread->join(); 119 | } 120 | 121 | if(m_pDataOffloadingThread.get()) 122 | { 123 | m_pDataOffloadingThread->join(); 124 | } 125 | } 126 | 127 | bool cSocketReceiverBase::isShutdownRequested() 128 | { 129 | //Thread safe accessor 130 | 131 | boost::shared_lock oLock(m_oFlagMutex); 132 | return m_bShutdownFlag; 133 | } 134 | 135 | int32_t cSocketReceiverBase::getNextPacketSize_B(uint32_t u32Timeout_ms) 136 | { 137 | //Get (or wait for) the next available element to read data from 138 | //If waiting, timeout every 500 ms and check for shutdown or stop streaming flags 139 | //This prevents the program locking up in this thread. 140 | 141 | //Current time: 142 | boost::posix_time::ptime oStartTime = boost::posix_time::microsec_clock::local_time(); 143 | 144 | int32_t i32Index = -1; 145 | while(i32Index == -1) 146 | { 147 | boost::posix_time::time_duration oDuration = boost::posix_time::microsec_clock::local_time() - oStartTime; 148 | if(u32Timeout_ms && oDuration.total_milliseconds() >= u32Timeout_ms) 149 | { 150 | cout << "cSocketReceiverBase::getNextPacketSize_B(): Hit caller specified timeout. Returning." << endl; 151 | return -1; 152 | } 153 | 154 | i32Index = m_oBuffer.getNextReadIndex(100); 155 | 156 | } 157 | 158 | return m_oBuffer.getElementPointer(i32Index)->allocationSize(); 159 | } 160 | 161 | bool cSocketReceiverBase::getNextPacket(char *cpData, uint32_t u32Timeout_ms, bool bPopData) 162 | { 163 | //By setting pop data to false this function can be used to peek into the front of the queue. Otherwise it reads 164 | //data off the queue by default. Note bPopData = true should probably not be used concurrently with callback based 165 | //offloading as this will results in inconsistent data distribution. 166 | 167 | //Note cpData should be of sufficient size to store data. Check with getNextPacketSize_B() 168 | 169 | //Get (or wait for) the next available element to read data from 170 | //If waiting timeout every 100 ms and check for shutdown or stop streaming flags 171 | //This prevents the program locking up in this thread. 172 | 173 | //Current time: 174 | boost::posix_time::ptime oStartTime = boost::posix_time::microsec_clock::local_time(); 175 | 176 | int32_t i32Index = -1; 177 | while(i32Index == -1) 178 | { 179 | boost::posix_time::time_duration oDuration = boost::posix_time::microsec_clock::local_time() - oStartTime; 180 | if(u32Timeout_ms && oDuration.total_milliseconds() >= u32Timeout_ms) 181 | { 182 | cout << "cSocketReceiverBase::getNextPacket(): Hit caller specified timeout. Returning." << endl; 183 | return false; 184 | } 185 | 186 | i32Index = m_oBuffer.getNextReadIndex(100); 187 | 188 | if(i32Index == -1) 189 | cout << "Got semaphore timeout." << endl; 190 | 191 | //Also check for shutdown flag 192 | if(!isReceivingEnabled() || isShutdownRequested()) 193 | { 194 | cout << "cSocketReceiverBase::getNextPacket(): Got stop flag. Aborting..." << endl; 195 | return false; 196 | } 197 | } 198 | 199 | memcpy(cpData, m_oBuffer.getElementDataPointer(i32Index), m_oBuffer.getElementPointer(i32Index)->allocationSize()); 200 | 201 | if(bPopData) 202 | { 203 | if(m_bCallbackOffloadingEnabled) 204 | { 205 | cout << "cSocketReceiverBase::getNextPacket(): Warning. Popping data while callback offloading is enabled. Data may be insistency distributed amongst destinations." << endl; 206 | } 207 | m_oBuffer.elementRead(); //Signal to pop element off FIFO 208 | } 209 | 210 | return true; 211 | } 212 | 213 | void cSocketReceiverBase::dataOffloadingThreadFunction() 214 | { 215 | cout << "Entered cSocketReceiverBase::dataOffloadingThreadFuncton()." << endl; 216 | 217 | while(isCallbackOffloadingEnabled() && !isShutdownRequested()) 218 | { 219 | //Get (or wait for) the next available element to read data from 220 | //If waiting timeout every 500 ms and check for shutdown or stop streaming flags 221 | //This prevents the program locking up in this thread. 222 | int32_t i32Index = -1; 223 | while(i32Index == -1) 224 | { 225 | i32Index = m_oBuffer.getNextReadIndex(500); 226 | 227 | //Also check for shutdown flag 228 | if(!m_bCallbackOffloadingEnabled || isShutdownRequested()) 229 | { 230 | cout << "cSocketReceiverBase::dataOffloadingThreadFunction(): Got stop flag. Aborting..." << endl; 231 | return; 232 | } 233 | } 234 | 235 | { 236 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 237 | 238 | for(uint32_t ui = 0; ui < m_vpDataCallbackHandlers.size(); ui++) 239 | { 240 | m_vpDataCallbackHandlers[ui]->offloadData_callback(m_oBuffer.getElementDataPointer(i32Index), m_oBuffer.getElementPointer(i32Index)->allocationSize()); 241 | } 242 | } 243 | 244 | m_oBuffer.elementRead(); //Signal to pop element off FIFO 245 | } 246 | 247 | cout << "Exiting cSocketReceiverBase::dataOffloadingThreadFunction()." << endl; 248 | } 249 | 250 | void cSocketReceiverBase::registerDataCallbackHandler(boost::shared_ptr pNewHandler) 251 | { 252 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 253 | 254 | m_vpDataCallbackHandlers.push_back(pNewHandler); 255 | 256 | cout << "cSocketReceiverBase::registerDataCallbackHandler(): Successfully registered callback handler: " << pNewHandler.get() << endl; 257 | } 258 | 259 | void cSocketReceiverBase::deregisterDataCallbackHandler(boost::shared_ptr pHandler) 260 | { 261 | boost::unique_lock oLock(m_oCallbackHandlersMutex); 262 | bool bSuccess = false; 263 | 264 | //Search for matching pointer values and erase 265 | for(uint32_t ui = 0; ui < m_vpDataCallbackHandlers.size();) 266 | { 267 | if(m_vpDataCallbackHandlers[ui].get() == pHandler.get()) 268 | { 269 | m_vpDataCallbackHandlers.erase(m_vpDataCallbackHandlers.begin() + ui); 270 | 271 | cout << "cSocketReceiverBase::deregisterDataCallbackHandler(): Deregistered callback handler: " << pHandler.get() << endl; 272 | bSuccess = true; 273 | } 274 | else 275 | { 276 | ui++; 277 | } 278 | } 279 | 280 | if(!bSuccess) 281 | { 282 | cout << "cSocketReceiverBase::deregisterDataCallbackHandler(): Warning: Deregistering callback handler: " << pHandler.get() << " failed. Object instance not found." << endl; 283 | } 284 | } 285 | --------------------------------------------------------------------------------