diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj
index d92ff4ce51..f8cf5724f9 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj
@@ -38,6 +38,7 @@
+
@@ -68,6 +69,7 @@
+
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj.filters b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj.filters
index bf1bca2c22..be141992e2 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj.filters
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ApolloRTCCMFD.vcxproj.filters
@@ -90,6 +90,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -179,6 +182,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj b/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj
index 6cea8a7b6e..c3410fbca0 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj
@@ -289,6 +289,7 @@
%(PreprocessorDefinitions)
+
%(AdditionalIncludeDirectories)
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj.filters b/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj.filters
index 21c0e046cf..81ccc389de 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj.filters
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/LEM.vcxproj.filters
@@ -222,6 +222,9 @@
Source Files
+
+ Source Files
+
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj
index c880a11c6d..b39af00a88 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj
@@ -157,6 +157,7 @@
+
@@ -179,6 +180,7 @@
%(PreprocessorDefinitions)
+
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj.filters b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj.filters
index 9e25279581..d8456cc82b 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj.filters
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/ProjectApolloMFD.vcxproj.filters
@@ -44,6 +44,9 @@
Header Files
+
+ Header Files
+
@@ -72,5 +75,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj
index 653b59a6ad..3427b9920f 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj
@@ -386,6 +386,7 @@
%(PreprocessorDefinitions)
ProgramDatabase
+
ProgramDatabase
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj.filters b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj.filters
index 356551dd53..86366ff000 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj.filters
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn1b.vcxproj.filters
@@ -237,6 +237,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj
index f0243c86c8..06a70a62e5 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj
@@ -346,6 +346,7 @@
%(AdditionalIncludeDirectories)
%(PreprocessorDefinitions)
+
%(AdditionalIncludeDirectories)
@@ -474,6 +475,7 @@
+
diff --git a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj.filters b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj.filters
index b0284a34c7..608078fc9b 100644
--- a/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj.filters
+++ b/Orbitersdk/samples/ProjectApollo/Build/VC2017/Saturn5NASP.vcxproj.filters
@@ -237,6 +237,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -470,6 +473,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.cpp b/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.cpp
index 9e0628b2ea..baef8d2727 100644
--- a/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.cpp
+++ b/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.cpp
@@ -26,7 +26,6 @@
#include "Orbitersdk.h"
#include
#include
-#include // TODO: Replace with winsock2 after yaAGC updates
#include "soundlib.h"
#include "resource.h"
#include "nasspdefs.h"
@@ -2025,15 +2024,10 @@ PCM::PCM()
last_rx = 0;
frame_addr = 0;
frame_count = 0;
- m_socket = INVALID_SOCKET;
}
PCM::~PCM()
{
- if (m_socket != INVALID_SOCKET) {
- shutdown(m_socket, 2); // Shutdown both streams
- closesocket(m_socket);
- }
}
void PCM::Init(Saturn *vessel){
@@ -2045,46 +2039,16 @@ void PCM::Init(Saturn *vessel){
last_update = 0;
last_rx = MINUS_INFINITY;
word_addr = 0;
- int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
- if ( iResult != NO_ERROR ){
- sprintf(wsk_emsg,"TELECOM: Error at WSAStartup()");
- wsk_error = 1;
- return;
- }
- m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
- if ( m_socket == INVALID_SOCKET ) {
- sprintf(wsk_emsg,"TELECOM: Error at socket(): %ld", WSAGetLastError());
- WSACleanup();
- wsk_error = 1;
- return;
- }
- // Be nonblocking
- int iMode = 1; // 0 = BLOCKING, 1 = NONBLOCKING
- if(ioctlsocket(m_socket, FIONBIO, (u_long FAR*) &iMode) != 0){
- sprintf(wsk_emsg,"TELECOM: ioctlsocket() failed: %ld", WSAGetLastError());
+ if (!NetStartup()){
+ sprintf(wsk_emsg,"TELECOM: Error at NetStartup()");
wsk_error = 1;
- closesocket(m_socket);
- WSACleanup();
return;
}
- // Set up incoming options
- service.sin_family = AF_INET;
- service.sin_addr.s_addr = htonl(INADDR_ANY);
- service.sin_port = htons( 14242 );
-
- if ( ::bind( m_socket, (SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR ) {
- sprintf(wsk_emsg,"Failed to start CSM telemetry. Please completely exit Orbiter and restart. Please file a bug report if this message persists.");
- wsk_error = 1;
- closesocket(m_socket);
- WSACleanup();
- return;
- }
- if ( listen( m_socket, 1 ) == SOCKET_ERROR ){
+ m_tcpserver = TcpService(14242); // CM on 14242, LM on 14243
+ if (m_tcpserver.Status() != TcpService::STARTED) {
+ sprintf(wsk_emsg, "TELECOM: Error starting server: %d", m_tcpserver.ErrorCode());
wsk_error = 1;
- sprintf(wsk_emsg,"TELECOM: listen() failed: %ld", WSAGetLastError());
- closesocket(m_socket);
- WSACleanup();
return;
}
@@ -4996,73 +4960,52 @@ void PCM::perform_io(double simt){
}
}else{
// Try to accept
- AcceptSocket = accept( m_socket, NULL, NULL );
- if(AcceptSocket != INVALID_SOCKET){
+ m_connection = m_tcpserver.Accept();
+ if(m_connection.Status() == TcpConnection::CONNECTED){
conn_state = 2; // Accept this!
wsk_error = 0; // For now
}
}
// Otherwise loop and try again.
break;
- case 2: // CONNECTED
- int bytesSent,bytesRecv;
-
- bytesSent = send(AcceptSocket, (char *)tx_data, tx_size, 0 );
- if(bytesSent == SOCKET_ERROR){
- long errnumber = WSAGetLastError();
- switch(errnumber){
- // KNOWN CODES that we can ignore
- case 10035: // Operation Would Block
- // We can ignore this entirely. It's not an error.
- break;
-
- case 10038: // Socket isn't a socket
- case 10053: // Software caused connection abort
- case 10054: // Connection reset by peer
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
-
- default: // If unknown
- wsk_error = 1; // do this
- sprintf(wsk_emsg,"TELECOM: send() failed: %ld",errnumber);
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
- }
+ case 2: // CONNECTED
+ switch (m_connection.Send((char*)tx_data, tx_size)) {
+ case TcpConnection::CONNECTION_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ break;
+ case TcpConnection::UNEXPECTED_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ wsk_error = 1;
+ sprintf(wsk_emsg, "CSM-TELECOM: Send failed : %d", m_connection.ErrorCode());
+ break;
+ default:
+ break;
}
- // Should we recieve?
+
+ // Should we receive?
if ((fabs(simt - last_rx) / 0.005) < 1 || sat->agc.InterruptPending(ApolloGuidance::Interrupt::UPRUPT)) {
return; // No
}
last_rx = simt;
- bytesRecv = recv( AcceptSocket, (char *)(rx_data+rx_offset), 1, 0 );
- if(bytesRecv == SOCKET_ERROR){
- long errnumber = WSAGetLastError();
- switch(errnumber){
- // KNOWN CODES that we can ignore
- case 10035: // Operation Would Block
- // We can ignore this entirely. It's not an error.
- break;
-
- case 10053: // Software caused connection abort
- case 10038: // Socket isn't a socket
- case 10054: // Connection reset by peer
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
-
- default: // If unknown
- wsk_error = 1; // do this
- sprintf(wsk_emsg,"TELECOM: recv() failed: %ld",errnumber);
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
+ TcpConnection::CommandStatus status = m_connection.RecvChar((char *)(rx_data+rx_offset));
+ if(status != TcpConnection::OK){
+ switch (status) {
+ case TcpConnection::CONNECTION_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ break;
+ case TcpConnection::UNEXPECTED_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ wsk_error = 1;
+ sprintf(wsk_emsg, "CSM-TELECOM: Recv failed : %d", m_connection.ErrorCode());
+ break;
+ default:
+ break;
}
+
// Do we have data from MCC instead?
if (mcc_size > 0) {
// Yes. Take a byte
@@ -5079,28 +5022,12 @@ void PCM::perform_io(double simt){
mcc_offset = mcc_size = 0;
}
}
- }else{
+ } else {
// If the telemetry data-path is disconnected
- if(sat->UPTLMSwitch1.GetState() == TOGGLESWITCH_DOWN){
+ if(sat->UPTLMSwitch1.GetState() == TOGGLESWITCH_DOWN) {
return; // Discard the data
}
- if(bytesRecv > 0){
- handle_uplink();
- } else {
- // Do we have data from MCC instead?
- if (mcc_size > 0) {
- // Yes. Take a byte
- rx_data[rx_offset] = mcc_data[mcc_offset];
- mcc_offset++;
- // Handle it
- handle_uplink();
- // Are we done?
- if (mcc_offset >= mcc_size) {
- // We reached the end of the MCC buffer.
- mcc_offset = mcc_size = 0;
- }
- }
- }
+ handle_uplink();
}
break;
}
diff --git a/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.h b/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.h
index 33dbbf0e1c..516da9ab6d 100644
--- a/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.h
+++ b/Orbitersdk/samples/ProjectApollo/src_csm/csm_telecom.h
@@ -25,6 +25,7 @@
#include "RF_calc.h"
#include "paCBGmessageID.h"
+#include "socket.h"
/* PCM DOWN-TELEMETRY
@@ -342,11 +343,9 @@ class PCM {
void TimeStep(double simt); // TimeStep
void SystemTimestep(double simdt); // System Timestep (consume power)
- // Winsock2
- WSADATA wsaData; // Winsock subsystem data
- SOCKET m_socket; // TCP socket
- sockaddr_in service; // SOCKADDR_IN
- SOCKET AcceptSocket; // Accept Socket
+ // Network
+ TcpService m_tcpserver;
+ TcpConnection m_connection;
int conn_state; // Connection State
int uplink_state; // Uplink State
void perform_io(double simt); // Get data from here to there
diff --git a/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.cpp b/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.cpp
index ce224a30eb..2bb5ecec3b 100644
--- a/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.cpp
+++ b/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.cpp
@@ -27,7 +27,6 @@
#include "Orbitersdk.h"
#include
#include
-#include // TODO: Replace with winsock2 when yaAGC updates
#include "lmresource.h"
#include "nasspdefs.h"
@@ -374,16 +373,10 @@ LM_PCM::LM_PCM()
last_rx = 0;
frame_addr = 0;
frame_count = 0;
- m_socket = INVALID_SOCKET;
}
LM_PCM::~LM_PCM()
{
- // Close telemetry socket
- if (m_socket != INVALID_SOCKET) {
- shutdown(m_socket, 2); // Shutdown both streams
- closesocket(m_socket);
- }
}
void LM_PCM::Init(LEM *vessel, h_HeatLoad *pcmh)
@@ -397,48 +390,20 @@ void LM_PCM::Init(LEM *vessel, h_HeatLoad *pcmh)
last_update = 0;
last_rx = MINUS_INFINITY;
word_addr = 0;
- int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != NO_ERROR) {
- sprintf(wsk_emsg, "LM-TELECOM: Error at WSAStartup()");
+ if (!NetStartup()) {
+ sprintf(wsk_emsg, "LM-TELECOM: Error at Startup()");
wsk_error = 1;
return;
}
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- sprintf(wsk_emsg, "LM-TELECOM: Error at socket(): %ld", WSAGetLastError());
- WSACleanup();
- wsk_error = 1;
- return;
- }
- // Be nonblocking
- int iMode = 1; // 0 = BLOCKING, 1 = NONBLOCKING
- if (ioctlsocket(m_socket, FIONBIO, (u_long FAR*) &iMode) != 0) {
- sprintf(wsk_emsg, "LM-TELECOM: ioctlsocket() failed: %ld", WSAGetLastError());
- wsk_error = 1;
- closesocket(m_socket);
- WSACleanup();
- return;
- }
- // Set up incoming options
- service.sin_family = AF_INET;
- service.sin_addr.s_addr = htonl(INADDR_ANY);
- service.sin_port = htons(14243); // CM on 14242, LM on 14243
-
- if (::bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) {
- sprintf(wsk_emsg, "Failed to start LM telemetry. Please completely exit Orbiter and restart. Please file a bug report if this message persists.");
+ m_tcpserver = TcpService(14243); // CM on 14242, LM on 14243
+ if (m_tcpserver.Status() != TcpService::STARTED) {
+ sprintf(wsk_emsg, "LM-TELECOM: Error at socket(): %ld", m_tcpserver.ErrorCode());
+ NetCleanup();
wsk_error = 1;
- closesocket(m_socket);
- WSACleanup();
- return;
- }
- if (listen(m_socket, 1) == SOCKET_ERROR) {
- wsk_error = 1;
- sprintf(wsk_emsg, "LM-TELECOM: listen() failed: %ld", WSAGetLastError());
- closesocket(m_socket);
- WSACleanup();
return;
}
+
conn_state = 1; // INITIALIZED, LISTENING
uplink_state = 0; rx_offset = 0;
}
@@ -570,73 +535,52 @@ void LM_PCM::perform_io(double simt){
}
else {
// Try to accept
- AcceptSocket = accept(m_socket, NULL, NULL);
- if (AcceptSocket != INVALID_SOCKET) {
+ m_connection = m_tcpserver.Accept();
+ if (m_connection.Status() == TcpConnection::CONNECTED) {
conn_state = 2; // Accept this!
wsk_error = 0; // For now
}
}
// Otherwise loop and try again.
break;
- case 2: // CONNECTED
- int bytesSent,bytesRecv;
-
- bytesSent = send(AcceptSocket, (char *)tx_data, tx_size, 0 );
- if(bytesSent == SOCKET_ERROR){
- long errnumber = WSAGetLastError();
- switch(errnumber){
- // KNOWN CODES that we can ignore
- case 10035: // Operation Would Block
- // We can ignore this entirely. It's not an error.
- break;
-
- case 10038: // Socket isn't a socket
- case 10053: // Software caused connection abort
- case 10054: // Connection reset by peer
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
-
- default: // If unknown
- wsk_error = 1; // do this
- sprintf(wsk_emsg,"LM-TELECOM: send() failed: %ld",errnumber);
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
- }
+ case 2: // CONNECTED
+ switch (m_connection.Send((char*)tx_data, tx_size)) {
+ case TcpConnection::CONNECTION_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ break;
+ case TcpConnection::UNEXPECTED_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ wsk_error = 1;
+ sprintf(wsk_emsg, "LM-TELECOM: Send failed : %d", m_connection.ErrorCode());
+ break;
+ default:
+ break;
}
+
// Should we receive?
if (((simt - last_rx) / 0.005) < 1 || lem->agc.InterruptPending(ApolloGuidance::Interrupt::UPRUPT)) {
return; // No
}
last_rx = simt;
- bytesRecv = recv( AcceptSocket, (char *)(rx_data+rx_offset), 1, 0 );
- if(bytesRecv == SOCKET_ERROR){
- long errnumber = WSAGetLastError();
- switch(errnumber){
- // KNOWN CODES that we can ignore
- case 10035: // Operation Would Block
- // We can ignore this entirely. It's not an error.
- break;
-
- case 10053: // Software caused connection abort
- case 10038: // Socket isn't a socket
- case 10054: // Connection reset by peer
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
-
- default: // If unknown
- wsk_error = 1; // do this
- sprintf(wsk_emsg,"LM-TELECOM: recv() failed: %ld",errnumber);
- closesocket(AcceptSocket);
- conn_state = 1; // Accept another
- uplink_state = 0; rx_offset = 0;
- break;
+ TcpConnection::CommandStatus status = m_connection.RecvChar((char*)(rx_data + rx_offset));
+ if (status != TcpConnection::OK) {
+ switch (status) {
+ case TcpConnection::CONNECTION_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ break;
+ case TcpConnection::UNEXPECTED_ERROR:
+ conn_state = 1; // Accept another
+ uplink_state = 0; rx_offset = 0;
+ wsk_error = 1;
+ sprintf(wsk_emsg, "LM-TELECOM: Recv failed : %d", m_connection.ErrorCode());
+ break;
+ default:
+ break;
}
+
// Do we have data from MCC instead?
if (mcc_size > 0) {
// Yes. Take a byte
@@ -653,31 +597,13 @@ void LM_PCM::perform_io(double simt){
mcc_offset = mcc_size = 0;
}
}
- }else{
+ } else {
// FIXME: Check to make sure the up-data equipment is powered
// Reject uplink if switch is not down.
if(lem->COMM_UP_DATA_LINK_CB.IsPowered() == false || lem->Panel12UpdataLinkSwitch.GetState() != THREEPOSSWITCH_DOWN){
return; // Discard the data
}
- if(bytesRecv > 0){
- handle_uplink();
- }
- else
- {
- // Do we have data from MCC instead?
- if (mcc_size > 0) {
- // Yes. Take a byte
- rx_data[rx_offset] = mcc_data[mcc_offset];
- mcc_offset++;
- // Handle it
- handle_uplink();
- // Are we done?
- if (mcc_offset >= mcc_size) {
- // We reached the end of the MCC buffer.
- mcc_offset = mcc_size = 0;
- }
- }
- }
+ handle_uplink();
}
break;
}
diff --git a/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.h b/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.h
index f80c32a32b..32ecfe4ddc 100644
--- a/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.h
+++ b/Orbitersdk/samples/ProjectApollo/src_lm/lm_telecom.h
@@ -24,6 +24,7 @@
#include "RF_calc.h"
#include "paCBGmessageID.h"
+#include "socket.h"
/* PCM DOWN-TELEMETRY
@@ -251,11 +252,9 @@ class LM_PCM
LEM *lem; // Ship we're installed in
h_HeatLoad *PCMHeat; //PCM Heat Load
- // Winsock2
- WSADATA wsaData; // Winsock subsystem data
- SOCKET m_socket; // TCP socket
- sockaddr_in service; // SOCKADDR_IN
- SOCKET AcceptSocket; // Accept Socket
+ // Network
+ TcpService m_tcpserver;
+ TcpConnection m_connection;
int conn_state; // Connection State
int uplink_state; // Uplink State
void perform_io(double simt); // Get data from here to there
diff --git a/Orbitersdk/samples/ProjectApollo/src_mfd/ProjectApolloMFD.cpp b/Orbitersdk/samples/ProjectApollo/src_mfd/ProjectApolloMFD.cpp
index f23f650731..06aa7b5f42 100644
--- a/Orbitersdk/samples/ProjectApollo/src_mfd/ProjectApolloMFD.cpp
+++ b/Orbitersdk/samples/ProjectApollo/src_mfd/ProjectApolloMFD.cpp
@@ -49,6 +49,7 @@
#include "MFDResource.h"
#include "ProjectApolloMFD.h"
+#include "socket.h"
#include
@@ -101,10 +102,7 @@ static struct ProjectApolloMFDData { // global data storage
int killrot;
} g_Data;
-static WSADATA wsaData;
-static SOCKET m_socket;
-static sockaddr_in clientService;
-static SOCKET close_Socket = INVALID_SOCKET;
+static TcpConnection m_socket;
static char debugString[100];
static char debugStringBuffer[100];
static char debugWinsock[100];
@@ -136,12 +134,11 @@ void ProjectApolloMFDopcDLLInit (HINSTANCE hDLL)
//Init Emem
for(int i = 0; i < 24; i++)
g_Data.emem[i] = 0;
- int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
- if ( iResult != NO_ERROR ) {
- sprintf(debugWinsock,"ERROR AT WSAStartup()");
+ if (!NetStartup()) {
+ sprintf(debugWinsock, "ERROR AT NetStartup()");
}
else {
- sprintf(debugWinsock,"DISCONNECTED");
+ sprintf(debugWinsock, "DISCONNECTED");
}
g_Data.uplinkBufferSimt = 0;
g_Data.V42angles = _V(0, 0, 0);
@@ -351,24 +348,15 @@ void uplink_aeaa_cmd(bool arm, bool set)
void UplinkLMRTC(bool arm, bool set)
{
if (g_Data.connStatus == 0) {
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
+ if (g_Data.uplinkLEM > 0) {
+ m_socket = TcpConnection("127.0.0.1", 14243);
+ }
+ else {
+ m_socket = TcpConnection("127.0.0.1", 14242);
}
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
- if (g_Data.uplinkLEM > 0) { clientService.sin_port = htons(14243); }
- else { clientService.sin_port = htons(14242); }
- if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
sprintf(debugWinsock, "CONNECTED");
@@ -381,24 +369,16 @@ void UplinkLMRTC(bool arm, bool set)
void UplinkData()
{
if (g_Data.connStatus == 0) {
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
char buffer[8];
- m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
- if ( m_socket == INVALID_SOCKET ) {
- g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock,"ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
+ if(g_Data.uplinkLEM > 0) {
+ m_socket = TcpConnection("127.0.0.1", 14243);
}
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
- if(g_Data.uplinkLEM > 0){ clientService.sin_port = htons( 14243 ); }else{ clientService.sin_port = htons( 14242 ); }
- if (connect( m_socket, (SOCKADDR*) &clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ else {
+ m_socket = TcpConnection("127.0.0.1", 14242);
+ }
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock,"FAILED TO CONNECT, ERROR %ld",WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
sprintf(debugWinsock, "CONNECTED");
@@ -429,27 +409,19 @@ void UpdateClock()
{
if (g_Data.connStatus == 0)
{
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
char buffer[8];
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- g_Data.updateClockReady = 0;
- sprintf(debugWinsock, "ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
+ if (g_Data.uplinkLEM > 0) {
+ m_socket = TcpConnection("127.0.0.1", 14243);
}
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
- if (g_Data.uplinkLEM > 0) { clientService.sin_port = htons(14243); }
- else { clientService.sin_port = htons(14242); }
- if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ else {
+ m_socket = TcpConnection("127.0.0.1", 14242);
+ }
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
g_Data.updateClockReady = 0;
- sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
+
sprintf(debugWinsock, "CONNECTED");
g_Data.uplinkState = 0;
send_agc_key('V');
@@ -530,24 +502,15 @@ void UplinkSunburstSuborbitalAbort()
if (g_Data.connStatus == 0)
{
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
+ if (g_Data.uplinkLEM > 0) {
+ m_socket = TcpConnection("127.0.0.1", 14243);
+ }
+ else {
+ m_socket = TcpConnection("127.0.0.1", 14242);
}
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
- if (g_Data.uplinkLEM > 0) { clientService.sin_port = htons(14243); }
- else { clientService.sin_port = htons(14242); }
- if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
sprintf(debugWinsock, "CONNECTED");
@@ -565,24 +528,15 @@ void UplinkSunburstCOI()
if (g_Data.connStatus == 0)
{
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
+ if (g_Data.uplinkLEM > 0) {
+ m_socket = TcpConnection("127.0.0.1", 14243);
+ }
+ else {
+ m_socket = TcpConnection("127.0.0.1", 14242);
}
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
- if (g_Data.uplinkLEM > 0) { clientService.sin_port = htons(14243); }
- else { clientService.sin_port = htons(14242); }
- if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
sprintf(debugWinsock, "CONNECTED");
@@ -599,7 +553,7 @@ void ProjectApolloMFDopcTimestep (double simt, double simdt, double mjd)
if (g_Data.connStatus > 0 && g_Data.uplinkBuffer.size() > 0) {
if (simt > g_Data.uplinkBufferSimt + 0.1) {
unsigned char data = g_Data.uplinkBuffer.front();
- send(m_socket, (char *) &data, 1, 0);
+ m_socket.Send((char *) &data, 1);
g_Data.uplinkBuffer.pop();
g_Data.uplinkBufferSimt = simt;
}
@@ -609,7 +563,7 @@ void ProjectApolloMFDopcTimestep (double simt, double simdt, double mjd)
g_Data.uplinkDataReady = 0;
g_Data.updateClockReady = 0;
g_Data.connStatus = 0;
- closesocket(m_socket);
+ m_socket.Close();
} else if (g_Data.connStatus == 2 && g_Data.updateClockReady == 2) {
UpdateClock();
}
diff --git a/Orbitersdk/samples/ProjectApollo/src_rtccmfd/ARCore.cpp b/Orbitersdk/samples/ProjectApollo/src_rtccmfd/ARCore.cpp
index ad63290a39..fc78018112 100644
--- a/Orbitersdk/samples/ProjectApollo/src_rtccmfd/ARCore.cpp
+++ b/Orbitersdk/samples/ProjectApollo/src_rtccmfd/ARCore.cpp
@@ -15,13 +15,11 @@
#include "TLMCC.h"
#include "rtcc.h"
#include "nassputils.h"
+#include "socket.h"
using namespace nassp;
-static WSADATA wsaData;
-static SOCKET m_socket;
-static sockaddr_in clientService;
-static SOCKET close_Socket = INVALID_SOCKET;
+static TcpConnection m_socket;
static char debugString[100];
static char debugStringBuffer[100];
static char debugWinsock[100];
@@ -475,9 +473,9 @@ ARCore::ARCore(VESSEL* v, AR_GCore* gcin)
{
g_Data.emem[i] = 0;
}
- int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (iResult != NO_ERROR) {
- sprintf(debugWinsock, "ERROR AT WSAStartup()");
+
+ if(!NetStartup()) {
+ sprintf(debugWinsock, "ERROR AT NetStartup()");
}
else {
sprintf(debugWinsock, "DISCONNECTED");
@@ -817,7 +815,7 @@ void ARCore::MinorCycle(double SimT, double SimDT, double mjd)
if (g_Data.connStatus > 0 && g_Data.uplinkBuffer.size() > 0) {
if (SimT > g_Data.uplinkBufferSimt + 0.1) {
unsigned char data = g_Data.uplinkBuffer.front();
- send(m_socket, (char *)&data, 1, 0);
+ m_socket.Send((char *)&data, 1);
g_Data.uplinkBuffer.pop();
g_Data.uplinkBufferSimt = SimT;
}
@@ -826,7 +824,7 @@ void ARCore::MinorCycle(double SimT, double SimDT, double mjd)
if (g_Data.connStatus == 1) {
sprintf(debugWinsock, "DISCONNECTED");
g_Data.connStatus = 0;
- closesocket(m_socket);
+ m_socket.Close();
}
}
}
@@ -2145,31 +2143,18 @@ void ARCore::AP12AbortCoefUplink()
void ARCore::UplinkData(bool isCSM)
{
if (g_Data.connStatus == 0) {
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
char buffer[8];
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- //g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
- }
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
if (isCSM)
{
- clientService.sin_port = htons(14242);
+ m_socket = TcpConnection("127.0.0.1", 14242);
}
else
{
- clientService.sin_port = htons(14243);
+ m_socket = TcpConnection("127.0.0.1", 14243);
}
- if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
//g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
sprintf(debugWinsock, "CONNECTED");
@@ -2201,33 +2186,21 @@ void ARCore::UplinkData(bool isCSM)
void ARCore::UplinkData2(bool isCSM)
{
if (g_Data.connStatus == 0) {
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
char buffer[8];
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- //g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
- }
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
if (isCSM)
{
- clientService.sin_port = htons(14242);
+ m_socket = TcpConnection("127.0.0.1", 14242);
}
else
{
- clientService.sin_port = htons(14243);
+ m_socket = TcpConnection("127.0.0.1", 14243);
}
- if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
//g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
+
sprintf(debugWinsock, "CONNECTED");
g_Data.uplinkState = 0;
send_agc_key('V', isCSM);
@@ -2257,33 +2230,21 @@ void ARCore::UplinkData2(bool isCSM)
void ARCore::UplinkDataV70V73(bool v70, bool isCSM)
{
if (g_Data.connStatus == 0) {
- int bytesRecv = SOCKET_ERROR;
- char addr[256];
char buffer[8];
- m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (m_socket == INVALID_SOCKET) {
- //g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "ERROR AT SOCKET(): %ld", WSAGetLastError());
- closesocket(m_socket);
- return;
- }
- sprintf(addr, "127.0.0.1");
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr(addr);
if (isCSM)
{
- clientService.sin_port = htons(14242);
+ m_socket = TcpConnection("127.0.0.1", 14242);
}
else
{
- clientService.sin_port = htons(14243);
+ m_socket = TcpConnection("127.0.0.1", 14243);
}
- if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ if (m_socket.Status() != TcpConnection::CONNECTED) {
//g_Data.uplinkDataReady = 0;
- sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", WSAGetLastError());
- closesocket(m_socket);
+ sprintf(debugWinsock, "FAILED TO CONNECT, ERROR %ld", m_socket.ErrorCode());
return;
}
+
sprintf(debugWinsock, "CONNECTED");
g_Data.uplinkState = 0;
send_agc_key('V', isCSM);
diff --git a/Orbitersdk/samples/ProjectApollo/src_sys/socket.cpp b/Orbitersdk/samples/ProjectApollo/src_sys/socket.cpp
new file mode 100644
index 0000000000..f955584964
--- /dev/null
+++ b/Orbitersdk/samples/ProjectApollo/src_sys/socket.cpp
@@ -0,0 +1,287 @@
+/***************************************************************************
+ This file is part of Project Apollo - NASSP
+ Copyright 2023
+
+ Project Apollo is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ Project Apollo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Project Apollo; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ See http://nassp.sourceforge.net/license/ for more details.
+
+ **************************************************************************/
+
+#include "socket.h"
+
+#ifdef __unix
+#include
+#include
+#include
+#include
+#include
+#include
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define SOCKADDR sockaddr
+#define closesocket close
+#define ioctlsocket ioctl
+#endif
+
+static int NativeError() {
+#ifdef _WIN32
+ return WSAGetLastError();
+#elif __unix
+ return errno;
+#endif
+}
+
+bool NetStartup() {
+#ifdef _WIN32
+ WSADATA wsaData;
+ int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
+ return (iResult == NO_ERROR);
+#else
+ return true;
+#endif
+}
+void NetCleanup() {
+#ifdef _WIN32
+ WSACleanup();
+#endif
+}
+
+TcpConnection::TcpConnection() {
+ m_error = 0;
+ m_status = ConnectionStatus::UNINITIALIZED;
+ m_socket = INVALID_SOCKET;
+}
+
+TcpConnection::TcpConnection(const char *dst, uint16_t tcpport) {
+ m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_socket == INVALID_SOCKET) {
+ m_status = ConnectionStatus::UNINITIALIZED;
+ m_error = NativeError();
+ return;
+ }
+
+ sockaddr_in clientService;
+ clientService.sin_family = AF_INET;
+ clientService.sin_addr.s_addr = inet_addr(dst);
+ clientService.sin_port = htons(tcpport);
+
+ if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR) {
+ m_status = ConnectionStatus::UNINITIALIZED;
+ m_error = NativeError();
+ Close();
+ return;
+ }
+ m_status = ConnectionStatus::CONNECTED;
+}
+
+TcpConnection::TcpConnection(TcpConnection&& from) noexcept {
+ m_error = from.m_error;
+ m_status = from.m_status;
+ m_socket = from.m_socket;
+ from.m_socket = INVALID_SOCKET;
+ from.m_status = ConnectionStatus::UNINITIALIZED;
+}
+
+TcpConnection& TcpConnection::operator=(TcpConnection&& from) noexcept {
+ Close();
+ m_error = from.m_error;
+ m_status = from.m_status;
+ m_socket = from.m_socket;
+ from.m_socket = INVALID_SOCKET;
+ from.m_status = ConnectionStatus::UNINITIALIZED;
+ return *this;
+}
+
+TcpConnection::~TcpConnection() {
+ Close();
+}
+
+TcpConnection::CommandStatus TcpConnection::HandleError() noexcept {
+ m_error = NativeError();
+ switch (m_error) {
+#ifdef _WIN32
+ // KNOWN CODES that we can ignore
+ case 10035: // Operation Would Block
+ // We can ignore this entirely. It's not an error.
+ m_error = 0;
+ return CommandStatus::RETRY;
+
+ case 10038: // Socket isn't a socket
+ case 10053: // Software caused connection abort
+ case 10054: // Connection reset by peer
+ Close();
+ return CommandStatus::CONNECTION_ERROR;
+#elif __unix
+ case EAGAIN:
+#if EAGAIN != EWOULDBLOCK
+ case EWOULDBLOCK:
+#endif
+ case EINTR:
+ m_error = 0;
+ return CommandStatus::RETRY;
+ case EBADF:
+ case ECONNRESET:
+ case ENOTCONN:
+ case ENOTSOCK:
+ case EPIPE:
+ Close();
+ return CommandStatus::CONNECTION_ERROR;
+#else
+#error Platform not supported
+#endif
+ default: // If unknown
+ Close();
+ return CommandStatus::UNEXPECTED_ERROR;
+ }
+}
+
+TcpConnection::CommandStatus TcpConnection::Send(const char* buf, size_t len) noexcept {
+ m_error = 0;
+ int bytesSent = send(m_socket, buf, len, 0);
+ if (bytesSent == SOCKET_ERROR) {
+ return HandleError();
+ }
+ return OK;
+}
+
+TcpConnection::CommandStatus TcpConnection::RecvChar(char* buf) noexcept {
+ int bytesRecv = recv(m_socket, buf, 1, 0);
+ if (bytesRecv == SOCKET_ERROR) {
+ return HandleError();
+ }
+ m_error = 0;
+ return OK;
+}
+
+void TcpConnection::Close() noexcept {
+ if (m_socket != INVALID_SOCKET) {
+ shutdown(m_socket, 2); // Shutdown both streams
+ closesocket(m_socket);
+ m_socket = INVALID_SOCKET;
+ }
+ m_status = ConnectionStatus::UNINITIALIZED;
+}
+
+TcpConnection::TcpConnection(NativeSocket s) {
+ m_error = 0;
+ m_socket = s;
+ m_status = ConnectionStatus::CONNECTED;
+}
+
+
+TcpService::TcpService() {
+ m_status = ServiceStatus::DISABLED;
+}
+
+TcpService::TcpService(TcpService&& from) noexcept {
+ m_status = from.m_status;
+ m_socket = from.m_socket;
+ m_error = from.m_error;
+ from.m_status = TcpService::DISABLED;
+ from.m_socket = INVALID_SOCKET;
+}
+
+TcpService& TcpService::operator=(TcpService&& from) noexcept {
+ m_status = from.m_status;
+ m_socket = from.m_socket;
+ m_error = from.m_error;
+ from.m_status = TcpService::DISABLED;
+ from.m_socket = INVALID_SOCKET;
+ return *this;
+}
+
+TcpService::~TcpService() {
+ if (m_socket != INVALID_SOCKET) {
+ closesocket(m_socket);
+ }
+}
+
+TcpService::TcpService(uint16_t tcpport) {
+ m_status = ServiceStatus::DISABLED;
+
+ sockaddr_in service;
+ m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_socket == INVALID_SOCKET) {
+ m_error = NativeError();
+ NetCleanup();
+ return;
+ }
+ // Be nonblocking
+ int iMode = 1; // 0 = BLOCKING, 1 = NONBLOCKING
+ if (ioctlsocket(m_socket, FIONBIO, (u_long *) & iMode) != 0) {
+ m_error = NativeError();
+ closesocket(m_socket);
+ NetCleanup();
+ return;
+ }
+
+ // Set up incoming options
+ service.sin_family = AF_INET;
+ service.sin_addr.s_addr = htonl(INADDR_ANY);
+ service.sin_port = htons(tcpport);
+
+ if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) {
+ m_error = NativeError();
+ closesocket(m_socket);
+ NetCleanup();
+ return;
+ }
+ if (listen(m_socket, 1) == SOCKET_ERROR) {
+ m_error = NativeError();
+ closesocket(m_socket);
+ NetCleanup();
+ return;
+ }
+
+ m_status = ServiceStatus::STARTED;
+ return;
+}
+
+TcpConnection TcpService::Accept() noexcept {
+ NativeSocket s = accept(m_socket, NULL, NULL);
+ if (s == INVALID_SOCKET) {
+ m_error = NativeError();
+ return TcpConnection();
+ }
+ else {
+ m_error = 0;
+ return TcpConnection(s);
+ }
+}
+
+#if 0
+// TcpService::Accept can be modified to investigate performance impact with time acceleration
+#include
+TcpConnection TcpService::Accept() noexcept {
+ static std::chrono::time_point time_prev = std::chrono::steady_clock::now();
+ std::chrono::time_point time_now = std::chrono::steady_clock::now();
+
+ // Limit accept call to 10Hz real-time
+ if (time_now - time_prev > std::chrono::microseconds(100000)) {
+ NativeSocket s = accept(m_socket, NULL, NULL);
+ time_prev = time_now;
+ if (s == INVALID_SOCKET) {
+ m_error = NativeError();
+ return TcpConnection();
+ }
+ else {
+ m_error = 0;
+ return TcpConnection(s);
+ }
+ }
+ return TcpConnection();
+}
+#endif
diff --git a/Orbitersdk/samples/ProjectApollo/src_sys/socket.h b/Orbitersdk/samples/ProjectApollo/src_sys/socket.h
new file mode 100644
index 0000000000..120d3ff006
--- /dev/null
+++ b/Orbitersdk/samples/ProjectApollo/src_sys/socket.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+ This file is part of Project Apollo - NASSP
+ Copyright 2023
+
+ Project Apollo is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ Project Apollo is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Project Apollo; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ See http://nassp.sourceforge.net/license/ for more details.
+
+ **************************************************************************/
+#pragma once
+#include
+#include
+
+#ifdef _WIN32
+#include
+using NativeSocket = SOCKET;
+#elif __unix
+using NativeSocket = int;
+#else
+#error Platform not supported
+#endif
+
+// Initialize the network subsystem
+bool NetStartup();
+
+// Close the network subsystem
+void NetCleanup();
+
+class TcpService;
+
+// Move only class that encapsulates a non blocking TCP socket used for reading/writing
+// Can be created directly by specifying a destination and port to connect to
+// or indirectly by a TcpService instance
+class TcpConnection {
+ friend TcpService;
+public:
+ typedef enum {
+ UNINITIALIZED,
+ CONNECTED
+ } ConnectionStatus;
+
+ typedef enum {
+ OK,
+ RETRY,
+ CONNECTION_ERROR,
+ UNEXPECTED_ERROR
+ } CommandStatus;
+
+ // Create a default UNINITIALIZED TcpConnection
+ TcpConnection();
+
+ // Tries to connect to the specified address/port and updates m_status and m_error accordingly
+ TcpConnection(const char *dst, uint16_t tcpport);
+
+ // Move only semantics
+ TcpConnection(const TcpConnection&) = delete;
+ TcpConnection& operator=(TcpConnection const&) = delete;
+ TcpConnection(TcpConnection&& from) noexcept;
+ TcpConnection& operator=(TcpConnection&& from) noexcept;
+
+ // Close() is called upon destruction
+ ~TcpConnection();
+ ConnectionStatus Status() noexcept { return m_status; }
+
+ // Tries to send len bytes to the other peer
+ // Return value:
+ // - OK: the data was sent successfully
+ // - CONNECTION_ERROR: the connection was closed
+ // - UNEXPECTED_ERROR: an unexpected error occured
+ // - RETRY : no data could be sent without blocking
+ // m_status and m_error are updated accordingly
+ CommandStatus Send(const char* buf, size_t len) noexcept;
+
+ // Tries to read one byte from the other peer
+ // Return value:
+ // - OK: the data was read successfully
+ // - CONNECTION_ERROR: the connection was closed
+ // - UNEXPECTED_ERROR: an unexpected error occured
+ // - RETRY : no data was available
+ // m_status and m_error are updated accordingly
+ CommandStatus RecvChar(char* buf) noexcept;
+
+ int ErrorCode() noexcept { return m_error; }
+
+ // Close the connection and sets its status to UNINITIALIZED
+ void Close() noexcept;
+
+private:
+ // Used by TcpService
+ TcpConnection(NativeSocket s);
+
+ CommandStatus HandleError() noexcept;
+
+ ConnectionStatus m_status;
+ NativeSocket m_socket;
+ int m_error;
+};
+
+// Move only class that encapsulates a TCP "server" socket
+// Only one client is accepted in the socket queue
+class TcpService {
+public:
+ typedef enum {
+ DISABLED,
+ STARTED
+ } ServiceStatus;
+
+ // Create a default DISABLED TcpService
+ TcpService();
+
+ // Create a new service listening on all interfaces on tcpport
+ // Sets m_status and m_error accordingly
+ TcpService(uint16_t tcpport);
+
+ // Move only semantics
+ TcpService(const TcpService&) = delete;
+ TcpService& operator=(TcpService const&) = delete;
+ TcpService(TcpService&& from) noexcept;
+ TcpService& operator=(TcpService&& from) noexcept;
+
+ // The socket is closed on destruction
+ ~TcpService();
+
+ // Accepts a new connection if a client is trying to connect to the service (non blocking)
+ // Returns:
+ // - a CONNECTED TcpConnection if a client connected to the service
+ // - an UNINITIALIZED TcpConnection if there was no client
+ TcpConnection Accept() noexcept;
+
+ ServiceStatus Status() noexcept { return m_status; };
+ int ErrorCode() noexcept { return m_error; }
+
+private:
+ ServiceStatus m_status;
+ NativeSocket m_socket;
+ int m_error;
+};