Added UDP multicast for plugin discovery (#153)
* Added Timer * Added UDPSocket::GetAddr * Added MessageHandlers::SendBeacon() * PoC of starting a timer on PluginEnable * C++11 * Added Timer to xcode project * C++11 in cmake * added Timer to cmake * use function pointer in Timer * moved Timer to namespace + wait for thread to join when stopping the timer * Windows: changed uint to unisgned short * Windows: Added Timer.h/cpp to project * GetAddr static * Send xplane and plugin version with BECN * SendBeacon with params * fixed file copyrights * Include functional to fix Linux compile error * review fixes * Send plugin receive port in BECN * review fixes
This commit is contained in:
committed by
Jason Watkins
parent
f9bfd6e3b9
commit
50335c4a5c
@@ -10,6 +10,7 @@ add_definitions(-DXPLM200 -DLIN=1)
|
||||
|
||||
SET(CMAKE_C_COMPILER gcc)
|
||||
SET(CMAKE_CXX_COMPILER g++)
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
add_library(xpc64 SHARED XPCPlugin.cpp
|
||||
DataManager.cpp
|
||||
@@ -17,6 +18,7 @@ add_library(xpc64 SHARED XPCPlugin.cpp
|
||||
Log.cpp
|
||||
Message.cpp
|
||||
MessageHandlers.cpp
|
||||
Timer.cpp
|
||||
UDPSocket.cpp)
|
||||
set_target_properties(xpc64 PROPERTIES PREFIX "" SUFFIX ".xpl")
|
||||
set_target_properties(xpc64 PROPERTIES COMPILE_FLAGS "-m64 -fno-stack-protector" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m64 -fno-stack-protector")
|
||||
@@ -27,6 +29,7 @@ add_library(xpc32 SHARED XPCPlugin.cpp
|
||||
Log.cpp
|
||||
Message.cpp
|
||||
MessageHandlers.cpp
|
||||
Timer.cpp
|
||||
UDPSocket.cpp)
|
||||
set_target_properties(xpc32 PROPERTIES PREFIX "" SUFFIX ".xpl")
|
||||
set_target_properties(xpc32 PROPERTIES COMPILE_FLAGS "-m32 -fno-stack-protector" LINK_FLAGS "-shared -rdynamic -nodefaultlibs -undefined_warning -m32 -fno-stack-protector")
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#define MULTICAST_GROUP "239.255.1.1"
|
||||
#define MULITCAST_PORT 49710
|
||||
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
@@ -35,6 +38,8 @@ namespace XPC
|
||||
std::string MessageHandlers::connectionKey;
|
||||
MessageHandlers::ConnectionInfo MessageHandlers::connection;
|
||||
UDPSocket* MessageHandlers::sock;
|
||||
|
||||
static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT);
|
||||
|
||||
void MessageHandlers::SetSocket(UDPSocket* socket)
|
||||
{
|
||||
@@ -130,6 +135,28 @@ namespace XPC
|
||||
MessageHandlers::HandleUnknown(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion) {
|
||||
|
||||
unsigned char response[128] = "BECN";
|
||||
|
||||
std::size_t cur = 5;
|
||||
|
||||
// 2 bytes plugin port
|
||||
*((uint16_t *)(response + cur)) = pluginReceivePort;
|
||||
cur += sizeof(uint16_t);
|
||||
|
||||
// 4 bytes xplane version
|
||||
*((uint32_t*)(response + cur)) = xplaneVersion;
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
// plugin version
|
||||
int len = pluginVersion.length();
|
||||
memcpy(response + cur, pluginVersion.c_str(), len);
|
||||
cur += strlen(pluginVersion.c_str()) + len;
|
||||
|
||||
sock->SendTo(response, cur, &multicast_address);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleConn(const Message& msg)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace XPC
|
||||
|
||||
/// Sets the socket that message handlers use to send responses.
|
||||
static void SetSocket(UDPSocket* socket);
|
||||
|
||||
static void SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion);
|
||||
|
||||
private:
|
||||
// One handler per message type. Message types are descripbed on the
|
||||
|
||||
27
xpcPlugin/Timer.cpp
Normal file
27
xpcPlugin/Timer.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
|
||||
#include "Timer.h"
|
||||
using namespace std;
|
||||
|
||||
namespace XPC {
|
||||
void Timer::start(const chrono::milliseconds interval, const Callback &callback) {
|
||||
{
|
||||
running.test_and_set();
|
||||
th = thread([=]()
|
||||
{
|
||||
while (running.test_and_set()) {
|
||||
this_thread::sleep_for(interval);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::stop() {
|
||||
running.clear();
|
||||
if(th.joinable()) {
|
||||
th.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
29
xpcPlugin/Timer.h
Normal file
29
xpcPlugin/Timer.h
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2013-2018 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
|
||||
#ifndef XPCPLUGIN_TIMER_H_
|
||||
#define XPCPLUGIN_TIMER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
namespace XPC {
|
||||
class Timer
|
||||
{
|
||||
std::atomic_flag running;
|
||||
std::thread th;
|
||||
|
||||
public:
|
||||
|
||||
using Callback = std::function<void(void)>;
|
||||
|
||||
void start(const std::chrono::milliseconds, const Callback &callback);
|
||||
|
||||
void stop();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Timer_hpp */
|
||||
@@ -138,6 +138,18 @@ namespace XPC
|
||||
Log::FormatLine(LOG_INFO, tag, "Send succeeded. (remote: %s)", GetHost(remote).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
sockaddr UDPSocket::GetAddr(std::string address, unsigned short port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr(address.c_str());
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
sockaddr* sa = reinterpret_cast<sockaddr*>(&addr);
|
||||
return *sa;
|
||||
}
|
||||
|
||||
std::string UDPSocket::GetHost(sockaddr* sa)
|
||||
{
|
||||
|
||||
@@ -56,12 +56,14 @@ namespace XPC
|
||||
/// \param len The number of bytes to send.
|
||||
/// \param remote The destination socket.
|
||||
void SendTo(const unsigned char* buffer, std::size_t len, sockaddr* remote) const;
|
||||
|
||||
|
||||
/// Gets a string containing the IP address and port contained in the given sockaddr.
|
||||
///
|
||||
/// \param addr The socket address to parse.
|
||||
/// \returns A string representation of the socket address.
|
||||
static std::string GetHost(sockaddr* addr);
|
||||
|
||||
static sockaddr GetAddr(std::string address, unsigned short port);
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
SOCKET sock;
|
||||
|
||||
@@ -60,13 +60,15 @@
|
||||
#include "Log.h"
|
||||
#include "MessageHandlers.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
|
||||
// XPLM Includes
|
||||
#include "XPLMProcessing.h"
|
||||
#include "XPLMUtilities.h"
|
||||
|
||||
// System Includes
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach_time.h>
|
||||
@@ -75,7 +77,12 @@
|
||||
#define RECVPORT 49009 // Port that the plugin receives commands on
|
||||
#define OPS_PER_CYCLE 20 // Max Number of operations per cycle
|
||||
|
||||
#define XPC_PLUGIN_VERSION "1.3-rc.1"
|
||||
|
||||
using namespace std;
|
||||
|
||||
XPC::UDPSocket* sock = NULL;
|
||||
XPC::Timer* timer = NULL;
|
||||
|
||||
double start;
|
||||
double lap;
|
||||
@@ -96,7 +103,7 @@ PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc)
|
||||
strcpy(outDesc, "X Plane Communications Toolbox\nCopyright (c) 2013-2018 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved.");
|
||||
|
||||
#if (__APPLE__)
|
||||
if ( abs(timeConvert) <= 1e-9 ) // is about 0
|
||||
if ( timeConvert <= 1e-9 ) // is about 0
|
||||
{
|
||||
mach_timebase_info_data_t timeBase;
|
||||
(void)mach_timebase_info(&timeBase);
|
||||
@@ -105,7 +112,7 @@ PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc)
|
||||
1000000000.0;
|
||||
}
|
||||
#endif
|
||||
XPC::Log::Initialize("1.3-rc.1");
|
||||
XPC::Log::Initialize(XPC_PLUGIN_VERSION);
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Start");
|
||||
XPC::DataManager::Initialize();
|
||||
|
||||
@@ -133,12 +140,18 @@ PLUGIN_API void XPluginDisable(void)
|
||||
XPC::Drawing::ClearWaypoints();
|
||||
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Disabled, sockets closed");
|
||||
|
||||
timer->stop();
|
||||
delete timer;
|
||||
timer = NULL;
|
||||
}
|
||||
|
||||
PLUGIN_API int XPluginEnable(void)
|
||||
{
|
||||
// Open sockets
|
||||
sock = new XPC::UDPSocket(RECVPORT);
|
||||
timer = new XPC::Timer();
|
||||
|
||||
XPC::MessageHandlers::SetSocket(sock);
|
||||
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Enabled, sockets opened");
|
||||
@@ -152,6 +165,15 @@ PLUGIN_API int XPluginEnable(void)
|
||||
void* refcon = NULL; // Don't pass anything to the callback directly
|
||||
XPLMRegisterFlightLoopCallback(XPCFlightLoopCallback, interval, refcon);
|
||||
|
||||
|
||||
int xpVer;
|
||||
XPLMGetVersions(&xpVer, NULL, NULL);
|
||||
|
||||
timer->start(chrono::milliseconds(1000), [=]{
|
||||
XPC::MessageHandlers::SendBeacon(XPC_PLUGIN_VERSION, RECVPORT, xpVer);
|
||||
});
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */; };
|
||||
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */; };
|
||||
BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; };
|
||||
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; };
|
||||
@@ -36,6 +37,8 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3D0F44CC21C6D3E7008A0655 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = "<group>"; };
|
||||
3D0F44CD21C6D3E7008A0655 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = "<group>"; };
|
||||
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XPCPlugin.cpp; sourceTree = SOURCE_ROOT; usesTabs = 1; };
|
||||
BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataManager.cpp; sourceTree = "<group>"; };
|
||||
BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = "<group>"; };
|
||||
@@ -76,6 +79,7 @@
|
||||
AC4E46B809C2E0B3006B7E1B /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D0F44CD21C6D3E7008A0655 /* Timer.cpp */,
|
||||
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */,
|
||||
BEDC620218EDF1A7005DB364 /* xplaneConnect.c */,
|
||||
BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */,
|
||||
@@ -91,6 +95,7 @@
|
||||
BE953E0B1AEB183400CE4A8C /* inc */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D0F44CC21C6D3E7008A0655 /* Timer.h */,
|
||||
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */,
|
||||
BEABAD2C1AE041A3007BA7DA /* DataManager.h */,
|
||||
BEABAD301AE041A3007BA7DA /* Drawing.h */,
|
||||
@@ -190,6 +195,7 @@
|
||||
BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */,
|
||||
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */,
|
||||
BEABAD391AE041A3007BA7DA /* Drawing.cpp in Sources */,
|
||||
3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */,
|
||||
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */,
|
||||
BEABAD3F1AE0498D007BA7DA /* UDPSocket.cpp in Sources */,
|
||||
);
|
||||
@@ -298,6 +304,7 @@
|
||||
D607B19C09A556E400699BC3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_LINK_OBJC_RUNTIME = NO;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
@@ -337,6 +344,7 @@
|
||||
D607B19D09A556E400699BC3 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_LINK_OBJC_RUNTIME = NO;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
@@ -365,9 +373,7 @@
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/xplaneConnect-asdjuezcjkhojuewbyxhyhabxfwc/Build/Products/Debug",
|
||||
);
|
||||
MACH_O_TYPE = mh_bundle;
|
||||
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
|
||||
PRODUCT_NAME = mac;
|
||||
SDKROOT = macosx;
|
||||
STRIP_INSTALLED_PRODUCT = YES;
|
||||
|
||||
@@ -206,6 +206,7 @@
|
||||
<ClInclude Include="..\Log.h" />
|
||||
<ClInclude Include="..\Message.h" />
|
||||
<ClInclude Include="..\MessageHandlers.h" />
|
||||
<ClCompile Include="..\Timer.h" />
|
||||
<ClInclude Include="..\UDPSocket.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -214,6 +215,7 @@
|
||||
<ClCompile Include="..\Log.cpp" />
|
||||
<ClCompile Include="..\Message.cpp" />
|
||||
<ClCompile Include="..\MessageHandlers.cpp" />
|
||||
<ClCompile Include="..\Timer.cpp" />
|
||||
<ClCompile Include="..\UDPSocket.cpp" />
|
||||
<ClCompile Include="..\XPCPlugin.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user