Updated plugin.

- Removed dependency on C client.
 - The plugin now responds to client requests on the same port used to establish the connection.
Removed C client dependency from plugin.
This commit is contained in:
Jason Watkins
2015-04-16 16:50:05 -07:00
parent 55f3953955
commit 5ee49c7d81
9 changed files with 146 additions and 153 deletions

View File

@@ -3,12 +3,17 @@
#ifndef XPC_DRAWING_H #ifndef XPC_DRAWING_H
#define XPC_DRAWING_H #define XPC_DRAWING_H
#include "xplaneConnect.h"
#include <cstdlib> #include <cstdlib>
namespace XPC namespace XPC
{ {
typedef struct
{
double latitude;
double longitude;
double altitude;
} Waypoint;
/// Handles tasks that involve drawing to the screen in X-Plane. /// Handles tasks that involve drawing to the screen in X-Plane.
/// ///
/// \author Jason Watkins /// \author Jason Watkins

View File

@@ -2,7 +2,6 @@
//National Aeronautics and Space Administration. All Rights Reserved. //National Aeronautics and Space Administration. All Rights Reserved.
#include "Message.h" #include "Message.h"
#include "Log.h" #include "Log.h"
#include "xplaneConnect.h"
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
@@ -71,6 +70,7 @@ namespace XPC
} }
Log::WriteLine(ss.str()); Log::WriteLine(ss.str());
ss << std::dec;
ss.str(""); ss.str("");
ss << "[" << GetHead() << "-DEBUG] (" << GetSize() << ")"; ss << "[" << GetHead() << "-DEBUG] (" << GetSize() << ")";
switch (GetMagicNumber()) // Binary version of head switch (GetMagicNumber()) // Binary version of head
@@ -84,25 +84,41 @@ namespace XPC
} }
case 0x4C525443: // CTRL case 0x4C525443: // CTRL
{ {
xpcCtrl ctrl = parseCTRL((char*)buffer); // Parse message data
ss << " (" << ctrl.pitch << " " << ctrl.roll << " " << ctrl.yaw << ") "; float pitch = *((float*)(buffer + 5));
ss << ctrl.throttle << " " << ctrl.gear << " " << ctrl.flaps; float roll = *((float*)(buffer + 9));
float yaw = *((float*)(buffer + 13));
float thr = *((float*)(buffer + 17));
char gear = buffer[21];
float flaps = *((float*)(buffer + 22));
std::uint8_t aircraft = 0;
if (size == 27)
{
aircraft = buffer[26];
}
ss << " Attitude:(" << pitch << " " << roll << " " << yaw << ")";
ss << " Thr:" << thr << " Gear:" << (int)gear << " Flaps:" << flaps;
Log::WriteLine(ss.str()); Log::WriteLine(ss.str());
break; break;
} }
case 0x41544144: // DATA case 0x41544144: // DATA
{ {
float dataRef[30][9]; std::size_t numCols = (size - 5) / 36;
short numCols = parseDATA((char*)buffer, size, dataRef); float values[32][9];
for (int i = 0; i < numCols; ++i)
{
values[i][0] = buffer[5 + 36 * i];
memcpy(values[i] + 1, buffer + 9 + 36 * i, 9 * sizeof(float));
}
ss << " (" << numCols << " lines)"; ss << " (" << numCols << " lines)";
Log::WriteLine(ss.str()); Log::WriteLine(ss.str());
for (int i = 0; i < numCols; ++i) for (int i = 0; i < numCols; ++i)
{ {
ss.str(""); ss.str("");
ss << "\t#" << dataRef[i][0]; ss << "\t#" << values[i][0];
for (int j = 1; j < 9; ++j) for (int j = 1; j < 9; ++j)
{ {
ss << " " << dataRef[i][j]; ss << " " << values[i][j];
} }
Log::WriteLine(ss.str()); Log::WriteLine(ss.str());
} }
@@ -136,14 +152,16 @@ namespace XPC
break; break;
} }
case 0x49534F50: // POSI case 0x49534F50: // POSI
{ {
float position[6] = { 0.0 }; char aircraft = buffer[5];
short aircraft = 0; float gear = *((float*)(buffer + 30));
float gear = -1.0; float pos[3];
aircraft = parsePOSI((char*)buffer, position, 6, &gear); float orient[3];
ss << ' ' << aircraft; memcpy(pos, buffer + 6, 12);
ss << " (" << position[0] << ' ' << position[1] << ' ' << position[2] << ") ("; memcpy(orient, buffer + 18, 12);
ss << position[3] << ' ' << position[4] << ' ' << position[5] << ") "; ss << " AC:" << (int)aircraft;
ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:(";
ss << orient[3] << ' ' << orient[4] << ' ' << orient[5] << ") Gear:";
ss << gear; ss << gear;
Log::WriteLine(ss.str()); Log::WriteLine(ss.str());
break; break;

View File

@@ -55,48 +55,6 @@ namespace XPC
MessageHandlers::sock = socket; MessageHandlers::sock = socket;
} }
static std::string getIP(sockaddr* sa)
{
char ip[INET6_ADDRSTRLEN + 6] = { 0 };
switch (sa->sa_family)
{
case AF_INET:
{
sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(sa);
inet_ntop(AF_INET, &sin->sin_addr, ip, INET6_ADDRSTRLEN);
break;
}
case AF_INET6:
{
sockaddr_in6* sin = reinterpret_cast<sockaddr_in6*>(sa);
inet_ntop(AF_INET6, &sin->sin6_addr, ip, INET6_ADDRSTRLEN);
break;
}
default:
return "UNKNOWN";
}
return std::string(ip);
}
static std::uint16_t getPort(sockaddr* sa)
{
switch (sa->sa_family)
{
case AF_INET:
{
sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sa);
return ntohs((*sin).sin_port);
}
case AF_INET6:
{
sockaddr_in6 *sin = reinterpret_cast<sockaddr_in6*>(sa);
return ntohs((*sin).sin6_port);
}
default:
return ~0;
}
}
void MessageHandlers::HandleMessage(Message& msg) void MessageHandlers::HandleMessage(Message& msg)
{ {
// Make sure we really have a message to handle. // Make sure we really have a message to handle.
@@ -109,9 +67,7 @@ namespace XPC
// Set current connection // Set current connection
sockaddr sourceaddr = msg.GetSource(); sockaddr sourceaddr = msg.GetSource();
std::string ip = getIP(&sourceaddr); connectionKey = UDPSocket::GetHost(&sourceaddr);
std::uint16_t port = getPort(&sourceaddr);
connectionKey = ip + ":" + std::to_string(port);
#if LOG_VERBOSITY > 4 #if LOG_VERBOSITY > 4
Log::FormatLine("[MSGH] Handling message from %s", connectionKey.c_str()); Log::FormatLine("[MSGH] Handling message from %s", connectionKey.c_str());
#endif #endif
@@ -124,22 +80,20 @@ namespace XPC
// to connections. As long as we never remove elements, the size of // to connections. As long as we never remove elements, the size of
// connections will serve as a unique id. // connections will serve as a unique id.
connections.size(), connections.size(),
ip, sourceaddr,
49008, // By default, send information to the client on this port.
port,
0 0
}; };
connections[connectionKey] = connection; connections[connectionKey] = connection;
#if LOG_VERBOSITY > 4 #if LOG_VERBOSITY > 2
Log::FormatLine("[MSGH] New connection. ID=%u, Remote=%s:%u", connection.id, ip.c_str(), port); Log::FormatLine("[MSGH] New connection. ID=%u, Remote=%s", connection.id, connectionKey.c_str());
#endif #endif
} }
else else
{ {
connection = (*conn).second; connection = (*conn).second;
#if LOG_VERBOSITY > 4 #if LOG_VERBOSITY > 3
Log::FormatLine("[MSGH] Existing connection. ID=%u, Remote=%s:%u", Log::FormatLine("[MSGH] Existing connection. ID=%u, Remote=%s",
connection.id, connection.ip.c_str(), connection.srcPort); connection.id, connectionKey.c_str());
#endif #endif
} }
@@ -162,7 +116,30 @@ namespace XPC
const std::uint8_t* buffer = msg.GetBuffer(); const std::uint8_t* buffer = msg.GetBuffer();
// Store new port // Store new port
connection.dstPort = *((std::uint16_t*)(buffer + 5)); std::uint16_t port = *((std::uint16_t*)(buffer + 5));
sockaddr* sa = &connection.addr;
switch (sa->sa_family)
{
case AF_INET:
{
sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(sa);
(*sin).sin_port = htons(port);
break;
}
case AF_INET6:
{
sockaddr_in6* sin = reinterpret_cast<sockaddr_in6*>(sa);
(*sin).sin6_port = htons(port);
break;
}
default:
#if LOG_VERBOSITY > 0
Log::WriteLine("[CONN] ERROR: Unknown address type.");
return;
#endif
}
connections.erase(connectionKey);
connectionKey = UDPSocket::GetHost(&connection.addr);
connections[connectionKey] = connection; connections[connectionKey] = connection;
// Create response // Create response
@@ -170,19 +147,19 @@ namespace XPC
response[5] = connection.id; response[5] = connection.id;
// Update log // Update log
#if LOG_VERBOSITY > 0 #if LOG_VERBOSITY > 1
Log::FormatLine("[CONN] ID: %u New destination port: %u", Log::FormatLine("[CONN] ID: %u New destination port: %u",
connection.id, connection.dstPort); connection.id, port);
#endif #endif
// Send response // Send response
sock->SendTo(response, 6, connection.ip, connection.dstPort); sock->SendTo(response, 6, &connection.addr);
} }
void MessageHandlers::HandleCtrl(Message& msg) void MessageHandlers::HandleCtrl(Message& msg)
{ {
// Update Log // Update Log
#if LOG_VERBOSITY > 0 #if LOG_VERBOSITY > 2
Log::FormatLine("[CTRL] Message Received (Conn %i)", connection.id); Log::FormatLine("[CTRL] Message Received (Conn %i)", connection.id);
#endif #endif
@@ -192,7 +169,7 @@ namespace XPC
//Packets specifying an A/C num should be 27 bytes. //Packets specifying an A/C num should be 27 bytes.
if (size != 26 && size != 27) if (size != 26 && size != 27)
{ {
#if LOG_VERBOSITY > 1 #if LOG_VERBOSITY > 0
Log::FormatLine("[CTRL] ERROR: Unexpected message length (%i)", size); Log::FormatLine("[CTRL] ERROR: Unexpected message length (%i)", size);
#endif #endif
return; return;
@@ -244,20 +221,20 @@ namespace XPC
std::size_t numCols = (size - 5) / 36; std::size_t numCols = (size - 5) / 36;
if (numCols > 0) if (numCols > 0)
{ {
#if LOG_VERBOSITY > 3 #if LOG_VERBOSITY > 2
Log::FormatLine("[DATA] Message Received (Conn %i)", connection.id); Log::FormatLine("[DATA] Message Received (Conn %i)", connection.id);
#endif #endif
} }
if (numCols > 32) // Error. Will overflow values if (numCols > 32) // Error. Will overflow values
{ {
#if LOG_VERBOSITY > 2 #if LOG_VERBOSITY > 0
Log::FormatLine("[DATA] ERROR numCols to large."); Log::FormatLine("[DATA] ERROR numCols to large.");
#endif #endif
return; return;
} }
else else
{ {
#if LOG_VERBOSITY > 2 #if LOG_VERBOSITY > 1
Log::FormatLine("[DATA] WARNING: Empty data packet received (Conn %i)", connection.id); Log::FormatLine("[DATA] WARNING: Empty data packet received (Conn %i)", connection.id);
#endif #endif
return; return;
@@ -462,7 +439,7 @@ namespace XPC
cur += count * sizeof(float); cur += count * sizeof(float);
} }
sock->SendTo(response, cur, connection.ip, connection.dstPort); sock->SendTo(response, cur, &connection.addr);
} }
void MessageHandlers::HandlePosi(Message& msg) void MessageHandlers::HandlePosi(Message& msg)
@@ -599,13 +576,13 @@ namespace XPC
#endif #endif
switch (op) switch (op)
{ {
case xpc_WYPT_ADD: case 1:
Drawing::AddWaypoints(points, count); Drawing::AddWaypoints(points, count);
break; break;
case xpc_WYPT_DEL: case 2:
Drawing::RemoveWaypoints(points, count); Drawing::RemoveWaypoints(points, count);
break; break;
case xpc_WYPT_CLR: case 3:
Drawing::ClearWaypoints(); Drawing::ClearWaypoints();
break; break;
default: default:
@@ -621,7 +598,11 @@ namespace XPC
#if LOG_VERBOSITY > 1 #if LOG_VERBOSITY > 1
Log::WriteLine("[MSGH] Sending raw data to X-Plane"); Log::WriteLine("[MSGH] Sending raw data to X-Plane");
#endif #endif
sock->SendTo((std::uint8_t*)msg.GetBuffer(), msg.GetSize(), "127.0.0.1", 49000); sockaddr_in loopback;
loopback.sin_family = AF_INET;
loopback.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
loopback.sin_port = htons(49000);
sock->SendTo((std::uint8_t*)msg.GetBuffer(), msg.GetSize(), (sockaddr*)&loopback);
} }
void MessageHandlers::HandleUnknown(Message& msg) void MessageHandlers::HandleUnknown(Message& msg)

View File

@@ -53,9 +53,7 @@ namespace XPC
typedef struct typedef struct
{ {
std::uint8_t id; std::uint8_t id;
std::string ip; sockaddr addr;
std::uint16_t dstPort;
std::uint16_t srcPort;
std::uint8_t getdCount; std::uint8_t getdCount;
std::string getdRequest[255]; std::string getdRequest[255];
} ConnectionInfo; } ConnectionInfo;

View File

@@ -131,41 +131,49 @@ namespace XPC
return status; return status;
} }
// TODO: Add IPV6 support void UDPSocket::SendTo(std::uint8_t* buffer, std::size_t len, sockaddr* remote)
void UDPSocket::SendTo(std::uint8_t* buffer, std::size_t len, std::string remoteHost, std::uint16_t remotePort)
{ {
#if LOG_VERBOSITY > 4
Log::FormatLine("[SOCK] Sending message to %s:%u (length=%u)", remoteHost.c_str(), remotePort, len);
#endif
if (remoteHost == "localhost")
{
remoteHost = "127.0.0.1";
}
std::uint32_t ip;
inet_pton(AF_INET, remoteHost.c_str(), &ip);
SendTo(buffer, len, ip, remotePort);
}
void UDPSocket::SendTo(std::uint8_t* buffer, std::size_t len, std::uint32_t remoteIP, std::uint16_t remotePort)
{
struct sockaddr_in remoteAddr;
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_port = htons(remotePort);
remoteAddr.sin_addr.s_addr = remoteIP;
#ifdef _WIN32
const char on = 1;
#else
int on = 1;
#endif
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
buffer[4] = (std::uint8_t)len; buffer[4] = (std::uint8_t)len;
if (sendto(sock, (char*)buffer, (int)len, 0, (const struct sockaddr *) &remoteAddr, sizeof(remoteAddr)) < 0) if (sendto(sock, (char*)buffer, (int)len, 0, remote, sizeof(*remote)) < 0)
{ {
#if LOG_VERBOSITY > 0 #if LOG_VERBOSITY > 0
Log::FormatLine("[SOCK] Send failed. (remote: %s:%d)", remoteAddr, remotePort); Log::FormatLine("[SOCK] Send failed. (remote: %s)", GetHost(remote).c_str());
#endif
}
else
{
#if LOG_VERBOSITY > 3
Log::FormatLine("[SOCK] Datagram sent. (remote: %s)", GetHost(remote).c_str());
#endif #endif
} }
} }
std::string UDPSocket::GetHost(sockaddr* sa)
{
char ip[INET6_ADDRSTRLEN + 6] = { 0 };
switch (sa->sa_family)
{
case AF_INET:
{
sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(sa);
inet_ntop(AF_INET, &sin->sin_addr, ip, INET6_ADDRSTRLEN);
int len = strnlen(ip, INET6_ADDRSTRLEN);
ip[len++] = ':';
sprintf(ip + len, "%d", ntohs((*sin).sin_port));
break;
}
case AF_INET6:
{
sockaddr_in6* sin = reinterpret_cast<sockaddr_in6*>(sa);
inet_ntop(AF_INET6, &sin->sin6_addr, ip, INET6_ADDRSTRLEN);
int len = strnlen(ip, INET6_ADDRSTRLEN);
ip[len++] = ':';
sprintf(ip + len, "%d", ntohs((*sin).sin6_port));
break;
}
default:
return "UNKNOWN";
}
return std::string(ip);
}
} }

