]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/input_output/FGfdmSocket.cpp
latest changes for JSBSim (1.0 prerelease)
[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(_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 (!is_number(address)) {
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(_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 (!is_number(address)) {
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(_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(_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   if (sckt) shutdown(sckt,2);
209   if (sckt_in) shutdown(sckt_in,2);
210   Debug(1);
211 }
212
213 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214
215 string FGfdmSocket::Receive(void)
216 {
217   char buf[1024];
218   int len = sizeof(struct sockaddr_in);
219   int num_chars=0;
220   int total_chars = 0;
221   unsigned long NoBlock = true;
222   string data = ""; // todo: should allocate this with a standard size as a
223                     // class attribute and pass as a reference?
224
225   if (sckt_in <= 0) {
226     #if defined(_MSC_VER) || defined(__MINGW32__)
227       sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
228     #else
229       sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
230     #endif
231     if (sckt_in > 0) {
232       #if defined(_MSC_VER) || defined(__MINGW32__)
233          ioctlsocket(sckt_in, FIONBIO,&NoBlock);
234       #else
235          ioctl(sckt_in, FIONBIO, &NoBlock);
236       #endif
237       send(sckt_in, "Connected to JSBSim server\nJSBSim> ", 35, 0);
238     }
239   }
240
241   if (sckt_in > 0) {
242     while ((num_chars = recv(sckt_in, buf, 1024, 0)) > 0) {
243       data += string(buf).substr(0,num_chars);
244       total_chars += num_chars;
245     }
246
247 #if defined(_MSC_VER)
248     // when nothing received and the error isn't "would block"
249     // then assume that the client has closed the socket.
250     if (num_chars == 0) {
251         DWORD err = WSAGetLastError ();
252         if (err != WSAEWOULDBLOCK) {
253             printf ("Socket Closed. back to listening\n");
254             closesocket (sckt_in);
255             sckt_in = -1;
256         }
257     }
258 #endif
259   }
260
261   return data.substr(0, total_chars);
262 }
263
264 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265
266 int FGfdmSocket::Reply(string text)
267 {
268   int num_chars_sent=0;
269
270   if (sckt_in >= 0) {
271     num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
272     send(sckt_in, "JSBSim> ", 8, 0);
273   } else {
274     cerr << "Socket reply must be to a valid socket" << endl;
275     return -1;
276   }
277   return num_chars_sent;
278 }
279
280 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281
282 void FGfdmSocket::Close(void)
283 {
284   close(sckt_in);
285 }
286
287 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288
289 void FGfdmSocket::Clear(void)
290 {
291   buffer = "";
292   size = 0;
293 }
294
295 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296
297 void FGfdmSocket::Clear(string s)
298 {
299   buffer = s + " ";
300   size = buffer.size();
301 }
302
303 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304
305 void FGfdmSocket::Append(const char* item)
306 {
307   if (size == 0) buffer += string(item);
308   else buffer += string(",") + string(item);
309   size++;
310 }
311
312 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313
314 void FGfdmSocket::Append(double item)
315 {
316   char s[25];
317
318   sprintf(s,"%12.7f",item);
319
320   if (size == 0) buffer += string(s);
321   else buffer += string(",") + string(s);
322   size++;
323 }
324
325 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326
327 void FGfdmSocket::Append(long item)
328 {
329   char s[25];
330
331   sprintf(s,"%12ld",item);
332
333   if (size == 0) buffer += string(s);
334   else buffer += string(",") + string(s);
335   size++;
336 }
337
338 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339
340 void FGfdmSocket::Send(void)
341 {
342   buffer += string("\n");
343   if ((send(sckt,buffer.c_str(),buffer.size(),0)) <= 0) {
344     perror("send");
345   } else {
346   }
347 }
348
349 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350
351 void FGfdmSocket::Send(char *data, int length)
352 {
353   if ((send(sckt,data,length,0)) <= 0) {
354     perror("send");
355   } else {
356   }
357 }
358
359 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360 //    The bitmasked value choices are as follows:
361 //    unset: In this case (the default) JSBSim would only print
362 //       out the normally expected messages, essentially echoing
363 //       the config files as they are read. If the environment
364 //       variable is not set, debug_lvl is set to 1 internally
365 //    0: This requests JSBSim not to output any messages
366 //       whatsoever.
367 //    1: This value explicity requests the normal JSBSim
368 //       startup messages
369 //    2: This value asks for a message to be printed out when
370 //       a class is instantiated
371 //    4: When this value is set, a message is displayed when a
372 //       FGModel object executes its Run() method
373 //    8: When this value is set, various runtime state variables
374 //       are printed out periodically
375 //    16: When set various parameters are sanity checked and
376 //       a message is printed out when they go out of bounds
377
378 void FGfdmSocket::Debug(int from)
379 {
380   if (debug_lvl <= 0) return;
381
382   if (debug_lvl & 1) { // Standard console startup message output
383     if (from == 0) { // Constructor
384     }
385   }
386   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
387     if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
388     if (from == 1) cout << "Destroyed:    FGfdmSocket" << endl;
389   }
390   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
391   }
392   if (debug_lvl & 8 ) { // Runtime state variables
393   }
394   if (debug_lvl & 16) { // Sanity checking
395   }
396   if (debug_lvl & 64) {
397     if (from == 0) { // Constructor
398       cout << IdSrc << endl;
399       cout << IdHdr << endl;
400     }
401   }
402 }
403 }