Branch data Line data Source code
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 : 0 : FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
63 : : {
64 : 0 : sckt = sckt_in = 0;
65 : 0 : 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 [ # # # # ]: 0 : if (!is_number(address)) {
76 [ # # ][ # # ]: 0 : if ((host = gethostbyname(address.c_str())) == NULL) {
77 : 0 : cout << "Could not get host net address by name..." << endl;
78 : : }
79 : : } else {
80 : : unsigned int ip;
81 : 0 : ip = inet_addr(address.c_str());
82 [ # # # # ]: 0 : if ((host = gethostbyaddr((char*)&ip, address.size(), PF_INET)) == NULL) {
83 : 0 : cout << "Could not get host net address by number..." << endl;
84 : : }
85 : : }
86 : :
87 [ # # ][ # # ]: 0 : if (host != NULL) {
88 [ # # ][ # # ]: 0 : if (protocol == ptUDP) { //use udp protocol
89 : 0 : sckt = socket(AF_INET, SOCK_DGRAM, 0);
90 : 0 : cout << "Creating UDP socket on port " << port << endl;
91 : : }
92 : : else { //use tcp protocol
93 : 0 : sckt = socket(AF_INET, SOCK_STREAM, 0);
94 : 0 : cout << "Creating TCP socket on port " << port << endl;
95 : : }
96 : :
97 [ # # ][ # # ]: 0 : if (sckt >= 0) { // successful
98 : 0 : memset(&scktName, 0, sizeof(struct sockaddr_in));
99 : 0 : scktName.sin_family = AF_INET;
100 [ # # ][ # # ]: 0 : scktName.sin_port = htons(port);
101 : 0 : memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
102 : 0 : int len = sizeof(struct sockaddr_in);
103 [ # # # # ]: 0 : if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
104 : 0 : cout << "Successfully connected to socket for output ..." << endl;
105 : 0 : connected = true;
106 : : } else { // unsuccessful
107 : 0 : cout << "Could not connect to socket for output ..." << endl;
108 : : }
109 : : } else { // unsuccessful
110 : 0 : cout << "Could not create socket for FDM output, error = " << errno << endl;
111 : : }
112 : : }
113 : 0 : Debug(0);
114 : 0 : }
115 : :
116 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117 : :
118 : 0 : FGfdmSocket::FGfdmSocket(const string& address, int port)
119 : : {
120 : 0 : sckt = sckt_in = 0;
121 : 0 : 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 : 0 : cout << "... Socket Configuration Sanity Check ..." << endl;
132 : 0 : cout << "Host name... " << address << ", Port... " << port << "." << endl;
133 : 0 : cout << "Host name... (char) " << address.c_str() << "." << endl;
134 : :
135 [ # # # # ]: 0 : if (!is_number(address)) {
136 [ # # ][ # # ]: 0 : if ((host = gethostbyname(address.c_str())) == NULL) {
137 : 0 : cout << "Could not get host net address by name..." << endl;
138 : : }
139 : : } else {
140 [ # # ][ # # ]: 0 : if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
141 : 0 : cout << "Could not get host net address by number..." << endl;
142 : : }
143 : : }
144 : :
145 [ # # ][ # # ]: 0 : if (host != NULL) {
146 : 0 : cout << "Got host net address..." << endl;
147 : 0 : sckt = socket(AF_INET, SOCK_STREAM, 0);
148 : :
149 [ # # # # ]: 0 : if (sckt >= 0) { // successful
150 : 0 : memset(&scktName, 0, sizeof(struct sockaddr_in));
151 : 0 : scktName.sin_family = AF_INET;
152 [ # # ][ # # ]: 0 : scktName.sin_port = htons(port);
153 : 0 : memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
154 : 0 : int len = sizeof(struct sockaddr_in);
155 [ # # # # ]: 0 : if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
156 : 0 : cout << "Successfully connected to socket for output ..." << endl;
157 : 0 : connected = true;
158 : : } else { // unsuccessful
159 : 0 : cout << "Could not connect to socket for output ..." << endl;
160 : : }
161 : : } else { // unsuccessful
162 : 0 : cout << "Could not create socket for FDM output, error = " << errno << endl;
163 : : }
164 : : }
165 : 0 : Debug(0);
166 : 0 : }
167 : :
168 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169 : :
170 : 0 : FGfdmSocket::FGfdmSocket(int port)
171 : : {
172 : 0 : connected = false;
173 : 0 : 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 : 0 : sckt = socket(AF_INET, SOCK_STREAM, 0);
184 : :
185 [ # # # # ]: 0 : if (sckt >= 0) { // successful
186 : 0 : memset(&scktName, 0, sizeof(struct sockaddr_in));
187 : 0 : scktName.sin_family = AF_INET;
188 [ # # ][ # # ]: 0 : scktName.sin_port = htons(port);
189 : 0 : int len = sizeof(struct sockaddr_in);
190 [ # # ][ # # ]: 0 : if (bind(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
191 : 0 : cout << "Successfully bound to socket for input on port " << port << endl;
192 [ # # # # ]: 0 : 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 : 0 : ioctl(sckt, FIONBIO, &NoBlock);
198 : 0 : sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
199 : : #endif
200 : : } else {
201 : 0 : cerr << "Could not listen ..." << endl;
202 : : }
203 : 0 : connected = true;
204 : : } else { // unsuccessful
205 : 0 : cerr << "Could not bind to socket for input ..." << endl;
206 : : }
207 : : } else { // unsuccessful
208 : 0 : cerr << "Could not create socket for FDM input, error = " << errno << endl;
209 : : }
210 : :
211 : 0 : Debug(0);
212 : 0 : }
213 : :
214 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 : :
216 : 0 : FGfdmSocket::~FGfdmSocket()
217 : : {
218 [ # # ][ # # ]: 0 : if (sckt) shutdown(sckt,2);
219 [ # # ][ # # ]: 0 : if (sckt_in) shutdown(sckt_in,2);
220 : 0 : Debug(1);
221 : 0 : }
222 : :
223 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 : :
225 : 0 : string FGfdmSocket::Receive(void)
226 : : {
227 : : char buf[1024];
228 : 0 : int len = sizeof(struct sockaddr_in);
229 : 0 : int num_chars=0;
230 : 0 : unsigned long NoBlock = true;
231 : 0 : string data; // todo: should allocate this with a standard size as a
232 : : // class attribute and pass as a reference?
233 : :
234 [ # # ]: 0 : if (sckt_in <= 0) {
235 : : #if defined(_MSC_VER) || defined(__MINGW32__)
236 : : sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
237 : : #else
238 : 0 : sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
239 : : #endif
240 [ # # ]: 0 : if (sckt_in > 0) {
241 : : #if defined(_MSC_VER) || defined(__MINGW32__)
242 : : ioctlsocket(sckt_in, FIONBIO,&NoBlock);
243 : : #else
244 : 0 : ioctl(sckt_in, FIONBIO, &NoBlock);
245 : : #endif
246 : 0 : send(sckt_in, "Connected to JSBSim server\nJSBSim> ", 35, 0);
247 : : }
248 : : }
249 : :
250 [ # # ]: 0 : if (sckt_in > 0) {
251 [ # # ]: 0 : while ((num_chars = recv(sckt_in, buf, sizeof buf, 0)) > 0) {
252 : 0 : 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 : 0 : return data;
270 : : }
271 : :
272 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 : :
274 : 0 : int FGfdmSocket::Reply(const string& text)
275 : : {
276 : 0 : int num_chars_sent=0;
277 : :
278 [ # # ]: 0 : if (sckt_in >= 0) {
279 : 0 : num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
280 : 0 : send(sckt_in, "JSBSim> ", 8, 0);
281 : : } else {
282 : 0 : cerr << "Socket reply must be to a valid socket" << endl;
283 : 0 : return -1;
284 : : }
285 : 0 : return num_chars_sent;
286 : : }
287 : :
288 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289 : :
290 : 0 : void FGfdmSocket::Close(void)
291 : : {
292 : 0 : close(sckt_in);
293 : 0 : }
294 : :
295 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 : :
297 : 0 : void FGfdmSocket::Clear(void)
298 : : {
299 : 0 : buffer.str(string());
300 : 0 : }
301 : :
302 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
303 : :
304 : 0 : void FGfdmSocket::Clear(const string& s)
305 : : {
306 : 0 : Clear();
307 : 0 : buffer << s << ' ';
308 : 0 : }
309 : :
310 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311 : :
312 : 0 : void FGfdmSocket::Append(const char* item)
313 : : {
314 [ # # ]: 0 : if (buffer.tellp() > 0) buffer << ',';
315 : 0 : buffer << item;
316 : 0 : }
317 : :
318 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 : :
320 : 0 : void FGfdmSocket::Append(double item)
321 : : {
322 [ # # ]: 0 : if (buffer.tellp() > 0) buffer << ',';
323 : 0 : buffer << std::setw(12) << std::setprecision(7) << item;
324 : 0 : }
325 : :
326 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327 : :
328 : 0 : void FGfdmSocket::Append(long item)
329 : : {
330 [ # # ]: 0 : if (buffer.tellp() > 0) buffer << ',';
331 : 0 : buffer << std::setw(12) << item;
332 : 0 : }
333 : :
334 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 : :
336 : 0 : void FGfdmSocket::Send(void)
337 : : {
338 : 0 : buffer << '\n';
339 : 0 : string str = buffer.str();
340 [ # # ]: 0 : if ((send(sckt,str.c_str(),str.size(),0)) <= 0) {
341 : 0 : perror("send");
342 : 0 : }
343 : 0 : }
344 : :
345 : : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 : :
347 : 0 : void FGfdmSocket::Send(const char *data, int length)
348 : : {
349 [ # # ]: 0 : if ((send(sckt,data,length,0)) <= 0) {
350 : 0 : perror("send");
351 : : }
352 : 0 : }
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 : 0 : void FGfdmSocket::Debug(int from)
374 : : {
375 [ # # ]: 0 : if (debug_lvl <= 0) return;
376 : :
377 : 0 : if (debug_lvl & 1) { // Standard console startup message output
378 : : if (from == 0) { // Constructor
379 : : }
380 : : }
381 [ # # ]: 0 : if (debug_lvl & 2 ) { // Instantiation/Destruction notification
382 [ # # ]: 0 : if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
383 [ # # ]: 0 : if (from == 1) cout << "Destroyed: FGfdmSocket" << endl;
384 : : }
385 : 0 : if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
386 : : }
387 : 0 : if (debug_lvl & 8 ) { // Runtime state variables
388 : : }
389 : 0 : if (debug_lvl & 16) { // Sanity checking
390 : : }
391 [ # # ]: 0 : if (debug_lvl & 64) {
392 [ # # ]: 0 : if (from == 0) { // Constructor
393 : 0 : cout << IdSrc << endl;
394 : 0 : cout << IdHdr << endl;
395 : : }
396 : : }
397 : : }
398 [ + + ][ + - ]: 12 : }
|