1
0
Fork 0

CPDLC updates from Henning

This commit is contained in:
James Turner 2021-01-04 09:57:38 +00:00
parent 527f58d353
commit af387107a3
6 changed files with 75 additions and 57 deletions

View file

@ -26,6 +26,11 @@
#include "cpdlc.hxx" #include "cpdlc.hxx"
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
const std::string CPDLC_IRC_SERVER {"mpirc.flightgear.org"};
const std::string CPDLC_MSGPREFIX_CONNECT {"___CPDLC_CONNECT___"};
const std::string CPDLC_MSGPREFIX_MSG {"___CPDLC_MSG___"};
const std::string CPDLC_MSGPREFIX_DISCONNECT {"___CPDLC_DISCONNECT___"};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// CPDLCManager // CPDLCManager
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -65,29 +70,30 @@ bool CPDLCManager::connect(const std::string authority = "")
{ {
// ensure we get an authority on first call but do not accept a change before // ensure we get an authority on first call but do not accept a change before
// resetting _data_authority in disconnect() // resetting _data_authority in disconnect()
if (!_data_authority.size()) { if (_data_authority.empty()) {
if (!authority.size()) { if (authority.empty()) {
SG_LOG(SG_NETWORK, SG_WARN, "cpdlcConnect not possible: empty argument!"); SG_LOG(SG_NETWORK, SG_WARN, "cpdlcConnect not possible: empty argument!");
return false; return false;
} else { } else {
_data_authority = authority; _data_authority = authority;
} }
} }
if (authority.size() && authority != _data_authority) { if (!authority.empty() && authority != _data_authority) {
SG_LOG(SG_NETWORK, SG_WARN, "cpdlcConnect: cannot change authority now, use disconnect first!"); SG_LOG(SG_NETWORK, SG_WARN, "cpdlcConnect: cannot change authority now, use disconnect first!");
return false; return false;
} }
// launch IRC connection as needed // launch IRC connection as needed
if (!_irc->isConnected()) { if (!_irc->isConnected()) {
SG_LOG(SG_NETWORK, SG_DEV_WARN, "Connecting to IRC server..."); SG_LOG(SG_NETWORK, SG_INFO, "Connecting to IRC server...");
if (!_irc->login()) { if (!_irc->login()) {
SG_LOG(SG_NETWORK, SG_WARN, "IRC login failed.");
return false; return false;
} }
_status = CPDLC_WAIT_IRC_READY; _status = CPDLC_WAIT_IRC_READY;
return true; return true;
} else if (_irc->isReady() && _status != CPDLC_ONLINE) { } else if (_irc->isReady() && _status != CPDLC_ONLINE) {
SG_LOG(SG_NETWORK, SG_DEV_WARN, "CPDLC send connect"); SG_LOG(SG_NETWORK, SG_INFO, "CPDLC sending 'connect'");
_status = CPDLC_CONNECTING; _status = CPDLC_CONNECTING;
_pStatus->setIntValue(_status); _pStatus->setIntValue(_status);
return _irc->sendPrivmsg(_data_authority, CPDLC_MSGPREFIX_CONNECT); return _irc->sendPrivmsg(_data_authority, CPDLC_MSGPREFIX_CONNECT);
@ -97,7 +103,7 @@ bool CPDLCManager::connect(const std::string authority = "")
void CPDLCManager::disconnect() void CPDLCManager::disconnect()
{ {
if (_irc && _irc->isConnected() && _data_authority.size()) { if (_irc && _irc->isConnected() && !_data_authority.empty()) {
_irc->sendPrivmsg(_data_authority, CPDLC_MSGPREFIX_DISCONNECT); _irc->sendPrivmsg(_data_authority, CPDLC_MSGPREFIX_DISCONNECT);
} }
_data_authority = ""; _data_authority = "";
@ -137,7 +143,7 @@ void CPDLCManager::update()
if (_irc) { if (_irc) {
if (_irc->isConnected()) { if (_irc->isConnected()) {
if (_status == CPDLC_WAIT_IRC_READY && _irc->isReady()) { if (_status == CPDLC_WAIT_IRC_READY && _irc->isReady()) {
SG_LOG(SG_NETWORK, SG_DEV_WARN, "CPDLC IRC ready, connecting..."); SG_LOG(SG_NETWORK, SG_INFO, "CPDLC IRC ready, connecting...");
connect(); connect();
} }
if (_irc->hasMessage()) { if (_irc->hasMessage()) {
@ -155,9 +161,9 @@ void CPDLCManager::update()
// process incoming message // process incoming message
void CPDLCManager::processMessage(struct IRCMessage message) void CPDLCManager::processMessage(struct IRCMessage message)
{ {
SG_LOG(SG_NETWORK, SG_INFO, "CPDLC message");
// connection accepted by ATC, or new data authority (been transferred) // connection accepted by ATC, or new data authority (been transferred)
if (message.textline.find(CPDLC_MSGPREFIX_CONNECT) == 0) { if (message.textline.find(CPDLC_MSGPREFIX_CONNECT) == 0) {
SG_LOG(SG_NETWORK, SG_INFO, "CPDLC got connected.");
_data_authority = message.sender; _data_authority = message.sender;
_pDataAuthority->setStringValue(_data_authority); // make this known to ACFT _pDataAuthority->setStringValue(_data_authority); // make this known to ACFT
_status = CPDLC_ONLINE; _status = CPDLC_ONLINE;
@ -171,11 +177,13 @@ void CPDLCManager::processMessage(struct IRCMessage message)
// connection rejected, or terminated by ATC // connection rejected, or terminated by ATC
if (message.textline.find(CPDLC_MSGPREFIX_DISCONNECT) == 0) { if (message.textline.find(CPDLC_MSGPREFIX_DISCONNECT) == 0) {
if (message.sender == _data_authority) { if (message.sender == _data_authority) {
SG_LOG(SG_NETWORK, SG_INFO, "CPDLC got disconnect.");
disconnect(); disconnect();
} }
} }
// store valid message in queue for later retrieval by aircraft // store valid message in queue for later retrieval by aircraft
else if (message.textline.find(CPDLC_MSGPREFIX_MSG) == 0) { else if (message.textline.find(CPDLC_MSGPREFIX_MSG) == 0) {
SG_LOG(SG_NETWORK, SG_INFO, "CPDLC message");
_incoming_messages.push_back(message); _incoming_messages.push_back(message);
_pNewMessage->setBoolValue(1); _pNewMessage->setBoolValue(1);
} }

View file

@ -35,12 +35,6 @@
#include <simgear/io/sg_socket.hxx> #include <simgear/io/sg_socket.hxx>
#include "mpirc.hxx" #include "mpirc.hxx"
const std::string CPDLC_IRC_SERVER {"mpirc.flightgear.org"};
const std::string CPDLC_MSGPREFIX_CONNECT {"___CPDLC_CONNECT___"};
const std::string CPDLC_MSGPREFIX_MSG {"___CPDLC_MSG___"};
const std::string CPDLC_MSGPREFIX_DISCONNECT {"___CPDLC_DISCONNECT___"};
enum CPDLCStatus { enum CPDLCStatus {
CPDLC_OFFLINE, CPDLC_OFFLINE,
CPDLC_CONNECTING, CPDLC_CONNECTING,

View file

@ -27,8 +27,16 @@
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
const std::string IRC_TEST_CHANNEL{"#mptest"}; // for development const std::string IRC_TEST_CHANNEL{"#mptest"}; // for development
const std::string IRC_MSG_TERMINATOR {"\r\n"};
// https://www.alien.net.au/irc/irc2numerics.html
const std::string IRC_RPL_WELCOME {"001"};
const std::string IRC_RPL_YOURID {"042"};
const std::string IRC_RPL_MOTD {"372"};
const std::string IRC_RPL_MOTDSTART {"375"};
const std::string IRC_RPL_ENDOFMOTD {"376"};
const std::string IRC_ERR_NOSUCHNICK {"401"};
IRCConnection::IRCConnection(const std::string nickname, const std::string servername, const std::string port) : SGSocket(servername, port, "tcp"), IRCConnection::IRCConnection(const std::string &nickname, const std::string &servername, const std::string &port) : SGSocket(servername, port, "tcp"),
_nickname(nickname) _nickname(nickname)
{ {
} }
@ -50,14 +58,15 @@ void IRCConnection::setupProperties(std::string path)
} }
bool IRCConnection::login(const std::string nickname) bool IRCConnection::login(const std::string &nickname)
{ {
if (!_connected && !connect()) { if (!_connected && !connect()) {
return false; return false;
} }
if (nickname.length()) { if (!nickname.empty()) {
_nickname = nickname; _nickname = nickname;
} else { } else {
SG_LOG(SG_NETWORK, SG_WARN, "IRC login requires nickname argument.");
return false; return false;
} }
@ -86,9 +95,12 @@ void IRCConnection::quit()
disconnect(); disconnect();
} }
bool IRCConnection::sendPrivmsg(const std::string recipient, const std::string textline) bool IRCConnection::sendPrivmsg(const std::string &recipient, const std::string &textline)
{ {
if (!_logged_in) return false; if (!_logged_in) {
SG_LOG(SG_NETWORK, SG_WARN, "IRC 'privmsg' command unvailable. Login first!");
return false;
}
std::string line("PRIVMSG "); std::string line("PRIVMSG ");
line += recipient; line += recipient;
line += " :"; line += " :";
@ -99,14 +111,18 @@ bool IRCConnection::sendPrivmsg(const std::string recipient, const std::string t
if (_pIRCReturnCode) _pIRCReturnCode->setStringValue(""); if (_pIRCReturnCode) _pIRCReturnCode->setStringValue("");
return true; return true;
} else { } else {
SG_LOG(SG_NETWORK, SG_WARN, "IRC send privmsg failed.");
return false; return false;
} }
} }
// join an IRC channel // join an IRC channel
bool IRCConnection::join(const std::string channel) bool IRCConnection::join(const std::string &channel)
{ {
if (!_logged_in) return false; if (!_logged_in) {
SG_LOG(SG_NETWORK, SG_WARN, "IRC 'join' command unvailable. Login first!");
return false;
}
std::string lines("JOIN "); std::string lines("JOIN ");
lines += channel; lines += channel;
lines += IRC_MSG_TERMINATOR; lines += IRC_MSG_TERMINATOR;
@ -114,9 +130,12 @@ bool IRCConnection::join(const std::string channel)
} }
// leave an IRC channel // leave an IRC channel
bool IRCConnection::part(const std::string channel) bool IRCConnection::part(const std::string &channel)
{ {
if (!_logged_in) return false; if (!_logged_in) {
SG_LOG(SG_NETWORK, SG_WARN, "IRC 'part' command unvailable. Login first!");
return false;
}
std::string lines("PART "); std::string lines("PART ");
lines += channel; lines += channel;
lines += IRC_MSG_TERMINATOR; lines += IRC_MSG_TERMINATOR;
@ -145,7 +164,9 @@ void IRCConnection::update()
// open a connection to IRC server // open a connection to IRC server
bool IRCConnection::connect() bool IRCConnection::connect()
{ {
if (_connected) return false; if (_connected) {
return true;
}
_connected = open(SG_IO_OUT); _connected = open(SG_IO_OUT);
if (_connected) { if (_connected) {
@ -168,7 +189,8 @@ void IRCConnection::disconnect()
SG_LOG(SG_NETWORK, SG_INFO, "IRCConnection::disconnect"); SG_LOG(SG_NETWORK, SG_INFO, "IRCConnection::disconnect");
} }
} }
void IRCConnection::pong(const std::string recipient)
void IRCConnection::pong(const std::string &recipient)
{ {
if (!_connected) return; if (!_connected) return;
std::string line("PONG "); std::string line("PONG ");
@ -287,6 +309,7 @@ bool IRCConnection::parseReceivedLine(std::string line)
// TODO: anything sensitive here that we should handle? // TODO: anything sensitive here that we should handle?
// e.g. IRC user has disconnected and username == {current-cpdlc-authority} // e.g. IRC user has disconnected and username == {current-cpdlc-authority}
return false;
} }
return true; return true;
} }

View file

@ -35,15 +35,6 @@
#include <simgear/io/sg_socket.hxx> #include <simgear/io/sg_socket.hxx>
const std::string IRC_DEFAULT_PORT {"6667"}; const std::string IRC_DEFAULT_PORT {"6667"};
const std::string IRC_MSG_TERMINATOR {"\r\n"};
// https://www.alien.net.au/irc/irc2numerics.html
const std::string IRC_RPL_WELCOME {"001"};
const std::string IRC_RPL_YOURID {"042"};
const std::string IRC_RPL_MOTD {"372"};
const std::string IRC_RPL_MOTDSTART {"375"};
const std::string IRC_RPL_ENDOFMOTD {"376"};
const std::string IRC_ERR_NOSUCHNICK {"401"};
const int IRC_BUFFER_SIZE = 1024; const int IRC_BUFFER_SIZE = 1024;
struct IRCMessage { struct IRCMessage {
@ -64,19 +55,19 @@ struct IRCMessage {
class IRCConnection : SGSocket class IRCConnection : SGSocket
{ {
public: public:
IRCConnection(const std::string nickname, const std::string servername, const std::string port = IRC_DEFAULT_PORT); IRCConnection(const std::string &nickname, const std::string &servername, const std::string &port = IRC_DEFAULT_PORT);
~IRCConnection(); ~IRCConnection();
void setupProperties(const std::string path); void setupProperties(std::string path);
void update(); void update();
bool login(const std::string nickname); bool login(const std::string &nickname);
bool login(); bool login();
void quit(); void quit();
bool sendPrivmsg(const std::string recipient, const std::string textline); bool sendPrivmsg(const std::string &recipient, const std::string &textline);
bool join(const std::string channel); bool join(const std::string &channel);
bool part(const std::string channel); bool part(const std::string &channel);
bool isConnected() const { return _connected; } bool isConnected() const { return _connected; }
@ -87,14 +78,14 @@ public:
private: private:
bool connect(); bool connect();
void disconnect(); void disconnect();
void pong(const std::string recipient); void pong(const std::string &recipient);
bool parseReceivedLine(std::string irc_line); bool parseReceivedLine(std::string irc_line);
bool _connected {false}; // TCP session ok bool _connected {false}; // TCP session ok
bool _logged_in {false}; // IRC login completed bool _logged_in {false}; // IRC login completed
std::string _nickname {""}; std::string _nickname {""};
char _read_buffer[IRC_BUFFER_SIZE]; char _read_buffer[IRC_BUFFER_SIZE];
std::deque<struct IRCMessage> _incoming_private_messages; std::deque<IRCMessage> _incoming_private_messages;
SGPropertyNode *_pReadyFlag {nullptr}; SGPropertyNode *_pReadyFlag {nullptr};
SGPropertyNode *_pMessageCountIn {nullptr}; SGPropertyNode *_pMessageCountIn {nullptr};

View file

@ -54,6 +54,8 @@
#include <FDM/flightProperties.hxx> #include <FDM/flightProperties.hxx>
#include <Time/TimeManager.hxx> #include <Time/TimeManager.hxx>
#include <Main/sentryIntegration.hxx> #include <Main/sentryIntegration.hxx>
#include "mpirc.hxx"
#include "cpdlc.hxx"
#if defined(_MSC_VER) || defined(__MINGW32__) #if defined(_MSC_VER) || defined(__MINGW32__)
#include <WS2tcpip.h> #include <WS2tcpip.h>
@ -836,7 +838,7 @@ static inline bool IsIncludedInPacket(int filter_base, int property_id)
// rxport: incoming port number (default: 5000) // rxport: incoming port number (default: 5000)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
static bool do_multiplayer_connect(const SGPropertyNode * arg, SGPropertyNode * root) { static bool do_multiplayer_connect(const SGPropertyNode * arg, SGPropertyNode * root) {
FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem("mp"); const auto self = globals->get_subsystem<FGMultiplayMgr>();
if (!self) { if (!self) {
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
return false; return false;
@ -871,7 +873,7 @@ static bool do_multiplayer_connect(const SGPropertyNode * arg, SGPropertyNode *
// none // none
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
static bool do_multiplayer_disconnect(const SGPropertyNode * arg, SGPropertyNode * root) { static bool do_multiplayer_disconnect(const SGPropertyNode * arg, SGPropertyNode * root) {
FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem("mp"); const auto self = globals->get_subsystem<FGMultiplayMgr>();
if (!self) { if (!self) {
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
return false; return false;
@ -895,7 +897,7 @@ do_multiplayer_refreshserverlist (const SGPropertyNode * arg, SGPropertyNode * r
{ {
using namespace simgear; using namespace simgear;
FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem ("mp"); const auto self = globals->get_subsystem<FGMultiplayMgr>();
if (!self) { if (!self) {
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
return false; return false;
@ -953,7 +955,7 @@ do_multiplayer_refreshserverlist (const SGPropertyNode * arg, SGPropertyNode * r
static bool do_cpdlc_connect(const SGPropertyNode* arg, SGPropertyNode* root) static bool do_cpdlc_connect(const SGPropertyNode* arg, SGPropertyNode* root)
{ {
FGMultiplayMgr* self = (FGMultiplayMgr*)globals->get_subsystem("mp"); const auto self = globals->get_subsystem<FGMultiplayMgr>();
if (!self) { if (!self) {
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
return false; return false;
@ -962,9 +964,9 @@ static bool do_cpdlc_connect(const SGPropertyNode* arg, SGPropertyNode* root)
// check for atc argument // check for atc argument
std::string authority = arg->getStringValue("atc"); std::string authority = arg->getStringValue("atc");
// otherwise see if we got a property name to read out // otherwise see if we got a property name to read out
if (!authority.size()) { if (authority.empty()) {
std::string name = arg->getStringValue("property"); std::string name = arg->getStringValue("property");
if (name.size()) { if (!name.empty()) {
SGPropertyNode* pNode = globals->get_props()->getNode(name); SGPropertyNode* pNode = globals->get_props()->getNode(name);
if (!pNode) { return false; } if (!pNode) { return false; }
authority = pNode->getStringValue(); authority = pNode->getStringValue();
@ -979,7 +981,7 @@ static bool do_cpdlc_connect(const SGPropertyNode* arg, SGPropertyNode* root)
static bool do_cpdlc_send_msg(const SGPropertyNode* arg, SGPropertyNode* root) static bool do_cpdlc_send_msg(const SGPropertyNode* arg, SGPropertyNode* root)
{ {
FGMultiplayMgr* self = (FGMultiplayMgr*)globals->get_subsystem("mp"); const auto self = globals->get_subsystem<FGMultiplayMgr>();
if (!self) { if (!self) {
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
return false; return false;
@ -988,9 +990,9 @@ static bool do_cpdlc_send_msg(const SGPropertyNode* arg, SGPropertyNode* root)
// check for message argument // check for message argument
std::string message = arg->getStringValue("message"); std::string message = arg->getStringValue("message");
// otherwise see if we got a property name to read out // otherwise see if we got a property name to read out
if (!message.size()) { if (message.empty()) {
std::string name = arg->getStringValue("property"); std::string name = arg->getStringValue("property");
if (name.size()) { if (!name.empty()) {
SGPropertyNode* pNode = globals->get_props()->getNode(name); SGPropertyNode* pNode = globals->get_props()->getNode(name);
if (!pNode) { return false; } if (!pNode) { return false; }
message = pNode->getStringValue(); message = pNode->getStringValue();
@ -1004,7 +1006,7 @@ static bool do_cpdlc_send_msg(const SGPropertyNode* arg, SGPropertyNode* root)
static bool do_cpdlc_next_msg(const SGPropertyNode* arg, SGPropertyNode* root) static bool do_cpdlc_next_msg(const SGPropertyNode* arg, SGPropertyNode* root)
{ {
FGMultiplayMgr* self = (FGMultiplayMgr*)globals->get_subsystem("mp"); const auto self = globals->get_subsystem<FGMultiplayMgr>();
if (!self) { if (!self) {
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
return false; return false;
@ -1015,7 +1017,7 @@ static bool do_cpdlc_next_msg(const SGPropertyNode* arg, SGPropertyNode* root)
static bool do_cpdlc_disconnect(const SGPropertyNode* arg, SGPropertyNode* root) static bool do_cpdlc_disconnect(const SGPropertyNode* arg, SGPropertyNode* root)
{ {
FGMultiplayMgr* self = (FGMultiplayMgr*)globals->get_subsystem("mp"); const auto self = globals->get_subsystem<FGMultiplayMgr>();
if (!self) { if (!self) {
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
return false; return false;
@ -1178,8 +1180,8 @@ FGMultiplayMgr::init (void)
} }
// MP IRC CONNECTION SETUP // MP IRC CONNECTION SETUP
std::string host = fgHasNode(MPIRC_SERVER_HOST_PROPERTY) ? fgGetString(MPIRC_SERVER_HOST_PROPERTY) : MPIRC_SERVER_HOST_DEFAULT; std::string host = fgGetString(MPIRC_SERVER_HOST_PROPERTY, MPIRC_SERVER_HOST_DEFAULT);
std::string port = fgHasNode(MPIRC_SERVER_PORT_PROPERTY) ? fgGetString(MPIRC_SERVER_PORT_PROPERTY) : IRC_DEFAULT_PORT; std::string port = fgGetString(MPIRC_SERVER_PORT_PROPERTY, IRC_DEFAULT_PORT);
SG_LOG(SG_NETWORK, SG_DEBUG, "Creating socket to MP IRC service " + host + " on port " + port); SG_LOG(SG_NETWORK, SG_DEBUG, "Creating socket to MP IRC service " + host + " on port " + port);
_mpirc = std::make_unique<IRCConnection>(MPIRC_NICK_PREFIX + mCallsign, host, port); _mpirc = std::make_unique<IRCConnection>(MPIRC_NICK_PREFIX + mCallsign, host, port);

View file

@ -44,8 +44,8 @@ const int MAX_MP_PROTOCOL_VERSION = 2;
#include <simgear/io/raw_socket.hxx> #include <simgear/io/raw_socket.hxx>
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
#include "mpirc.hxx" class IRCConnection;
#include "cpdlc.hxx" class CPDLCManager;
const std::string MPIRC_SERVER_HOST_DEFAULT {"mpirc.flightgear.org"}; const std::string MPIRC_SERVER_HOST_DEFAULT {"mpirc.flightgear.org"};
const std::string MPIRC_SERVER_HOST_PROPERTY {"/network/mpirc/server-host"}; const std::string MPIRC_SERVER_HOST_PROPERTY {"/network/mpirc/server-host"};