]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/input_output/FGfdmSocket.cpp
Update to the latest version of JSBSim which supports Lighter Than Air craft
[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 (jsb@hal-pc.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 "FGfdmSocket.h"
42
43 namespace JSBSim {
44
45 static const char *IdSrc = "$Id$";
46 static const char *IdHdr = ID_FDMSOCKET;
47
48 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49 CLASS IMPLEMENTATION
50 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51
52 FGfdmSocket::FGfdmSocket(string address, int port, int protocol)
53 {
54   sckt = sckt_in = size = 0;
55   connected = false;
56
57   #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
58     WSADATA wsaData;
59     int wsaReturnCode;
60     wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
61     if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
62     else cout << "Winsock DLL not initialized ..." << endl;
63   #endif
64
65   if (address.find_first_not_of("0123456789.",0) != address.npos) {
66     if ((host = gethostbyname(address.c_str())) == NULL) {
67       cout << "Could not get host net address by name..." << endl;
68     }
69   } else {
70     if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
71       cout << "Could not get host net address by number..." << endl;
72     }
73   }
74
75   if (host != NULL) {
76     if (protocol == ptUDP) {  //use udp protocol
77        sckt = socket(AF_INET, SOCK_DGRAM, 0);
78        cout << "Creating UDP socket on port " << port << endl;
79     }
80     else { //use tcp protocol
81        sckt = socket(AF_INET, SOCK_STREAM, 0);
82        cout << "Creating TCP socket on port " << port << endl;
83     }
84
85     if (sckt >= 0) {  // successful
86       memset(&scktName, 0, sizeof(struct sockaddr_in));
87       scktName.sin_family = AF_INET;
88       scktName.sin_port = htons(port);
89       memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
90       int len = sizeof(struct sockaddr_in);
91       if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) {   // successful
92         cout << "Successfully connected to socket for output ..." << endl;
93         connected = true;
94       } else {                // unsuccessful
95         cout << "Could not connect to socket for output ..." << endl;
96       }
97     } else {          // unsuccessful
98       cout << "Could not create socket for FDM output, error = " << errno << endl;
99     }
100   }
101   Debug(0);
102 }
103
104 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105
106 FGfdmSocket::FGfdmSocket(string address, int port)
107 {
108   sckt = sckt_in = size = 0;
109   connected = false;
110
111   #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
112     WSADATA wsaData;
113     int wsaReturnCode;
114     wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
115     if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
116     else cout << "Winsock DLL not initialized ..." << endl;
117   #endif
118
119   cout << "... Socket Configuration Sanity Check ..." << endl;
120   cout << "Host name...   " << address << ",  Port...  " << port << "." << endl;
121   cout << "Host name... (char)  " << address.c_str() << "." << endl;
122
123   if (address.find_first_not_of("0123456789.",0) != address.npos) {
124     if ((host = gethostbyname(address.c_str())) == NULL) {
125       cout << "Could not get host net address by name..." << endl;
126     }
127   } else {
128     if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
129       cout << "Could not get host net address by number..." << endl;
130     }
131   }
132
133   if (host != NULL) {
134     cout << "Got host net address..." << endl;
135     sckt = socket(AF_INET, SOCK_STREAM, 0);
136
137     if (sckt >= 0) {  // successful
138       memset(&scktName, 0, sizeof(struct sockaddr_in));
139       scktName.sin_family = AF_INET;
140       scktName.sin_port = htons(port);
141       memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
142       int len = sizeof(struct sockaddr_in);
143       if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) {   // successful
144         cout << "Successfully connected to socket for output ..." << endl;
145         connected = true;
146       } else {                // unsuccessful
147         cout << "Could not connect to socket for output ..." << endl;
148       }
149     } else {          // unsuccessful
150       cout << "Could not create socket for FDM output, error = " << errno << endl;
151     }
152   }
153   Debug(0);
154 }
155
156 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157
158 FGfdmSocket::FGfdmSocket(int port)
159 {
160   size = 0;
161   connected = false;
162   unsigned long NoBlock = true;
163
164   #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
165     WSADATA wsaData;
166     int wsaReturnCode;
167     wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
168     if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
169     else cerr << "Winsock DLL not initialized ..." << endl;
170   #endif
171
172   sckt = socket(AF_INET, SOCK_STREAM, 0);
173
174   if (sckt >= 0) {  // successful
175     memset(&scktName, 0, sizeof(struct sockaddr_in));
176     scktName.sin_family = AF_INET;
177     scktName.sin_port = htons(port);
178     int len = sizeof(struct sockaddr_in);
179     if (bind(sckt, (struct sockaddr*)&scktName, len) == 0) {   // successful
180       cout << "Successfully bound to socket for input on port " << port << endl;
181       if (listen(sckt, 5) >= 0) { // successful listen()
182         #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
183           ioctlsocket(sckt, FIONBIO, &NoBlock);
184           sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
185         #else
186           ioctl(sckt, FIONBIO, &NoBlock);
187           sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
188         #endif
189       } else {
190         cerr << "Could not listen ..." << endl;
191       }
192       connected = true;
193     } else {                // unsuccessful
194       cerr << "Could not bind to socket for input ..." << endl;
195     }
196   } else {          // unsuccessful
197     cerr << "Could not create socket for FDM input, error = " << errno << endl;
198   }
199
200   Debug(0);
201 }
202
203 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204
205 FGfdmSocket::~FGfdmSocket()
206 {
207   #ifndef macintosh
208   if (sckt) shutdown(sckt,2);
209   if (sckt_in) shutdown(sckt_in,2);
210   #endif
211
212   #ifdef __BORLANDC__
213     WSACleanup();
214   #endif
215   Debug(1);
216 }
217
218 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219
220 string FGfdmSocket::Receive(void)
221 {
222   char buf[1024];
223   int len = sizeof(struct sockaddr_in);
224   int num_chars=0;
225   int total_chars = 0;
226   unsigned long NoBlock = true;
227   string data = ""; // todo: should allocate this with a standard size as a
228                     // class attribute and pass as a reference?
229
230   if (sckt_in <= 0) {
231     #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
232       sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
233     #else
234       sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
235     #endif
236     if (sckt_in > 0) {
237       #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
238          ioctlsocket(sckt_in, FIONBIO,&NoBlock);
239       #else
240          ioctl(sckt_in, FIONBIO, &NoBlock);
241       #endif
242       send(sckt_in, "Connected to JSBSim server\nJSBSim> ", 35, 0);
243     }
244   }
245
246   if (sckt_in > 0) {
247     while ((num_chars = recv(sckt_in, buf, 1024, 0)) > 0) {
248       data += string(buf).substr(0,num_chars);
249       total_chars += num_chars;
250     }
251
252 #if defined(_MSC_VER)
253     // when nothing received and the error isn't "would block"
254     // then assume that the client has closed the socket.
255     if (num_chars == 0) {
256         DWORD err = WSAGetLastError ();
257         if (err != WSAEWOULDBLOCK) {
258             printf ("Socket Closed. back to listening\n");
259             closesocket (sckt_in);
260             sckt_in = -1;
261         }
262     }
263 #endif
264   }
265
266   return data.substr(0, total_chars);
267 }
268
269 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270
271 int FGfdmSocket::Reply(string text)
272 {
273   int num_chars_sent=0;
274
275   if (sckt_in >= 0) {
276     num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
277     send(sckt_in, "JSBSim> ", 8, 0);
278   } else {
279     cerr << "Socket reply must be to a valid socket" << endl;
280     return -1;
281   }
282   return num_chars_sent;
283 }
284
285 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286
287 void FGfdmSocket::Close(void)
288 {
289   close(sckt_in);
290 }
291
292 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
293
294 void FGfdmSocket::Clear(void)
295 {
296   buffer = "";
297   size = 0;
298 }
299
300 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301
302 void FGfdmSocket::Clear(string s)
303 {
304   buffer = s + " ";
305   size = buffer.size();
306 }
307
308 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309
310 void FGfdmSocket::Append(const char* item)
311 {
312   if (size == 0) buffer += string(item);
313   else buffer += string(",") + string(item);
314   size++;
315 }
316
317 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318
319 void FGfdmSocket::Append(double item)
320 {
321   char s[25];
322
323   sprintf(s,"%12.7f",item);
324
325   if (size == 0) buffer += string(s);
326   else buffer += string(",") + string(s);
327   size++;
328 }
329
330 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331
332 void FGfdmSocket::Append(long item)
333 {
334   char s[25];
335
336   sprintf(s,"%12ld",item);
337
338   if (size == 0) buffer += string(s);
339   else buffer += string(",") + string(s);
340   size++;
341 }
342
343 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344
345 void FGfdmSocket::Send(void)
346 {
347   buffer += string("\n");
348   if ((send(sckt,buffer.c_str(),buffer.size(),0)) <= 0) {
349     perror("send");
350   } else {
351   }
352 }
353
354 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355
356 void FGfdmSocket::Send(char *data, int length)
357 {
358   if ((send(sckt,data,length,0)) <= 0) {
359     perror("send");
360   } else {
361   }
362 }
363
364 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 //    The bitmasked value choices are as follows:
366 //    unset: In this case (the default) JSBSim would only print
367 //       out the normally expected messages, essentially echoing
368 //       the config files as they are read. If the environment
369 //       variable is not set, debug_lvl is set to 1 internally
370 //    0: This requests JSBSim not to output any messages
371 //       whatsoever.
372 //    1: This value explicity requests the normal JSBSim
373 //       startup messages
374 //    2: This value asks for a message to be printed out when
375 //       a class is instantiated
376 //    4: When this value is set, a message is displayed when a
377 //       FGModel object executes its Run() method
378 //    8: When this value is set, various runtime state variables
379 //       are printed out periodically
380 //    16: When set various parameters are sanity checked and
381 //       a message is printed out when they go out of bounds
382
383 void FGfdmSocket::Debug(int from)
384 {
385   if (debug_lvl <= 0) return;
386
387   if (debug_lvl & 1) { // Standard console startup message output
388     if (from == 0) { // Constructor
389     }
390   }
391   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
392     if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
393     if (from == 1) cout << "Destroyed:    FGfdmSocket" << endl;
394   }
395   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
396   }
397   if (debug_lvl & 8 ) { // Runtime state variables
398   }
399   if (debug_lvl & 16) { // Sanity checking
400   }
401   if (debug_lvl & 64) {
402     if (from == 0) { // Constructor
403       cout << IdSrc << endl;
404       cout << IdHdr << endl;
405     }
406   }
407 }
408 }