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