]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/input_output/FGfdmSocket.cpp
Merge branch 'luff/kln89'
[flightgear.git] / src / FDM / JSBSim / input_output / FGfdmSocket.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGfdmSocket.cpp
4  Author:       Jon S. Berndt
5  Date started: 11/08/99
6  Purpose:      Encapsulates a socket
7  Called by:    FGOutput, et. al.
8
9  ------------- Copyright (C) 1999  Jon S. Berndt (jon@jsbsim.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU Lesser General Public License as published by the Free Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  version.
15
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
19  details.
20
21  You should have received a copy of the GNU Lesser General Public License along with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA  02111-1307, USA.
24
25  Further information about the GNU Lesser General Public License can also be found on
26  the world wide web at http://www.gnu.org.
27
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This class excapsulates a socket for simple data writing
31
32 HISTORY
33 --------------------------------------------------------------------------------
34 11/08/99   JSB   Created
35 11/08/07   HDW   Added Generic Socket Send
36
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40
41 #include <iostream>
42 #include <iomanip>
43 #include <cstring>
44 #include <cstdio>
45 #include "FGfdmSocket.h"
46 #include "string_utilities.h"
47
48 using std::cout;
49 using std::cerr;
50 using std::endl;
51 using std::string;
52
53 namespace JSBSim {
54
55 static const char *IdSrc = "$Id$";
56 static const char *IdHdr = ID_FDMSOCKET;
57
58 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59 CLASS IMPLEMENTATION
60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
61
62 FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
63 {
64   sckt = sckt_in = 0;
65   connected = false;
66
67   #if defined(_MSC_VER) || defined(__MINGW32__)
68     WSADATA wsaData;
69     int wsaReturnCode;
70     wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
71     if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
72     else cout << "Winsock DLL not initialized ..." << endl;
73   #endif
74
75   if (!is_number(address)) {
76     if ((host = gethostbyname(address.c_str())) == NULL) {
77       cout << "Could not get host net address by name..." << endl;
78     }
79   } else {
80     if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
81       cout << "Could not get host net address by number..." << endl;
82     }
83   }
84
85   if (host != NULL) {
86     if (protocol == ptUDP) {  //use udp protocol
87        sckt = socket(AF_INET, SOCK_DGRAM, 0);
88        cout << "Creating UDP socket on port " << port << endl;
89     }
90     else { //use tcp protocol
91        sckt = socket(AF_INET, SOCK_STREAM, 0);
92        cout << "Creating TCP socket on port " << port << endl;
93     }
94
95     if (sckt >= 0) {  // successful
96       memset(&scktName, 0, sizeof(struct sockaddr_in));
97       scktName.sin_family = AF_INET;
98       scktName.sin_port = htons(port);
99       memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
100       int len = sizeof(struct sockaddr_in);
101       if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) {   // successful
102         cout << "Successfully connected to socket for output ..." << endl;
103         connected = true;
104       } else {                // unsuccessful
105         cout << "Could not connect to socket for output ..." << endl;
106       }
107     } else {          // unsuccessful
108       cout << "Could not create socket for FDM output, error = " << errno << endl;
109     }
110   }
111   Debug(0);
112 }
113
114 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115
116 FGfdmSocket::FGfdmSocket(const string& address, int port)
117 {
118   sckt = sckt_in = 0;
119   connected = false;
120
121   #if defined(_MSC_VER) || defined(__MINGW32__)
122     WSADATA wsaData;
123     int wsaReturnCode;
124     wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
125     if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
126     else cout << "Winsock DLL not initialized ..." << endl;
127   #endif
128
129   cout << "... Socket Configuration Sanity Check ..." << endl;
130   cout << "Host name...   " << address << ",  Port...  " << port << "." << endl;
131   cout << "Host name... (char)  " << address.c_str() << "." << endl;
132
133   if (!is_number(address)) {
134     if ((host = gethostbyname(address.c_str())) == NULL) {
135       cout << "Could not get host net address by name..." << endl;
136     }
137   } else {
138     if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
139       cout << "Could not get host net address by number..." << endl;
140     }
141   }
142
143   if (host != NULL) {
144     cout << "Got host net address..." << endl;
145     sckt = socket(AF_INET, SOCK_STREAM, 0);
146
147     if (sckt >= 0) {  // successful
148       memset(&scktName, 0, sizeof(struct sockaddr_in));
149       scktName.sin_family = AF_INET;
150       scktName.sin_port = htons(port);
151       memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
152       int len = sizeof(struct sockaddr_in);
153       if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) {   // successful
154         cout << "Successfully connected to socket for output ..." << endl;
155         connected = true;
156       } else {                // unsuccessful
157         cout << "Could not connect to socket for output ..." << endl;
158       }
159     } else {          // unsuccessful
160       cout << "Could not create socket for FDM output, error = " << errno << endl;
161     }
162   }
163   Debug(0);
164 }
165
166 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167
168 FGfdmSocket::FGfdmSocket(int port)
169 {
170   connected = false;
171   unsigned long NoBlock = true;
172
173   #if defined(_MSC_VER) || defined(__MINGW32__)
174     WSADATA wsaData;
175     int wsaReturnCode;
176     wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
177     if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
178     else cerr << "Winsock DLL not initialized ..." << endl;
179   #endif
180
181   sckt = socket(AF_INET, SOCK_STREAM, 0);
182
183   if (sckt >= 0) {  // successful
184     memset(&scktName, 0, sizeof(struct sockaddr_in));
185     scktName.sin_family = AF_INET;
186     scktName.sin_port = htons(port);
187     int len = sizeof(struct sockaddr_in);
188     if (bind(sckt, (struct sockaddr*)&scktName, len) == 0) {   // successful
189       cout << "Successfully bound to socket for input on port " << port << endl;
190       if (listen(sckt, 5) >= 0) { // successful listen()
191         #if defined(_MSC_VER) || defined(__MINGW32__)
192           ioctlsocket(sckt, FIONBIO, &NoBlock);
193           sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
194         #else
195           ioctl(sckt, FIONBIO, &NoBlock);
196           sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
197         #endif
198       } else {
199         cerr << "Could not listen ..." << endl;
200       }
201       connected = true;
202     } else {                // unsuccessful
203       cerr << "Could not bind to socket for input ..." << endl;
204     }
205   } else {          // unsuccessful
206     cerr << "Could not create socket for FDM input, error = " << errno << endl;
207   }
208
209   Debug(0);
210 }
211
212 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213
214 FGfdmSocket::~FGfdmSocket()
215 {
216   if (sckt) shutdown(sckt,2);
217   if (sckt_in) shutdown(sckt_in,2);
218   Debug(1);
219 }
220
221 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222
223 string FGfdmSocket::Receive(void)
224 {
225   char buf[1024];
226   int len = sizeof(struct sockaddr_in);
227   int num_chars=0;
228   unsigned long NoBlock = true;
229   string data;      // todo: should allocate this with a standard size as a
230                     // class attribute and pass as a reference?
231
232   if (sckt_in <= 0) {
233     #if defined(_MSC_VER) || defined(__MINGW32__)
234       sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
235     #else
236       sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
237     #endif
238     if (sckt_in > 0) {
239       #if defined(_MSC_VER) || defined(__MINGW32__)
240          ioctlsocket(sckt_in, FIONBIO,&NoBlock);
241       #else
242          ioctl(sckt_in, FIONBIO, &NoBlock);
243       #endif
244       send(sckt_in, "Connected to JSBSim server\nJSBSim> ", 35, 0);
245     }
246   }
247
248   if (sckt_in > 0) {
249     while ((num_chars = recv(sckt_in, buf, sizeof buf, 0)) > 0) {
250       data.append(buf, num_chars);
251     }
252
253 #if defined(_MSC_VER)
254     // when nothing received and the error isn't "would block"
255     // then assume that the client has closed the socket.
256     if (num_chars == 0) {
257         DWORD err = WSAGetLastError ();
258         if (err != WSAEWOULDBLOCK) {
259             printf ("Socket Closed. back to listening\n");
260             closesocket (sckt_in);
261             sckt_in = -1;
262         }
263     }
264 #endif
265   }
266
267   return data;
268 }
269
270 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271
272 int FGfdmSocket::Reply(const string& text)
273 {
274   int num_chars_sent=0;
275
276   if (sckt_in >= 0) {
277     num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
278     send(sckt_in, "JSBSim> ", 8, 0);
279   } else {
280     cerr << "Socket reply must be to a valid socket" << endl;
281     return -1;
282   }
283   return num_chars_sent;
284 }
285
286 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287
288 void FGfdmSocket::Close(void)
289 {
290   close(sckt_in);
291 }
292
293 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294
295 void FGfdmSocket::Clear(void)
296 {
297   buffer.str(string());
298 }
299
300 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301
302 void FGfdmSocket::Clear(const string& s)
303 {
304   Clear();
305   buffer << s << ' ';
306 }
307
308 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309
310 void FGfdmSocket::Append(const char* item)
311 {
312   if (buffer.tellp() > 0) buffer << ',';
313   buffer << item;
314 }
315
316 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317
318 void FGfdmSocket::Append(double item)
319 {
320   if (buffer.tellp() > 0) buffer << ',';
321   buffer << std::setw(12) << std::setprecision(7) << item;
322 }
323
324 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325
326 void FGfdmSocket::Append(long item)
327 {
328   if (buffer.tellp() > 0) buffer << ',';
329   buffer << std::setw(12) << item;
330 }
331
332 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333
334 void FGfdmSocket::Send(void)
335 {
336   buffer << '\n';
337   string str = buffer.str();
338   if ((send(sckt,str.c_str(),str.size(),0)) <= 0) {
339     perror("send");
340   }
341 }
342
343 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344
345 void FGfdmSocket::Send(const char *data, int length)
346 {
347   if ((send(sckt,data,length,0)) <= 0) {
348     perror("send");
349   }
350 }
351
352 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353 //    The bitmasked value choices are as follows:
354 //    unset: In this case (the default) JSBSim would only print
355 //       out the normally expected messages, essentially echoing
356 //       the config files as they are read. If the environment
357 //       variable is not set, debug_lvl is set to 1 internally
358 //    0: This requests JSBSim not to output any messages
359 //       whatsoever.
360 //    1: This value explicity requests the normal JSBSim
361 //       startup messages
362 //    2: This value asks for a message to be printed out when
363 //       a class is instantiated
364 //    4: When this value is set, a message is displayed when a
365 //       FGModel object executes its Run() method
366 //    8: When this value is set, various runtime state variables
367 //       are printed out periodically
368 //    16: When set various parameters are sanity checked and
369 //       a message is printed out when they go out of bounds
370
371 void FGfdmSocket::Debug(int from)
372 {
373   if (debug_lvl <= 0) return;
374
375   if (debug_lvl & 1) { // Standard console startup message output
376     if (from == 0) { // Constructor
377     }
378   }
379   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
380     if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
381     if (from == 1) cout << "Destroyed:    FGfdmSocket" << endl;
382   }
383   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
384   }
385   if (debug_lvl & 8 ) { // Runtime state variables
386   }
387   if (debug_lvl & 16) { // Sanity checking
388   }
389   if (debug_lvl & 64) {
390     if (from == 0) { // Constructor
391       cout << IdSrc << endl;
392       cout << IdHdr << endl;
393     }
394   }
395 }
396 }