]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/input_output/FGfdmSocket.cpp
Sync. w. JSB CVS as of 15/01/2007
[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
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 for output ..." << endl;
86         connected = true;
87       } else {                // unsuccessful
88         cout << "Could not connect to socket for output ..." << endl;
89       }
90     } else {          // unsuccessful
91       cout << "Could not create socket for FDM output, 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     int len = sizeof(struct sockaddr_in);
120     if (bind(sckt, (struct sockaddr*)&scktName, len) == 0) {   // successful
121       cout << "Successfully bound to socket for input on port " << port << endl;
122       if (listen(sckt, 5) >= 0) { // successful listen()
123         #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
124           ioctlsocket(sckt, FIONBIO, &NoBlock);
125           sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
126         #else
127           ioctl(sckt, FIONBIO, &NoBlock);
128           sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
129         #endif
130       } else {
131         cerr << "Could not listen ..." << endl;
132       }
133       connected = true;
134     } else {                // unsuccessful
135       cerr << "Could not bind to socket for input ..." << endl;
136     }
137   } else {          // unsuccessful
138     cerr << "Could not create socket for FDM input, error = " << errno << endl;
139   }
140
141   Debug(0);
142 }
143
144 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145
146 FGfdmSocket::~FGfdmSocket()
147 {
148   #ifndef macintosh
149   if (sckt) shutdown(sckt,2);
150   if (sckt_in) shutdown(sckt_in,2);
151   #endif
152
153   #ifdef __BORLANDC__
154     WSACleanup();
155   #endif
156   Debug(1);
157 }
158
159 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160
161 string FGfdmSocket::Receive(void)
162 {
163   char buf[1024];
164   int len = sizeof(struct sockaddr_in);
165   int num_chars=0;
166   int total_chars = 0;
167   unsigned long NoBlock = true;
168   string data = ""; // todo: should allocate this with a standard size as a
169                     // class attribute and pass as a reference?
170
171   if (sckt_in <= 0) {
172     #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
173       sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
174     #else
175       sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
176     #endif
177     if (sckt_in > 0) {
178       #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
179          ioctlsocket(sckt_in, FIONBIO,&NoBlock);
180       #else
181          ioctl(sckt_in, FIONBIO, &NoBlock);
182       #endif
183       send(sckt_in, "Connected to JSBSim server\nJSBSim> ", 35, 0);
184     }
185   }
186
187   if (sckt_in > 0) {
188     while ((num_chars = recv(sckt_in, buf, 1024, 0)) > 0) {
189       data += string(buf).substr(0,num_chars);
190       total_chars += num_chars;
191     }
192
193 #if defined(_MSC_VER)
194     // when nothing received and the error isn't "would block"
195     // then assume that the client has closed the socket.
196     if (num_chars == 0) {
197         DWORD err = WSAGetLastError ();
198         if (err != WSAEWOULDBLOCK) {
199             printf ("Socket Closed. back to listening\n");
200             closesocket (sckt_in);
201             sckt_in = -1;
202         }
203     }
204 #endif
205   }
206
207   return data.substr(0, total_chars);
208 }
209
210 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
211
212 int FGfdmSocket::Reply(string text)
213 {
214   int num_chars_sent=0;
215
216   if (sckt_in >= 0) {
217     num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
218     send(sckt_in, "JSBSim> ", 8, 0);
219   } else {
220     cerr << "Socket reply must be to a valid socket" << endl;
221     return -1;
222   }
223   return num_chars_sent;
224 }
225
226 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227
228 void FGfdmSocket::Close(void)
229 {
230   close(sckt_in);
231 }
232
233 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234
235 void FGfdmSocket::Clear(void)
236 {
237   buffer = "";
238   size = 0;
239 }
240
241 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242
243 void FGfdmSocket::Clear(string s)
244 {
245   buffer = s + " ";
246   size = buffer.size();
247 }
248
249 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250
251 void FGfdmSocket::Append(const char* item)
252 {
253   if (size == 0) buffer += string(item);
254   else buffer += string(",") + string(item);
255   size++;
256 }
257
258 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259
260 void FGfdmSocket::Append(double item)
261 {
262   char s[25];
263
264   sprintf(s,"%12.7f",item);
265
266   if (size == 0) buffer += string(s);
267   else buffer += string(",") + string(s);
268   size++;
269 }
270
271 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272
273 void FGfdmSocket::Append(long item)
274 {
275   char s[25];
276
277   sprintf(s,"%12ld",item);
278
279   if (size == 0) buffer += string(s);
280   else buffer += string(",") + string(s);
281   size++;
282 }
283
284 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285
286 void FGfdmSocket::Send(void)
287 {
288   buffer += string("\n");
289   if ((send(sckt,buffer.c_str(),buffer.size(),0)) <= 0) {
290     perror("send");
291   } else {
292   }
293 }
294
295 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 //    The bitmasked value choices are as follows:
297 //    unset: In this case (the default) JSBSim would only print
298 //       out the normally expected messages, essentially echoing
299 //       the config files as they are read. If the environment
300 //       variable is not set, debug_lvl is set to 1 internally
301 //    0: This requests JSBSim not to output any messages
302 //       whatsoever.
303 //    1: This value explicity requests the normal JSBSim
304 //       startup messages
305 //    2: This value asks for a message to be printed out when
306 //       a class is instantiated
307 //    4: When this value is set, a message is displayed when a
308 //       FGModel object executes its Run() method
309 //    8: When this value is set, various runtime state variables
310 //       are printed out periodically
311 //    16: When set various parameters are sanity checked and
312 //       a message is printed out when they go out of bounds
313
314 void FGfdmSocket::Debug(int from)
315 {
316   if (debug_lvl <= 0) return;
317
318   if (debug_lvl & 1) { // Standard console startup message output
319     if (from == 0) { // Constructor
320     }
321   }
322   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
323     if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
324     if (from == 1) cout << "Destroyed:    FGfdmSocket" << endl;
325   }
326   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
327   }
328   if (debug_lvl & 8 ) { // Runtime state variables
329   }
330   if (debug_lvl & 16) { // Sanity checking
331   }
332   if (debug_lvl & 64) {
333     if (from == 0) { // Constructor
334       cout << IdSrc << endl;
335       cout << IdHdr << endl;
336     }
337   }
338 }
339 }