| /** |
| * |
| * This class demonstrates use of the CommonC++ SocketPort class. |
| * |
| * Copyright 2001 - Nick Liebmann <nick@ukmail.org> |
| * |
| * This sample code is distributed under the same terms and conditions of the CommonC++ library. |
| */ |
| |
| #include <cc++/socketport.h> |
| |
| #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: |
| }; |
| |