CPDLC updates from Henning
This commit is contained in:
parent
527f58d353
commit
af387107a3
6 changed files with 75 additions and 57 deletions
|
@ -26,6 +26,11 @@
|
|||
#include "cpdlc.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
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
// resetting _data_authority in disconnect()
|
||||
if (!_data_authority.size()) {
|
||||
if (!authority.size()) {
|
||||
if (_data_authority.empty()) {
|
||||
if (authority.empty()) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "cpdlcConnect not possible: empty argument!");
|
||||
return false;
|
||||
} else {
|
||||
_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!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// launch IRC connection as needed
|
||||
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()) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "IRC login failed.");
|
||||
return false;
|
||||
}
|
||||
_status = CPDLC_WAIT_IRC_READY;
|
||||
return true;
|
||||
} 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;
|
||||
_pStatus->setIntValue(_status);
|
||||
return _irc->sendPrivmsg(_data_authority, CPDLC_MSGPREFIX_CONNECT);
|
||||
|
@ -97,7 +103,7 @@ bool CPDLCManager::connect(const std::string authority = "")
|
|||
|
||||
void CPDLCManager::disconnect()
|
||||
{
|
||||
if (_irc && _irc->isConnected() && _data_authority.size()) {
|
||||
if (_irc && _irc->isConnected() && !_data_authority.empty()) {
|
||||
_irc->sendPrivmsg(_data_authority, CPDLC_MSGPREFIX_DISCONNECT);
|
||||
}
|
||||
_data_authority = "";
|
||||
|
@ -137,7 +143,7 @@ void CPDLCManager::update()
|
|||
if (_irc) {
|
||||
if (_irc->isConnected()) {
|
||||
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();
|
||||
}
|
||||
if (_irc->hasMessage()) {
|
||||
|
@ -155,9 +161,9 @@ void CPDLCManager::update()
|
|||
// process incoming 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)
|
||||
if (message.textline.find(CPDLC_MSGPREFIX_CONNECT) == 0) {
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "CPDLC got connected.");
|
||||
_data_authority = message.sender;
|
||||
_pDataAuthority->setStringValue(_data_authority); // make this known to ACFT
|
||||
_status = CPDLC_ONLINE;
|
||||
|
@ -171,11 +177,13 @@ void CPDLCManager::processMessage(struct IRCMessage message)
|
|||
// connection rejected, or terminated by ATC
|
||||
if (message.textline.find(CPDLC_MSGPREFIX_DISCONNECT) == 0) {
|
||||
if (message.sender == _data_authority) {
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "CPDLC got disconnect.");
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
// store valid message in queue for later retrieval by aircraft
|
||||
else if (message.textline.find(CPDLC_MSGPREFIX_MSG) == 0) {
|
||||
SG_LOG(SG_NETWORK, SG_INFO, "CPDLC message");
|
||||
_incoming_messages.push_back(message);
|
||||
_pNewMessage->setBoolValue(1);
|
||||
}
|
||||
|
|
|
@ -35,12 +35,6 @@
|
|||
#include <simgear/io/sg_socket.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 {
|
||||
CPDLC_OFFLINE,
|
||||
CPDLC_CONNECTING,
|
||||
|
|
|
@ -27,8 +27,16 @@
|
|||
#include <Main/fg_props.hxx>
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
@ -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()) {
|
||||
return false;
|
||||
}
|
||||
if (nickname.length()) {
|
||||
if (!nickname.empty()) {
|
||||
_nickname = nickname;
|
||||
} else {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "IRC login requires nickname argument.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -86,9 +95,12 @@ void IRCConnection::quit()
|
|||
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 ");
|
||||
line += recipient;
|
||||
line += " :";
|
||||
|
@ -99,14 +111,18 @@ bool IRCConnection::sendPrivmsg(const std::string recipient, const std::string t
|
|||
if (_pIRCReturnCode) _pIRCReturnCode->setStringValue("");
|
||||
return true;
|
||||
} else {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "IRC send privmsg failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ");
|
||||
lines += channel;
|
||||
lines += IRC_MSG_TERMINATOR;
|
||||
|
@ -114,9 +130,12 @@ bool IRCConnection::join(const std::string 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 ");
|
||||
lines += channel;
|
||||
lines += IRC_MSG_TERMINATOR;
|
||||
|
@ -145,7 +164,9 @@ void IRCConnection::update()
|
|||
// open a connection to IRC server
|
||||
bool IRCConnection::connect()
|
||||
{
|
||||
if (_connected) return false;
|
||||
if (_connected) {
|
||||
return true;
|
||||
}
|
||||
|
||||
_connected = open(SG_IO_OUT);
|
||||
if (_connected) {
|
||||
|
@ -168,7 +189,8 @@ void 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;
|
||||
std::string line("PONG ");
|
||||
|
@ -287,6 +309,7 @@ bool IRCConnection::parseReceivedLine(std::string line)
|
|||
|
||||
// TODO: anything sensitive here that we should handle?
|
||||
// e.g. IRC user has disconnected and username == {current-cpdlc-authority}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,15 +35,6 @@
|
|||
#include <simgear/io/sg_socket.hxx>
|
||||
|
||||
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;
|
||||
|
||||
struct IRCMessage {
|
||||
|
@ -64,19 +55,19 @@ struct IRCMessage {
|
|||
class IRCConnection : SGSocket
|
||||
{
|
||||
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();
|
||||
|
||||
void setupProperties(const std::string path);
|
||||
void setupProperties(std::string path);
|
||||
void update();
|
||||
|
||||
bool login(const std::string nickname);
|
||||
bool login(const std::string &nickname);
|
||||
bool login();
|
||||
void quit();
|
||||
|
||||
bool sendPrivmsg(const std::string recipient, const std::string textline);
|
||||
bool join(const std::string channel);
|
||||
bool part(const std::string channel);
|
||||
bool sendPrivmsg(const std::string &recipient, const std::string &textline);
|
||||
bool join(const std::string &channel);
|
||||
bool part(const std::string &channel);
|
||||
|
||||
|
||||
bool isConnected() const { return _connected; }
|
||||
|
@ -87,14 +78,14 @@ public:
|
|||
private:
|
||||
bool connect();
|
||||
void disconnect();
|
||||
void pong(const std::string recipient);
|
||||
void pong(const std::string &recipient);
|
||||
bool parseReceivedLine(std::string irc_line);
|
||||
|
||||
bool _connected {false}; // TCP session ok
|
||||
bool _logged_in {false}; // IRC login completed
|
||||
std::string _nickname {""};
|
||||
char _read_buffer[IRC_BUFFER_SIZE];
|
||||
std::deque<struct IRCMessage> _incoming_private_messages;
|
||||
std::deque<IRCMessage> _incoming_private_messages;
|
||||
|
||||
SGPropertyNode *_pReadyFlag {nullptr};
|
||||
SGPropertyNode *_pMessageCountIn {nullptr};
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#include <FDM/flightProperties.hxx>
|
||||
#include <Time/TimeManager.hxx>
|
||||
#include <Main/sentryIntegration.hxx>
|
||||
#include "mpirc.hxx"
|
||||
#include "cpdlc.hxx"
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#include <WS2tcpip.h>
|
||||
|
@ -836,7 +838,7 @@ static inline bool IsIncludedInPacket(int filter_base, int property_id)
|
|||
// rxport: incoming port number (default: 5000)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
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) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
return false;
|
||||
|
@ -871,7 +873,7 @@ static bool do_multiplayer_connect(const SGPropertyNode * arg, SGPropertyNode *
|
|||
// none
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
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) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
return false;
|
||||
|
@ -895,7 +897,7 @@ do_multiplayer_refreshserverlist (const SGPropertyNode * arg, SGPropertyNode * r
|
|||
{
|
||||
using namespace simgear;
|
||||
|
||||
FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem ("mp");
|
||||
const auto self = globals->get_subsystem<FGMultiplayMgr>();
|
||||
if (!self) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
return false;
|
||||
|
@ -953,7 +955,7 @@ do_multiplayer_refreshserverlist (const SGPropertyNode * arg, SGPropertyNode * r
|
|||
|
||||
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) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
return false;
|
||||
|
@ -962,9 +964,9 @@ static bool do_cpdlc_connect(const SGPropertyNode* arg, SGPropertyNode* root)
|
|||
// check for atc argument
|
||||
std::string authority = arg->getStringValue("atc");
|
||||
// otherwise see if we got a property name to read out
|
||||
if (!authority.size()) {
|
||||
if (authority.empty()) {
|
||||
std::string name = arg->getStringValue("property");
|
||||
if (name.size()) {
|
||||
if (!name.empty()) {
|
||||
SGPropertyNode* pNode = globals->get_props()->getNode(name);
|
||||
if (!pNode) { return false; }
|
||||
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)
|
||||
{
|
||||
FGMultiplayMgr* self = (FGMultiplayMgr*)globals->get_subsystem("mp");
|
||||
const auto self = globals->get_subsystem<FGMultiplayMgr>();
|
||||
if (!self) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
return false;
|
||||
|
@ -988,9 +990,9 @@ static bool do_cpdlc_send_msg(const SGPropertyNode* arg, SGPropertyNode* root)
|
|||
// check for message argument
|
||||
std::string message = arg->getStringValue("message");
|
||||
// otherwise see if we got a property name to read out
|
||||
if (!message.size()) {
|
||||
if (message.empty()) {
|
||||
std::string name = arg->getStringValue("property");
|
||||
if (name.size()) {
|
||||
if (!name.empty()) {
|
||||
SGPropertyNode* pNode = globals->get_props()->getNode(name);
|
||||
if (!pNode) { return false; }
|
||||
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)
|
||||
{
|
||||
FGMultiplayMgr* self = (FGMultiplayMgr*)globals->get_subsystem("mp");
|
||||
const auto self = globals->get_subsystem<FGMultiplayMgr>();
|
||||
if (!self) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
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)
|
||||
{
|
||||
FGMultiplayMgr* self = (FGMultiplayMgr*)globals->get_subsystem("mp");
|
||||
const auto self = globals->get_subsystem<FGMultiplayMgr>();
|
||||
if (!self) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
|
||||
return false;
|
||||
|
@ -1178,8 +1180,8 @@ FGMultiplayMgr::init (void)
|
|||
}
|
||||
|
||||
// MP IRC CONNECTION SETUP
|
||||
std::string host = fgHasNode(MPIRC_SERVER_HOST_PROPERTY) ? 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 host = fgGetString(MPIRC_SERVER_HOST_PROPERTY, MPIRC_SERVER_HOST_DEFAULT);
|
||||
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);
|
||||
|
||||
_mpirc = std::make_unique<IRCConnection>(MPIRC_NICK_PREFIX + mCallsign, host, port);
|
||||
|
|
|
@ -44,8 +44,8 @@ const int MAX_MP_PROTOCOL_VERSION = 2;
|
|||
#include <simgear/io/raw_socket.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include "mpirc.hxx"
|
||||
#include "cpdlc.hxx"
|
||||
class IRCConnection;
|
||||
class CPDLCManager;
|
||||
|
||||
const std::string MPIRC_SERVER_HOST_DEFAULT {"mpirc.flightgear.org"};
|
||||
const std::string MPIRC_SERVER_HOST_PROPERTY {"/network/mpirc/server-host"};
|
||||
|
|
Loading…
Add table
Reference in a new issue