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