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