1 //
2 // The contents of this file are subject to the Mozilla Public
3 // License Version 1.1 (the "License"); you may not use this file
4 // except in compliance with the License. You may obtain a copy of
5 // the License at http://www.mozilla.org/MPL/
6 //
7 // Software distributed under the License is distributed on an "AS
8 // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 // implied. See the License for the specific language governing
10 // rights and limitations under the License.
11 //
12 // The Original Code is State Machine Compiler (SMC).
13 //
14 // The Initial Developer of the Original Code is Charles W. Rapp.
15 // Portions created by Charles W. Rapp are
16 // Copyright (C) 2000 - 2003 Charles W. Rapp.
17 // All Rights Reserved.
18 //
19 // Contributor(s):
20 //
21 // Name
22 // AppClient.cpp
23 //
24 // Description
25 // TcpClient listener object.
26 //
27 // RCS ID
28 // $Id: AppClient.cpp,v 1.5 2005/05/28 13:31:18 cwrapp Exp $
29 //
30 // CHANGE LOG
31 // $Log: AppClient.cpp,v $
32 // Revision 1.5 2005/05/28 13:31:18 cwrapp
33 // Updated C++ examples.
34 //
35 // Revision 1.0 2003/12/14 19:34:34 charlesr
36 // Initial revision
37 //
38
39 #include "AppClient.h"
40 #include "AppServer.h"
41 #include "Eventloop.h"
42 #if defined(WIN32)
43 #include <winsock2.h>
44 #include <iostream>
45 #include <time.h>
46 #else
47 #include <arpa/inet.h>
48 #endif
49 #include <stdlib.h>
50 #include <memory.h>
51
52 using namespace std;
53
54 // Externally defined global variables.
55 extern Eventloop *Gevent_loop;
56
57 // Class variables.
58 int AppClient::_initFlag = 0;
59 const long AppClient::MIN_SLEEP_TIME = 100;
60 const long AppClient::MAX_SLEEP_TIME = 30000;
61
62 //---------------------------------------------------------------
63 // AppClient() (Public)
64 // Default constructor.
65 //
AppClient()66 AppClient::AppClient()
67 : _client_socket(NULL),
68 _owner(NULL),
69 _messageCount(0),
70 _host(NULL)
71 {}
72
73 //---------------------------------------------------------------
74 // AppClient(const char*, TcpClient&, AppServer&) (Public)
75 // An "accept" construct.
76 //
AppClient(const char * host,TcpClient & tcp_client,AppServer & owner)77 AppClient::AppClient(const char *host,
78 TcpClient& tcp_client,
79 AppServer& owner)
80 : _client_socket(&tcp_client),
81 _owner(&owner),
82 _messageCount(0),
83 _host(NULL)
84 {
85 // Store away the host name.
86 _host = new char[strlen(host) + 1];
87 (void) strcpy(_host, host);
88
89 // Tell the client that this object is now listening to it.
90 tcp_client.setListener(*this);
91
92 // Since this client is already connected, set the
93 // random transmit timer.
94 setTransmitTimer();
95 return;
96 } // end of AppClient::AppClient(TcpClient&, AppServer&)
97
98 //---------------------------------------------------------------
99 // ~AppClient() (Public)
100 // Destructor.
101 //
~AppClient()102 AppClient::~AppClient()
103 {
104 if (_client_socket != NULL)
105 {
106 delete _client_socket;
107 _client_socket = NULL;
108 }
109
110 if (_host != NULL)
111 {
112 delete[] _host;
113 _host = NULL;
114 }
115
116 return;
117 } // end of AppClient::~AppClient()
118
119 //---------------------------------------------------------------
120 // getHost() const (Public)
121 // Return the host name.
122 //
getHost() const123 const char* AppClient::getHost() const
124 {
125 return(_host);
126 } // end of AppClient::getHost() const
127
128 //---------------------------------------------------------------
129 // open(const char*, const sockaddr_in&) (Public)
130 // Open a connection to the named TCP service.
131 //
open(const char * host,const sockaddr_in & address)132 void AppClient::open(const char *host, const sockaddr_in& address)
133 {
134 if (_client_socket == NULL)
135 {
136 // Store away the host name.
137 _host = new char[strlen(host) + 1];
138 (void) strcpy(_host, host);
139
140 cout << "Opening connection to "
141 << host
142 << ":"
143 << ntohs(address.sin_port)
144 << " ... ";
145
146 // Create the client object and open it.
147 _client_socket = new TcpClient(*this);
148 _client_socket->open(address);
149 }
150
151 return;
152 } // end of AppClient::open(const char*, const sockaddr_in&)
153
154 //---------------------------------------------------------------
155 // close() (Public)
156 // Close the client connection.
157 //
close()158 void AppClient::close()
159 {
160 if (_client_socket != NULL)
161 {
162 cout << "Closing connection to "
163 << _host
164 << ":"
165 << ntohs((_client_socket->getServerAddress()).sin_port)
166 << " ... ";
167
168 _client_socket->doClose();
169 }
170
171 return;
172 } // end of AppClient::close()
173
174 //---------------------------------------------------------------
175 // opened(TcpConnection&) (Public)
176 // TCP client connection successful.
177 //
opened(TcpConnection &)178 void AppClient::opened(TcpConnection&)
179 {
180 const sockaddr_in& address = _client_socket->getServerAddress();
181
182 cout << "open successful." << endl;
183
184 // Set the transmit timer.
185 setTransmitTimer();
186
187 return;
188 } // end of AppClient::opened(TcpConnection&)
189
190 //---------------------------------------------------------------
191 // openFailed(const char*, TcpConnection&) (Public)
192 // TCP client connection failed.
193 //
openFailed(const char * reason,TcpConnection &)194 void AppClient::openFailed(const char *reason, TcpConnection&)
195 {
196 const sockaddr_in& address = _client_socket->getServerAddress();
197
198 void socketClosed();
199
200 cout << "open failed";
201 if (reason == NULL)
202 {
203 cout << "." << endl;
204 }
205 else
206 {
207 cout << " - "
208 << reason
209 << endl;
210 }
211
212 // Let the application know that the socket is closed.
213 socketClosed();
214
215 return;
216 } // end of AppClient::openFailed(const char*, TcpConnection&)
217
218 //---------------------------------------------------------------
219 // transmitted(TcpConnection&) (Public)
220 // Data successfully transmitted.
221 //
transmitted(TcpConnection &)222 void AppClient::transmitted(TcpConnection&)
223 {
224 // Set the timer for the next transmission.
225 setTransmitTimer();
226
227 cout << "transmit successful." << endl;
228 return;
229 } // end of AppClient::transmitted(TcpConnection&)
230
231 //---------------------------------------------------------------
232 // transmitFailed(const char*, TcpConnection&) (Public)
233 // Failed to send data to far-end.
234 //
transmitFailed(const char * reason,TcpConnection &)235 void AppClient::transmitFailed(const char *reason, TcpConnection&)
236 {
237 cout << "transmit failed - " << reason << "." << endl;
238 return;
239 } // end of AppClient::transmitFailed(const char*, TcpConnection&)
240
241 //---------------------------------------------------------------
242 // receive(const char*, int, TcpConnection&) (Public)
243 // Received data from far end.
244 //
receive(const char * data,int size,TcpConnection &)245 void AppClient::receive(const char *data,
246 int size,
247 TcpConnection&)
248 {
249 const sockaddr_in& address = _client_socket->getServerAddress();
250 char *string = new char[size + 1];
251
252 // Turn the data into a string.
253 (void) memcpy(string, data, size);
254 string[size] = '\0';
255
256 cout << "Received data from "
257 << inet_ntoa(address.sin_addr)
258 << ":"
259 << ntohs(address.sin_port)
260 << ": \""
261 << string
262 << "\""
263 << endl;
264
265 delete[] string;
266
267 return;
268 } // end of AppClient::receive(const char*, int, TcpConnection&)
269
270 //---------------------------------------------------------------
271 // halfClosed(TcpConnection&) (Public)
272 // This far end has closed its connection. Close down this side.
273 //
halfClosed(TcpConnection &)274 void AppClient::halfClosed(TcpConnection&)
275 {
276 const sockaddr_in& address = _client_socket->getServerAddress();
277
278 cout << "Connection from "
279 << _host
280 << ":"
281 << address.sin_port
282 << " has closed its side.\nClosing connection to "
283 << _host
284 << ":"
285 << ntohs(address.sin_port)
286 << " ... ";
287
288 // Stop the transmit timer if running.
289 Gevent_loop->stopTimer("TRANSMIT_TIMER", *this);
290
291 // When this timer expires, close this end of the connection,
292 // after waiting one millisecond.
293 Gevent_loop->startTimer("CLOSE_TIMER", 1, *this);
294
295 return;
296 } // end of AppClient::halfClosed(TcpConnection&)
297
298 //---------------------------------------------------------------
299 // closed(const char*, TcpConnection&) (Public)
300 // This client connection is closed.
301 //
closed(const char * reason,TcpConnection &)302 void AppClient::closed(const char *reason, TcpConnection&)
303 {
304 const sockaddr_in& address =
305 _client_socket->getServerAddress();
306
307 void socketClosed();
308
309 cout << "closed." << endl;
310
311 // Stop the transmit timer if running.
312 Gevent_loop->stopTimer("TRANSMIT_TIMER", *this);
313
314 // If this is an accepted connection, tell the service owner
315 // that this connection is gone.
316 if (_owner != NULL)
317 {
318 _owner->clientClosed(*this);
319 }
320 else
321 {
322 // Tell the client application that this connection is
323 // closed.
324 socketClosed();
325 }
326
327 return;
328 } // end of AppClient::closed(const char*, TcpConnection&)
329
330 //---------------------------------------------------------------
331 // handleTimeout(const char*) (Public)
332 // Time to send another message.
333 //
handleTimeout(const char * name)334 void AppClient::handleTimeout(const char *name)
335 {
336 if (strcmp(name, "TRANSMIT_TIMER") == 0)
337 {
338 char message[30];
339 const sockaddr_in& address = _client_socket->getServerAddress();
340
341 (void) sprintf(message,
342 "This is message #%d.",
343 ++_messageCount);
344
345 cout << "Transmitting to "
346 << _host
347 << ":"
348 << ntohs(address.sin_port)
349 << ": \""
350 << message
351 << "\" ... ";
352
353 _client_socket->transmit(message, 0, strlen(message));
354 }
355 else if (strcmp(name, "CLOSE_TIMER") == 0)
356 {
357 _client_socket->doClose();
358 }
359
360 return;
361 } // end of AppClient::handleTimeout(const char*)
362
363 //---------------------------------------------------------------
364 // setTransmitTimer() (Private)
365 // Set the transmit timer to expire some random time in the
366 // future.
367 //
setTransmitTimer()368 void AppClient::setTransmitTimer()
369 {
370 long duration;
371
372 // Initialize the random number generator, if necessary.
373 if (_initFlag == 0)
374 {
375 srand(time(NULL));
376 _initFlag = 1;
377 }
378
379 // Set the next tranmission to some random time.
380 duration = ((long) rand()) % MAX_SLEEP_TIME;
381 if (duration < MIN_SLEEP_TIME)
382 {
383 duration = MIN_SLEEP_TIME;
384 }
385
386 Gevent_loop->startTimer("TRANSMIT_TIMER", duration, *this);
387
388 return;
389 } // end of AppClient::setTransmitTimer()
390