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