1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 Module: FGfdmSocket.cpp
6 Purpose: Encapsulates a socket
7 Called by: FGOutput, et. al.
9 ------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
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
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
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.
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.
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This class excapsulates a socket for simple data writing
33 --------------------------------------------------------------------------------
35 11/08/07 HDW Added Generic Socket Send
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
45 #include "FGfdmSocket.h"
46 #include "string_utilities.h"
55 IDENT(IdSrc,"$Id: FGfdmSocket.cpp,v 1.29 2014/01/13 10:46:03 ehofman Exp $");
56 IDENT(IdHdr,ID_FDMSOCKET);
58 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
62 FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
67 #if defined(_MSC_VER) || defined(__MINGW32__)
70 wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
71 if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
72 else cout << "Winsock DLL not initialized ..." << endl;
75 if (!is_number(address)) {
76 if ((host = gethostbyname(address.c_str())) == NULL) {
77 cout << "Could not get host net address by name..." << endl;
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;
88 if (protocol == ptUDP) { //use udp protocol
89 sckt = socket(AF_INET, SOCK_DGRAM, 0);
90 cout << "Creating UDP socket on port " << port << endl;
92 else { //use tcp protocol
93 sckt = socket(AF_INET, SOCK_STREAM, 0);
94 cout << "Creating TCP socket on port " << port << endl;
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;
106 } else { // unsuccessful
107 cout << "Could not connect to socket for output ..." << endl;
109 } else { // unsuccessful
110 cout << "Could not create socket for FDM output, error = " << errno << endl;
116 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 FGfdmSocket::FGfdmSocket(const string& address, int port)
123 #if defined(_MSC_VER) || defined(__MINGW32__)
126 wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
127 if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
128 else cout << "Winsock DLL not initialized ..." << endl;
131 cout << "... Socket Configuration Sanity Check ..." << endl;
132 cout << "Host name... " << address << ", Port... " << port << "." << endl;
133 cout << "Host name... (char) " << address.c_str() << "." << endl;
135 if (!is_number(address)) {
136 if ((host = gethostbyname(address.c_str())) == NULL) {
137 cout << "Could not get host net address by name..." << endl;
140 if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
141 cout << "Could not get host net address by number..." << endl;
146 cout << "Got host net address..." << endl;
147 sckt = socket(AF_INET, SOCK_STREAM, 0);
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;
158 } else { // unsuccessful
159 cout << "Could not connect to socket for output ..." << endl;
161 } else { // unsuccessful
162 cout << "Could not create socket for FDM output, error = " << errno << endl;
168 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 FGfdmSocket::FGfdmSocket(int port)
173 unsigned long NoBlock = true;
175 #if defined(_MSC_VER) || defined(__MINGW32__)
178 wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
179 if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
180 else cerr << "Winsock DLL not initialized ..." << endl;
183 sckt = socket(AF_INET, SOCK_STREAM, 0);
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);
197 ioctl(sckt, FIONBIO, &NoBlock);
198 sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
201 cerr << "Could not listen ..." << endl;
204 } else { // unsuccessful
205 cerr << "Could not bind to socket for input ..." << endl;
207 } else { // unsuccessful
208 cerr << "Could not create socket for FDM input, error = " << errno << endl;
214 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 FGfdmSocket::~FGfdmSocket()
218 if (sckt) shutdown(sckt,2);
219 if (sckt_in) shutdown(sckt_in,2);
223 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225 string FGfdmSocket::Receive(void)
228 int len = sizeof(struct sockaddr_in);
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?
235 #if defined(_MSC_VER) || defined(__MINGW32__)
236 sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
238 sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
241 #if defined(_MSC_VER) || defined(__MINGW32__)
242 ioctlsocket(sckt_in, FIONBIO,&NoBlock);
244 ioctl(sckt_in, FIONBIO, &NoBlock);
246 send(sckt_in, "Connected to JSBSim server\nJSBSim> ", 35, 0);
251 while ((num_chars = recv(sckt_in, buf, sizeof buf, 0)) > 0) {
252 data.append(buf, num_chars);
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);
272 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 int FGfdmSocket::Reply(const string& text)
276 int num_chars_sent=0;
279 num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
280 send(sckt_in, "JSBSim> ", 8, 0);
282 cerr << "Socket reply must be to a valid socket" << endl;
285 return num_chars_sent;
288 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290 void FGfdmSocket::Close(void)
295 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
297 void FGfdmSocket::Clear(void)
299 buffer.str(string());
302 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304 void FGfdmSocket::Clear(const string& s)
310 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 void FGfdmSocket::Append(const char* item)
314 if (buffer.tellp() > 0) buffer << ',';
318 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320 void FGfdmSocket::Append(double item)
322 if (buffer.tellp() > 0) buffer << ',';
323 buffer << std::setw(12) << std::setprecision(7) << item;
326 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328 void FGfdmSocket::Append(long item)
330 if (buffer.tellp() > 0) buffer << ',';
331 buffer << std::setw(12) << item;
334 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 void FGfdmSocket::Send(void)
339 string str = buffer.str();
340 if ((send(sckt,str.c_str(),str.size(),0)) <= 0) {
345 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 void FGfdmSocket::Send(const char *data, int length)
349 if ((send(sckt,data,length,0)) <= 0) {
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
362 // 1: This value explicity requests the normal JSBSim
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
373 void FGfdmSocket::Debug(int from)
375 if (debug_lvl <= 0) return;
377 if (debug_lvl & 1) { // Standard console startup message output
378 if (from == 0) { // Constructor
381 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
382 if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
383 if (from == 1) cout << "Destroyed: FGfdmSocket" << endl;
385 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
387 if (debug_lvl & 8 ) { // Runtime state variables
389 if (debug_lvl & 16) { // Sanity checking
391 if (debug_lvl & 64) {
392 if (from == 0) { // Constructor
393 cout << IdSrc << endl;
394 cout << IdHdr << endl;