41#if defined(_MSC_VER) || defined(__MINGW32__)
43#elif defined(__OpenBSD__)
45#include <sys/socket.h>
59#include "FGfdmSocket.h"
60#include "input_output/string_utilities.h"
61#include "input_output/FGLog.h"
67#define closesocket close
68#define INVALID_SOCKET -1
69#define SOCKET_ERROR -1
70#define SD_BOTH SHUT_RDWR
80static bool LoadWinSockDLL(
int debug_lvl)
83 if (WSAStartup(MAKEWORD(1, 1), &wsaData)) {
84 FGLogging log(LogLevel::ERROR);
85 log <<
"Winsock DLL not initialized ...\n";
90 FGLogging log(LogLevel::DEBUG);
91 log <<
"Winsock DLL loaded ...\n";
100 sckt = sckt_in = INVALID_SOCKET;
101 Protocol = (ProtocolType)protocol;
103 struct addrinfo *addr =
nullptr;
104 this->precision = precision;
107 if (!LoadWinSockDLL(debug_lvl))
return;
110 struct addrinfo hints;
111 memset(&hints, 0,
sizeof(
struct addrinfo));
112 hints.ai_family = AF_INET;
113 if (protocol == ptUDP)
114 hints.ai_socktype = SOCK_DGRAM;
116 hints.ai_socktype = SOCK_STREAM;
117 hints.ai_protocol = 0;
118 if (!is_number(address))
119 hints.ai_flags = AI_ADDRCONFIG;
121 hints.ai_flags = AI_NUMERICHOST;
123 int failure = getaddrinfo(address.c_str(), NULL, &hints, &addr);
124 if (failure || !addr) {
126 log <<
"Could not get host net address " << address;
128 if (hints.ai_flags == AI_NUMERICHOST)
129 log <<
" by number...\n";
131 log <<
" by name...\n";
133 log << gai_strerror(failure) <<
"\n";
139 sckt = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
143 if (protocol == ptUDP)
144 log <<
"Creating UDP socket on port " << port <<
"\n";
146 log <<
"Creating TCP socket on port " << port <<
"\n";
149 if (sckt != INVALID_SOCKET) {
150 int len =
sizeof(
struct sockaddr_in);
151 memcpy(&scktName, addr->ai_addr, len);
152 scktName.sin_port = htons(port);
154 if (connect(sckt, (
struct sockaddr*)&scktName, len) == 0) {
157 log <<
"Successfully connected to socket for output ...\n";
162 log <<
"Could not connect to socket for output ...\n";
166 log <<
"Could not create socket for FDM output, error = " << errno <<
"\n";
178 sckt = INVALID_SOCKET;
180 Protocol = (ProtocolType)protocol;
182 this->precision = precision;
185 if (!LoadWinSockDLL(debug_lvl))
return;
188 if (Protocol == ptUDP) {
189 ProtocolName =
"UDP";
190 sckt = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
193 ioctlsocket(sckt, FIONBIO, &NonBlock);
195 int flags = fcntl(sckt, F_GETFL, 0);
196 fcntl(sckt, F_SETFL, flags | O_NONBLOCK);
200 ProtocolName =
"TCP";
201 sckt = socket(AF_INET, SOCK_STREAM, 0);
206 log <<
"Creating input " << ProtocolName <<
" socket on port " << port
210 if (sckt != INVALID_SOCKET) {
211 memset(&scktName, 0,
sizeof(
struct sockaddr_in));
212 scktName.sin_family = AF_INET;
213 scktName.sin_port = htons(port);
215 if (Protocol == ptUDP)
216 scktName.sin_addr.s_addr = htonl(INADDR_ANY);
218 socklen_t len =
sizeof(
struct sockaddr_in);
219 if (bind(sckt, (
struct sockaddr*)&scktName, len) != SOCKET_ERROR) {
222 log <<
"Successfully bound to " << ProtocolName
223 <<
" input socket on port " << port <<
"\n\n";
226 if (Protocol == ptTCP) {
227 if (listen(sckt, 5) != SOCKET_ERROR) {
231 ioctlsocket(sckt, FIONBIO, &NoBlock);
233 int flags = fcntl(sckt, F_GETFL, 0);
234 fcntl(sckt, F_SETFL, flags | O_NONBLOCK);
236 sckt_in = accept(sckt, (
struct sockaddr*)&scktName, &len);
239 sckt = INVALID_SOCKET;
241 log <<
"Could not listen ...\n";
247 sckt = INVALID_SOCKET;
249 log <<
"Could not bind to " << ProtocolName <<
" input socket, error = "
254 log <<
"Could not create " << ProtocolName <<
" socket for input, error = "
263FGfdmSocket::~FGfdmSocket()
266 if (sckt_in != INVALID_SOCKET) shutdown(sckt_in, SD_BOTH);
267 if (sckt != INVALID_SOCKET) closesocket(sckt);
279 if (Protocol == ptTCP){
280 if (sckt_in == INVALID_SOCKET) {
281 socklen_t len =
sizeof(
struct sockaddr_in);
282 sckt_in = accept(sckt, (
struct sockaddr*)&scktName, &len);
283 if (sckt_in != INVALID_SOCKET) {
286 ioctlsocket(sckt_in, FIONBIO, &NoBlock);
288 int flags = fcntl(sckt_in, F_GETFL, 0);
289 fcntl(sckt_in, F_SETFL, flags | O_NONBLOCK);
291 if (send(sckt_in,
"Connected to JSBSim server\r\nJSBSim> ", 36, 0) == SOCKET_ERROR)
292 LogSocketError(
"Receive - TCP connection acknowledgement");
296 if (sckt_in != INVALID_SOCKET) {
299 while ((num_chars = recv(sckt_in, buf,
sizeof buf, 0)) > 0)
300 data.append(buf, num_chars);
302 if (num_chars == SOCKET_ERROR || num_chars == 0) {
304 if (WSAGetLastError() != WSAEWOULDBLOCK)
306 if (errno != EWOULDBLOCK)
309 LogSocketError(
"Receive - TCP data reception");
313 log <<
"Socket Closed. Back to listening\n";
314 closesocket(sckt_in);
315 sckt_in = INVALID_SOCKET;
322 if (sckt != INVALID_SOCKET && Protocol == ptUDP) {
323 struct sockaddr addr;
324 socklen_t fromlen =
sizeof addr;
325 int num_chars = recvfrom(sckt, buf,
sizeof buf, 0, (
struct sockaddr*)&addr, &fromlen);
326 if (num_chars > 0) data.append(buf, num_chars);
327 if (num_chars == SOCKET_ERROR) {
329 if (WSAGetLastError() != WSAEWOULDBLOCK)
331 if (errno != EWOULDBLOCK)
333 LogSocketError(
"Receive - UDP data reception");
344 int num_chars_sent=0;
345 assert(Protocol == ptTCP);
347 if (sckt_in != INVALID_SOCKET) {
348 num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
349 if (num_chars_sent == SOCKET_ERROR) LogSocketError(
"Reply - Send data");
350 if (send(sckt_in,
"JSBSim> ", 8, 0) == SOCKET_ERROR) LogSocketError(
"Reply - Prompt");
353 log <<
"Socket reply must be to a valid socket\n";
356 return num_chars_sent;
363 assert(Protocol == ptTCP);
364 closesocket(sckt_in);
365 sckt_in = INVALID_SOCKET;
387 if (buffer.tellp() > 0) buffer <<
',';
395 if (buffer.tellp() > 0) buffer <<
',';
396 buffer << std::setw(12) << std::setprecision(precision) << item;
403 if (buffer.tellp() > 0) buffer <<
',';
404 buffer << std::setw(12) << item;
412 string str = buffer.str();
413 Send(str.c_str(), str.size());
420 if (Protocol == ptTCP && sckt_in != INVALID_SOCKET) {
421 if ((send(sckt_in, data, length, 0)) == SOCKET_ERROR) LogSocketError(
"Send - TCP data sending");
425 if (Protocol == ptUDP && sckt != INVALID_SOCKET) {
426 if ((send(sckt, data, length, 0)) == SOCKET_ERROR) LogSocketError(
"Send - UDP data sending");
431 log <<
"Data sending must be to a valid socket\n";
438 assert(Protocol == ptTCP);
439 if (sckt_in == INVALID_SOCKET)
return;
443 FD_SET(sckt_in, &fds);
445 int result = select(FD_SETSIZE, &fds,
nullptr,
nullptr,
nullptr);
449 log <<
"Socket timeout.\n";
451 }
else if (result != SOCKET_ERROR)
454 LogSocketError(
"WaitUntilReadable");
459void FGfdmSocket::LogSocketError(
const std::string& msg)
463 log <<
"Socket error in " << msg <<
": ";
465 LPSTR errorMessage =
nullptr;
466 DWORD errorCode = WSAGetLastError();
467 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
468 nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&errorMessage, 0,
nullptr);
469 log << errorMessage <<
"\n";
470 LocalFree(errorMessage);
472 log << strerror(errno) <<
"\n";
495void FGfdmSocket::Debug(
int from)
497 if (debug_lvl <= 0)
return;
503 if (debug_lvl & 2 ) {
504 FGLogging log(LogLevel::DEBUG);
505 if (from == 0) log <<
"Instantiated: FGfdmSocket\n";
506 if (from == 1) log <<
"Destroyed: FGfdmSocket\n";
508 if (debug_lvl & 4 ) {
510 if (debug_lvl & 8 ) {
512 if (debug_lvl & 16) {
514 if (debug_lvl & 64) {
std::string Receive(void)
Receive data from the socket connection.
void Clear(void)
Clear the internal buffer.
void Append(const std::string &s)
Append the specified string to the internal buffer.
void Close(void)
Close the socket connection if the protocol is TCP.
void WaitUntilReadable(void)
Wait until the TCP socket is readable.
FGfdmSocket(const std::string &address, int port, int protocol, int precision=7)
Construct a client socket.
int Reply(const std::string &text)
Send a reply to the client ending by a prompt "JSBSim>".
void Send(void)
Send the internal buffer over the socket connection.
Main namespace for the JSBSim Flight Dynamics Model.