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