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:
Jan Chaloupecky
2019-03-14 14:49:43 +00:00
committed by Jason Watkins
parent f9bfd6e3b9
commit 50335c4a5c
10 changed files with 138 additions and 6 deletions

View File

@@ -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")

View File

@@ -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)
{

View File

@@ -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
View 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
View 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 */

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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>