View File

@@ -53,20 +53,16 @@ namespace XPC
/// Sends data to the specified remote endpoint. /// Sends data to the specified remote endpoint.
/// ///
/// \param data The data to be sent. /// \param data The data to be sent.
/// \param len The number of bytes to send. /// \param len The number of bytes to send.
/// \param remoteHost The hostname of the destination client. /// \param remote The destination socket.
/// \param remotePort The port of the destination client. void SendTo(std::uint8_t* buffer, std::size_t len, sockaddr* remote);
void SendTo(std::uint8_t* buffer, std::size_t len, std::string remoteHost, std::uint16_t remotePort);
/// Sends data to the specified remote endpoint. /// Gets a string containing the IP address and port contained in the given sockaddr.
/// ///
/// \param data The data to be sent. /// \param addr The socket address to parse.
/// \param len The number of bytes to send. /// \returns A string representation of the socket address.
/// \param remoteHost The hostname of the destination client. static std::string GetHost(sockaddr* addr);
/// \param remotePort The port of the destination client.
void UDPSocket::SendTo(std::uint8_t* buffer, std::size_t len, std::uint32_t remoteIP, std::uint16_t remotePort);
private: private:
#ifdef _WIN32 #ifdef _WIN32
SOCKET sock; SOCKET sock;

