/** * * This class demonstrates use of the CommonC++ SocketPort class. * * Copyright 2001 - Nick Liebmann * * This sample code is distributed under the same terms and conditions of the CommonC++ library. */ #include #ifdef CCXX_NAMESPACES using namespace ost; using namespace std; #endif #define MAX_RXBUF 32768 /**< Specifies the maximum number of bytes in a 'packet' */ #define MAX_RXTIMEOUT 10000 /**< Specifies how long we will wait for a complete packet */ #define DISCONNECT_MS 500 /**< Specifies the timeout for the diconnect timer */ class SampleSocketPort : public SocketPort { public: SampleSocketPort(SocketService *pService, TCPSocket & tcpSocket); virtual ~SampleSocketPort(); /** * Overridden from class SocketPort. * Called when data is available in the receive buffer. */ virtual void pending(); /** * Overridden from class SocketPort. * Called when the socket has been disconnected from the client-side. * Under some conditions this function is NOT called, which is why we have * some additional disconnection functionality within pending(). */ virtual void disconnect(void); /** * Overridden from class SocketPort. * This function is called by the system when our timer expires. * We use the timer for 2 things: * 1) To determine whether reception has timed out. (Timer started in pending()) * 2) To call CloseInterface to safely destroy the port. */ virtual void expired(void); /** * This function will send the specified number of bytes, or the whole string * (without the terminating '\0') */ bool WriteData(const char *szTxData, const size_t nByteCount = -1); /** * Our function to provide uniform closure of the Socket. * Can be called from the outside! */ bool CloseSocket(void); /** * This function should be called from pending() when the first bytes of our * data has been received. If the complete data has not been received by the time * this expires we consider this an error. * */ void ResetReadTimeout(timeout_t timeout) { m_bTimedOut = false; setTimer(timeout); } /** * This function should be use in the event of a reception error, to flush out * the receive buffer. */ void FlushRxData(void) { while(receive(m_pBuf, MAX_RXBUF) > 0); cerr << "FLUSHED" << endl; } /* * Some virtual function placeholders..... */ /** * This function is called just before the port is closed. * Do not send any data from this function! */ virtual void OnConnectionClosed(void) { cerr << "Connection Closed!" << endl; } /** * Called when the receive timeout occurs */ virtual void OnRxTimeout(void) { cerr << "Receive timeout occurred" << endl; FlushRxData(); } /** * Called when a 'packet' of data has been received. */ virtual void OnDataReceived(char *pszData, unsigned int nByteCount) { } protected: bool m_bOpen; /**< Flag set to true while Socket is open */ bool m_bDoDisconnect; /**< Flag set to true when disconnection event has occurred */ bool m_bTimedOut; /**< Flag set to true when reception has timed out */ bool m_bReceptionStarted; /**< Flag set to true when the first bytes of a transmission have arrived */ int m_nLastBytesAvail; /**< Count of last number of bytes received in pending() */ char *m_pBuf; /**< Buffer used to store received data for parsing */ /** * Little utility function for sending data to the client. * @return Number of bytes sent to client */ ssize_t DoSend(void *buf, size_t len); }; /* * This class implements a Thread that manages a SocketService. Simply * create an instance of this class with the specified address and port, and * signal the semaphore when you want it to start. * * A new SampleSocketPort object will be created for every connection that arrives. * */ class SampleSocketServiceServer : public virtual TCPSocket, public virtual Thread { public: SampleSocketServiceServer(InetHostAddress & machine, int port) : TCPSocket(machine, port), Thread(), m_bQuitServer(true) { m_pSocketService = new SocketService(0); //IMPORTANT SOCKET SERVICE MUST NOW BE EXPLICITLY STARTED m_pSocketService->start(); } virtual ~SampleSocketServiceServer() { terminate(); delete m_pSocketService; } virtual void run(void) { waitMutex.enterMutex(); m_bQuitServer = false; while(!m_bQuitServer) { try { // new does all the work to accept a new connection // and attach itself to the SocketService. CreateSocketPort(m_pSocketService, *((TCPSocket *)this)); } catch ( ... ) { // Bummer - there was an error. cerr << "SampleSocketPort create failed\n"; exit(); } } waitMutex.leaveMutex(); } /** * This abstract function is used to create a SocketPort of the desired type. */ virtual SocketPort *CreateSocketPort(SocketService *pService, TCPSocket & Socket) = 0; virtual void StartServer() { m_bQuitServer = true; start(); while(m_bQuitServer) { Thread::yield(); } } /** * If the server is not stopped like this then the SocketPort created in CreateSocketPort * is leaked. This allows it to complete construction, and be deleted cleanly. */ virtual void StopServer() { m_bQuitServer = true; InetHostAddress host; tpport_t port; host = getLocal(&port); //This is required so that CreateSocketPort can return. TCPStream strm(host, port); waitMutex.enterMutex(); waitMutex.leaveMutex(); } protected: SocketService *m_pSocketService; bool m_bQuitServer; Mutex waitMutex; private: };