From 5ee49c7d81ecca9d4ee3e46b8a3082bd60046141 Mon Sep 17 00:00:00 2001 From: Jason Watkins Date: Thu, 16 Apr 2015 16:50:05 -0700 Subject: [PATCH] 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. --- xpcPlugin/Drawing.h | 9 +- xpcPlugin/Message.cpp | 52 +++++--- xpcPlugin/MessageHandlers.cpp | 115 ++++++++---------- xpcPlugin/MessageHandlers.h | 4 +- xpcPlugin/UDPSocket.cpp | 68 ++++++----- xpcPlugin/UDPSocket.h | 20 ++- xpcPlugin/XPCPlugin.cpp | 21 ++-- xpcPlugin/xpcPlugin/xpcPlugin.vcxproj | 4 +- xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters | 6 - 9 files changed, 146 insertions(+), 153 deletions(-) diff --git a/xpcPlugin/Drawing.h b/xpcPlugin/Drawing.h index dbc57e4..0187810 100644 --- a/xpcPlugin/Drawing.h +++ b/xpcPlugin/Drawing.h @@ -3,12 +3,17 @@ #ifndef XPC_DRAWING_H #define XPC_DRAWING_H -#include "xplaneConnect.h" - #include namespace XPC { + typedef struct + { + double latitude; + double longitude; + double altitude; + } Waypoint; + /// Handles tasks that involve drawing to the screen in X-Plane. /// /// \author Jason Watkins diff --git a/xpcPlugin/Message.cpp b/xpcPlugin/Message.cpp index 3b05f21..81920e1 100644 --- a/xpcPlugin/Message.cpp +++ b/xpcPlugin/Message.cpp @@ -2,7 +2,6 @@ //National Aeronautics and Space Administration. All Rights Reserved. #include "Message.h" #include "Log.h" -#include "xplaneConnect.h" #include #include @@ -71,6 +70,7 @@ namespace XPC } Log::WriteLine(ss.str()); + ss << std::dec; ss.str(""); ss << "[" << GetHead() << "-DEBUG] (" << GetSize() << ")"; switch (GetMagicNumber()) // Binary version of head @@ -84,25 +84,41 @@ namespace XPC } case 0x4C525443: // CTRL { - xpcCtrl ctrl = parseCTRL((char*)buffer); - ss << " (" << ctrl.pitch << " " << ctrl.roll << " " << ctrl.yaw << ") "; - ss << ctrl.throttle << " " << ctrl.gear << " " << ctrl.flaps; + // Parse message data + float pitch = *((float*)(buffer + 5)); + 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()); break; } case 0x41544144: // DATA - { - float dataRef[30][9]; - short numCols = parseDATA((char*)buffer, size, dataRef); + { + std::size_t numCols = (size - 5) / 36; + 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)"; Log::WriteLine(ss.str()); for (int i = 0; i < numCols; ++i) { ss.str(""); - ss << "\t#" << dataRef[i][0]; + ss << "\t#" << values[i][0]; for (int j = 1; j < 9; ++j) { - ss << " " << dataRef[i][j]; + ss << " " << values[i][j]; } Log::WriteLine(ss.str()); } @@ -136,14 +152,16 @@ namespace XPC break; } case 0x49534F50: // POSI - { - float position[6] = { 0.0 }; - short aircraft = 0; - float gear = -1.0; - aircraft = parsePOSI((char*)buffer, position, 6, &gear); - ss << ' ' << aircraft; - ss << " (" << position[0] << ' ' << position[1] << ' ' << position[2] << ") ("; - ss << position[3] << ' ' << position[4] << ' ' << position[5] << ") "; + { + char aircraft = buffer[5]; + float gear = *((float*)(buffer + 30)); + float pos[3]; + float orient[3]; + memcpy(pos, buffer + 6, 12); + memcpy(orient, buffer + 18, 12); + ss << " AC:" << (int)aircraft; + ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:("; + ss << orient[3] << ' ' << orient[4] << ' ' << orient[5] << ") Gear:"; ss << gear; Log::WriteLine(ss.str()); break; diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index ac8c35a..0a43454 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -55,48 +55,6 @@ namespace XPC 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(sa); - inet_ntop(AF_INET, &sin->sin_addr, ip, INET6_ADDRSTRLEN); - break; - } - case AF_INET6: - { - sockaddr_in6* sin = reinterpret_cast(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(sa); - return ntohs((*sin).sin_port); - } - case AF_INET6: - { - sockaddr_in6 *sin = reinterpret_cast(sa); - return ntohs((*sin).sin6_port); - } - default: - return ~0; - } - } - void MessageHandlers::HandleMessage(Message& msg) { // Make sure we really have a message to handle. @@ -109,9 +67,7 @@ namespace XPC // Set current connection sockaddr sourceaddr = msg.GetSource(); - std::string ip = getIP(&sourceaddr); - std::uint16_t port = getPort(&sourceaddr); - connectionKey = ip + ":" + std::to_string(port); + connectionKey = UDPSocket::GetHost(&sourceaddr); #if LOG_VERBOSITY > 4 Log::FormatLine("[MSGH] Handling message from %s", connectionKey.c_str()); #endif @@ -124,22 +80,20 @@ namespace XPC // to connections. As long as we never remove elements, the size of // connections will serve as a unique id. connections.size(), - ip, - 49008, // By default, send information to the client on this port. - port, + sourceaddr, 0 }; connections[connectionKey] = connection; -#if LOG_VERBOSITY > 4 - Log::FormatLine("[MSGH] New connection. ID=%u, Remote=%s:%u", connection.id, ip.c_str(), port); +#if LOG_VERBOSITY > 2 + Log::FormatLine("[MSGH] New connection. ID=%u, Remote=%s", connection.id, connectionKey.c_str()); #endif } else { connection = (*conn).second; -#if LOG_VERBOSITY > 4 - Log::FormatLine("[MSGH] Existing connection. ID=%u, Remote=%s:%u", - connection.id, connection.ip.c_str(), connection.srcPort); +#if LOG_VERBOSITY > 3 + Log::FormatLine("[MSGH] Existing connection. ID=%u, Remote=%s", + connection.id, connectionKey.c_str()); #endif } @@ -162,7 +116,30 @@ namespace XPC const std::uint8_t* buffer = msg.GetBuffer(); // 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(sa); + (*sin).sin_port = htons(port); + break; + } + case AF_INET6: + { + sockaddr_in6* sin = reinterpret_cast(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; // Create response @@ -170,19 +147,19 @@ namespace XPC response[5] = connection.id; // Update log -#if LOG_VERBOSITY > 0 +#if LOG_VERBOSITY > 1 Log::FormatLine("[CONN] ID: %u New destination port: %u", - connection.id, connection.dstPort); + connection.id, port); #endif // Send response - sock->SendTo(response, 6, connection.ip, connection.dstPort); + sock->SendTo(response, 6, &connection.addr); } void MessageHandlers::HandleCtrl(Message& msg) { // Update Log -#if LOG_VERBOSITY > 0 +#if LOG_VERBOSITY > 2 Log::FormatLine("[CTRL] Message Received (Conn %i)", connection.id); #endif @@ -192,7 +169,7 @@ namespace XPC //Packets specifying an A/C num should be 27 bytes. if (size != 26 && size != 27) { -#if LOG_VERBOSITY > 1 +#if LOG_VERBOSITY > 0 Log::FormatLine("[CTRL] ERROR: Unexpected message length (%i)", size); #endif return; @@ -244,20 +221,20 @@ namespace XPC std::size_t numCols = (size - 5) / 36; if (numCols > 0) { -#if LOG_VERBOSITY > 3 +#if LOG_VERBOSITY > 2 Log::FormatLine("[DATA] Message Received (Conn %i)", connection.id); #endif } if (numCols > 32) // Error. Will overflow values { -#if LOG_VERBOSITY > 2 +#if LOG_VERBOSITY > 0 Log::FormatLine("[DATA] ERROR numCols to large."); #endif return; } else { -#if LOG_VERBOSITY > 2 +#if LOG_VERBOSITY > 1 Log::FormatLine("[DATA] WARNING: Empty data packet received (Conn %i)", connection.id); #endif return; @@ -462,7 +439,7 @@ namespace XPC cur += count * sizeof(float); } - sock->SendTo(response, cur, connection.ip, connection.dstPort); + sock->SendTo(response, cur, &connection.addr); } void MessageHandlers::HandlePosi(Message& msg) @@ -599,13 +576,13 @@ namespace XPC #endif switch (op) { - case xpc_WYPT_ADD: + case 1: Drawing::AddWaypoints(points, count); break; - case xpc_WYPT_DEL: + case 2: Drawing::RemoveWaypoints(points, count); break; - case xpc_WYPT_CLR: + case 3: Drawing::ClearWaypoints(); break; default: @@ -621,7 +598,11 @@ namespace XPC #if LOG_VERBOSITY > 1 Log::WriteLine("[MSGH] Sending raw data to X-Plane"); #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) diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index 7db08e2..eafd0f7 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -53,9 +53,7 @@ namespace XPC typedef struct { std::uint8_t id; - std::string ip; - std::uint16_t dstPort; - std::uint16_t srcPort; + sockaddr addr; std::uint8_t getdCount; std::string getdRequest[255]; } ConnectionInfo; diff --git a/xpcPlugin/UDPSocket.cpp b/xpcPlugin/UDPSocket.cpp index 9795205..642ef12 100644 --- a/xpcPlugin/UDPSocket.cpp +++ b/xpcPlugin/UDPSocket.cpp @@ -131,41 +131,49 @@ namespace XPC return status; } - // TODO: Add IPV6 support - void UDPSocket::SendTo(std::uint8_t* buffer, std::size_t len, std::string remoteHost, std::uint16_t remotePort) + void UDPSocket::SendTo(std::uint8_t* buffer, std::size_t len, sockaddr* remote) { -#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; - 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 - 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 } } + + std::string UDPSocket::GetHost(sockaddr* sa) + { + char ip[INET6_ADDRSTRLEN + 6] = { 0 }; + switch (sa->sa_family) + { + case AF_INET: + { + sockaddr_in* sin = reinterpret_cast(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(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); + } } \ No newline at end of file diff --git a/xpcPlugin/UDPSocket.h b/xpcPlugin/UDPSocket.h index 69d7410..904b055 100644 --- a/xpcPlugin/UDPSocket.h +++ b/xpcPlugin/UDPSocket.h @@ -53,20 +53,16 @@ namespace XPC /// Sends data to the specified remote endpoint. /// - /// \param data The data to be sent. - /// \param len The number of bytes to send. - /// \param remoteHost The hostname of the destination client. - /// \param remotePort The port of the destination client. - void SendTo(std::uint8_t* buffer, std::size_t len, std::string remoteHost, std::uint16_t remotePort); + /// \param data The data to be sent. + /// \param len The number of bytes to send. + /// \param remote The destination socket. + void SendTo(std::uint8_t* buffer, std::size_t len, sockaddr* remote); - /// 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 len The number of bytes to send. - /// \param remoteHost The hostname of the destination client. - /// \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); - + /// \param addr The socket address to parse. + /// \returns A string representation of the socket address. + static std::string GetHost(sockaddr* addr); private: #ifdef _WIN32 SOCKET sock; diff --git a/xpcPlugin/XPCPlugin.cpp b/xpcPlugin/XPCPlugin.cpp index 726754e..84fafae 100755 --- a/xpcPlugin/XPCPlugin.cpp +++ b/xpcPlugin/XPCPlugin.cpp @@ -71,11 +71,9 @@ #endif #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 -XPC::UDPSocket* recvSocket = nullptr; -XPC::UDPSocket* sendSocket = nullptr; +XPC::UDPSocket* sock = nullptr; double start,lap; static double timeConvert = 0.0; @@ -126,10 +124,8 @@ PLUGIN_API void XPluginStop(void) PLUGIN_API void XPluginDisable(void) { // Close sockets - delete recvSocket; - delete sendSocket; - recvSocket = nullptr; - sendSocket = nullptr; + delete sock; + sock = nullptr; // Stop rendering messages to screen. XPC::Drawing::ClearMessage(); @@ -143,9 +139,8 @@ PLUGIN_API void XPluginDisable(void) PLUGIN_API int XPluginEnable(void) { // Open sockets - recvSocket = new XPC::UDPSocket(RECVPORT); - sendSocket = new XPC::UDPSocket(SENDPORT); - XPC::MessageHandlers::SetSocket(sendSocket); + sock = new XPC::UDPSocket(RECVPORT); + XPC::MessageHandlers::SetSocket(sock); XPC::Log::WriteLine("[EXEC] Plugin Enabled, sockets opened"); if (benchmarkingSwitch > 0) @@ -189,7 +184,7 @@ float XPCFlightLoopCallback(float inElapsedSinceLastCall, #endif } - XPC::Message msg = XPC::Message::ReadFrom(*recvSocket); + XPC::Message msg = XPC::Message::ReadFrom(*sock); if (msg.GetHead() == "") { break; @@ -209,8 +204,8 @@ float XPCFlightLoopCallback(float inElapsedSinceLastCall, if (cyclesToClear != -1 && counter%cyclesToClear == 0) { XPC::Log::WriteLine("[EXEC] Cleared UDP Buffer"); - delete recvSocket; - recvSocket = new XPC::UDPSocket(RECVPORT); + delete sock; + sock = new XPC::UDPSocket(RECVPORT); } return -1; } \ No newline at end of file diff --git a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj index 3ed8c71..ac3d36c 100644 --- a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj +++ b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj @@ -42,7 +42,7 @@ true ..\XPlaneConnect\ .xpl - ..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath) + ..\SDK\CHeaders\XPLM;$(IncludePath) ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) win @@ -99,7 +99,6 @@ - @@ -109,7 +108,6 @@ - diff --git a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters index 21d7598..e921a5d 100644 --- a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters +++ b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters @@ -15,9 +15,6 @@ - - Header Files - Header Files @@ -41,9 +38,6 @@ - - Source Files - Source Files