View File

@@ -71,11 +71,9 @@
#endif #endif
#define RECVPORT 49009 // Port that the plugin receives commands on #define RECVPORT 49009 // Port that the plugin receives commands on
#define SENDPORT 49097 // Port that the plugin sends on
#define OPS_PER_CYCLE 20 // Max Number of operations per cycle #define OPS_PER_CYCLE 20 // Max Number of operations per cycle
XPC::UDPSocket* recvSocket = nullptr; XPC::UDPSocket* sock = nullptr;
XPC::UDPSocket* sendSocket = nullptr;
double start,lap; double start,lap;
static double timeConvert = 0.0; static double timeConvert = 0.0;
@@ -126,10 +124,8 @@ PLUGIN_API void XPluginStop(void)
PLUGIN_API void XPluginDisable(void) PLUGIN_API void XPluginDisable(void)
{ {
// Close sockets // Close sockets
delete recvSocket; delete sock;
delete sendSocket; sock = nullptr;
recvSocket = nullptr;
sendSocket = nullptr;
// Stop rendering messages to screen. // Stop rendering messages to screen.
XPC::Drawing::ClearMessage(); XPC::Drawing::ClearMessage();
@@ -143,9 +139,8 @@ PLUGIN_API void XPluginDisable(void)
PLUGIN_API int XPluginEnable(void) PLUGIN_API int XPluginEnable(void)
{ {
// Open sockets // Open sockets
recvSocket = new XPC::UDPSocket(RECVPORT); sock = new XPC::UDPSocket(RECVPORT);
sendSocket = new XPC::UDPSocket(SENDPORT); XPC::MessageHandlers::SetSocket(sock);
XPC::MessageHandlers::SetSocket(sendSocket);
XPC::Log::WriteLine("[EXEC] Plugin Enabled, sockets opened"); XPC::Log::WriteLine("[EXEC] Plugin Enabled, sockets opened");
if (benchmarkingSwitch > 0) if (benchmarkingSwitch > 0)
@@ -189,7 +184,7 @@ float XPCFlightLoopCallback(float inElapsedSinceLastCall,
#endif #endif
} }
XPC::Message msg = XPC::Message::ReadFrom(*recvSocket); XPC::Message msg = XPC::Message::ReadFrom(*sock);
if (msg.GetHead() == "") if (msg.GetHead() == "")
{ {
break; break;
@@ -209,8 +204,8 @@ float XPCFlightLoopCallback(float inElapsedSinceLastCall,
if (cyclesToClear != -1 && counter%cyclesToClear == 0) if (cyclesToClear != -1 && counter%cyclesToClear == 0)
{ {
XPC::Log::WriteLine("[EXEC] Cleared UDP Buffer"); XPC::Log::WriteLine("[EXEC] Cleared UDP Buffer");
delete recvSocket; delete sock;
recvSocket = new XPC::UDPSocket(RECVPORT); sock = new XPC::UDPSocket(RECVPORT);
} }
return -1; return -1;
} }

View File

@@ -42,7 +42,7 @@
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<OutDir>..\XPlaneConnect\</OutDir> <OutDir>..\XPlaneConnect\</OutDir>
<TargetExt>.xpl</TargetExt> <TargetExt>.xpl</TargetExt>
<IncludePath>..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath)</IncludePath> <IncludePath>..\SDK\CHeaders\XPLM;$(IncludePath)</IncludePath>
<LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath> <LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath>
<TargetName>win</TargetName> <TargetName>win</TargetName>
</PropertyGroup> </PropertyGroup>
@@ -99,7 +99,6 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\C\src\xplaneConnect.h" />
<ClInclude Include="..\DataManager.h" /> <ClInclude Include="..\DataManager.h" />
<ClInclude Include="..\DataMaps.h" /> <ClInclude Include="..\DataMaps.h" />
<ClInclude Include="..\Drawing.h" /> <ClInclude Include="..\Drawing.h" />
@@ -109,7 +108,6 @@
<ClInclude Include="..\UDPSocket.h" /> <ClInclude Include="..\UDPSocket.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\C\src\xplaneConnect.c" />
<ClCompile Include="..\DataManager.cpp" /> <ClCompile Include="..\DataManager.cpp" />
<ClCompile Include="..\DataMaps.cpp" /> <ClCompile Include="..\DataMaps.cpp" />
<ClCompile Include="..\Drawing.cpp" /> <ClCompile Include="..\Drawing.cpp" />

View File

@@ -15,9 +15,6 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\C\src\xplaneConnect.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Log.h"> <ClInclude Include="..\Log.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -41,9 +38,6 @@
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\C\src\xplaneConnect.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\XPCPlugin.cpp"> <ClCompile Include="..\XPCPlugin.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>