blob: 3f07d0f3175ade9f33ebbd7d94bc54f64cfcf0bd [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001/**
2 *
3 * This class demonstrates use of the CommonC++ SocketPort class.
4 *
5 * Copyright 2001 - Nick Liebmann <nick@ukmail.org>
6 *
7 * This sample code is distributed under the same terms and conditions of the CommonC++ library.
8 */
9
10#include <cc++/socketport.h>
11
12#ifdef CCXX_NAMESPACES
13using namespace ost;
14using namespace std;
15#endif
16
17#define MAX_RXBUF 32768 /**< Specifies the maximum number of bytes in a 'packet' */
18#define MAX_RXTIMEOUT 10000 /**< Specifies how long we will wait for a complete packet */
19#define DISCONNECT_MS 500 /**< Specifies the timeout for the diconnect timer */
20
21class SampleSocketPort : public SocketPort
22{
23public:
24 SampleSocketPort(SocketService *pService, TCPSocket & tcpSocket);
25 virtual ~SampleSocketPort();
26
27 /**
28 * Overridden from class SocketPort.
29 * Called when data is available in the receive buffer.
30 */
31 virtual void pending();
32
33 /**
34 * Overridden from class SocketPort.
35 * Called when the socket has been disconnected from the client-side.
36 * Under some conditions this function is NOT called, which is why we have
37 * some additional disconnection functionality within pending().
38 */
39 virtual void disconnect(void);
40
41 /**
42 * Overridden from class SocketPort.
43 * This function is called by the system when our timer expires.
44 * We use the timer for 2 things:
45 * 1) To determine whether reception has timed out. (Timer started in pending())
46 * 2) To call CloseInterface to safely destroy the port.
47 */
48 virtual void expired(void);
49
50
51 /**
52 * This function will send the specified number of bytes, or the whole string
53 * (without the terminating '\0')
54 */
55 bool WriteData(const char *szTxData, const size_t nByteCount = -1);
56
57 /**
58 * Our function to provide uniform closure of the Socket.
59 * Can be called from the outside!
60 */
61 bool CloseSocket(void);
62
63 /**
64 * This function should be called from pending() when the first bytes of our
65 * data has been received. If the complete data has not been received by the time
66 * this expires we consider this an error.
67 *
68 */
69 void ResetReadTimeout(timeout_t timeout) {
70 m_bTimedOut = false;
71 setTimer(timeout);
72 }
73
74 /**
75 * This function should be use in the event of a reception error, to flush out
76 * the receive buffer.
77 */
78 void FlushRxData(void) {
79 while(receive(m_pBuf, MAX_RXBUF) > 0);
80 cerr << "FLUSHED" << endl;
81 }
82
83
84 /*
85 * Some virtual function placeholders.....
86 */
87
88 /**
89 * This function is called just before the port is closed.
90 * Do not send any data from this function!
91 */
92 virtual void OnConnectionClosed(void) {
93 cerr << "Connection Closed!" << endl;
94 }
95 /**
96 * Called when the receive timeout occurs
97 */
98 virtual void OnRxTimeout(void) {
99 cerr << "Receive timeout occurred" << endl;
100 FlushRxData();
101 }
102 /**
103 * Called when a 'packet' of data has been received.
104 */
105 virtual void OnDataReceived(char *pszData, unsigned int nByteCount) {
106 }
107protected:
108 bool m_bOpen; /**< Flag set to true while Socket is open */
109 bool m_bDoDisconnect; /**< Flag set to true when disconnection event has occurred */
110 bool m_bTimedOut; /**< Flag set to true when reception has timed out */
111 bool m_bReceptionStarted; /**< Flag set to true when the first bytes of a transmission have arrived */
112 int m_nLastBytesAvail; /**< Count of last number of bytes received in pending() */
113 char *m_pBuf; /**< Buffer used to store received data for parsing */
114
115 /**
116 * Little utility function for sending data to the client.
117 * @return Number of bytes sent to client
118 */
119 ssize_t DoSend(void *buf, size_t len);
120};
121
122
123/*
124 * This class implements a Thread that manages a SocketService. Simply
125 * create an instance of this class with the specified address and port, and
126 * signal the semaphore when you want it to start.
127 *
128 * A new SampleSocketPort object will be created for every connection that arrives.
129 *
130 */
131
132class SampleSocketServiceServer : public virtual TCPSocket, public virtual Thread
133{
134public:
135 SampleSocketServiceServer(InetHostAddress & machine, int port) :
136 TCPSocket(machine, port), Thread(), m_bQuitServer(true) {
137 m_pSocketService = new SocketService(0);
138
139 //IMPORTANT SOCKET SERVICE MUST NOW BE EXPLICITLY STARTED
140 m_pSocketService->start();
141 }
142
143 virtual ~SampleSocketServiceServer()
144 { terminate(); delete m_pSocketService; }
145
146 virtual void run(void) {
147 waitMutex.enterMutex();
148 m_bQuitServer = false;
149 while(!m_bQuitServer) {
150 try {
151 // new does all the work to accept a new connection
152 // and attach itself to the SocketService.
153 CreateSocketPort(m_pSocketService, *((TCPSocket *)this));
154 }
155 catch ( ... ) {
156 // Bummer - there was an error.
157 cerr << "SampleSocketPort create failed\n";
158 exit();
159 }
160 }
161 waitMutex.leaveMutex();
162 }
163 /**
164 * This abstract function is used to create a SocketPort of the desired type.
165 */
166 virtual SocketPort *CreateSocketPort(SocketService *pService, TCPSocket & Socket) = 0;
167 virtual void StartServer() {
168 m_bQuitServer = true;
169 start();
170 while(m_bQuitServer) {
171 Thread::yield();
172 }
173 }
174
175 /**
176 * If the server is not stopped like this then the SocketPort created in CreateSocketPort
177 * is leaked. This allows it to complete construction, and be deleted cleanly.
178 */
179 virtual void StopServer() {
180 m_bQuitServer = true;
181
182 InetHostAddress host;
183 tpport_t port;
184 host = getLocal(&port);
185
186 //This is required so that CreateSocketPort can return.
187 TCPStream strm(host, port);
188
189 waitMutex.enterMutex();
190 waitMutex.leaveMutex();
191 }
192protected:
193 SocketService *m_pSocketService;
194 bool m_bQuitServer;
195 Mutex waitMutex;
196private:
197};
198