mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-23 12:48:40 -05:00
Make UDP message handling version mismatch tolerant
By providing safe defaults for expected input fields that are not present in messages from older version senders, it is now possible to mix versions of clients and servers. This relies on fields never changing meaning or content, new fields may be safely added to the end of existing messages. Merged from the wsjtx-1.5 branch. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5338 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
155c9ab576
commit
c42e0407b0
@ -38,11 +38,13 @@ public:
|
|||||||
closedown ();
|
closedown ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum StreamStatus {Fail, Short, OK};
|
||||||
|
|
||||||
void parse_message (QByteArray const& msg);
|
void parse_message (QByteArray const& msg);
|
||||||
void pending_datagrams ();
|
void pending_datagrams ();
|
||||||
void heartbeat ();
|
void heartbeat ();
|
||||||
void closedown ();
|
void closedown ();
|
||||||
bool check_status (QDataStream const&) const;
|
StreamStatus check_status (QDataStream const&) const;
|
||||||
|
|
||||||
Q_SLOT void host_info_results (QHostInfo);
|
Q_SLOT void host_info_results (QHostInfo);
|
||||||
|
|
||||||
@ -91,7 +93,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
//
|
//
|
||||||
NetworkMessage::Reader in {msg};
|
NetworkMessage::Reader in {msg};
|
||||||
|
|
||||||
if (id_ == in.id ()) // for us
|
if (OK == check_status (in) && id_ == in.id ()) // OK and for us
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// message format is described in NetworkMessage.hpp
|
// message format is described in NetworkMessage.hpp
|
||||||
@ -108,7 +110,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
QByteArray mode;
|
QByteArray mode;
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
|
in >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
|
||||||
if (check_status (in))
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->reply (time, snr, delta_time, delta_frequency
|
Q_EMIT self_->reply (time, snr, delta_time, delta_frequency
|
||||||
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
|
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
|
||||||
@ -117,23 +119,25 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NetworkMessage::Replay:
|
case NetworkMessage::Replay:
|
||||||
if (check_status (in))
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->replay ();
|
Q_EMIT self_->replay ();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NetworkMessage::HaltTx:
|
case NetworkMessage::HaltTx:
|
||||||
if (check_status (in))
|
|
||||||
{
|
{
|
||||||
bool auto_only;
|
bool auto_only {false};
|
||||||
in >> auto_only;
|
in >> auto_only;
|
||||||
|
if (check_status (in) != Fail)
|
||||||
|
{
|
||||||
Q_EMIT self_->halt_tx (auto_only);
|
Q_EMIT self_->halt_tx (auto_only);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NetworkMessage::FreeText:
|
case NetworkMessage::FreeText:
|
||||||
if (check_status (in))
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
in >> message;
|
in >> message;
|
||||||
@ -163,7 +167,7 @@ void MessageClient::impl::heartbeat ()
|
|||||||
{
|
{
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id_};
|
NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id_};
|
||||||
if (check_status (hb))
|
if (OK == check_status (hb))
|
||||||
{
|
{
|
||||||
writeDatagram (message, server_, server_port_);
|
writeDatagram (message, server_, server_port_);
|
||||||
}
|
}
|
||||||
@ -176,20 +180,22 @@ void MessageClient::impl::closedown ()
|
|||||||
{
|
{
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::Close, id_};
|
NetworkMessage::Builder out {&message, NetworkMessage::Close, id_};
|
||||||
if (check_status (out))
|
if (OK == check_status (out))
|
||||||
{
|
{
|
||||||
writeDatagram (message, server_, server_port_);
|
writeDatagram (message, server_, server_port_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageClient::impl::check_status (QDataStream const& stream) const
|
auto MessageClient::impl::check_status (QDataStream const& stream) const -> StreamStatus
|
||||||
{
|
{
|
||||||
auto stat = stream.status ();
|
auto stat = stream.status ();
|
||||||
|
StreamStatus result {Fail};
|
||||||
switch (stat)
|
switch (stat)
|
||||||
{
|
{
|
||||||
case QDataStream::ReadPastEnd:
|
case QDataStream::ReadPastEnd:
|
||||||
Q_EMIT self_->error ("Message serialization error: read failed");
|
qDebug () << __PRETTY_FUNCTION__ << " warning: short UDP message received.";
|
||||||
|
result = Short;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QDataStream::ReadCorruptData:
|
case QDataStream::ReadCorruptData:
|
||||||
@ -201,9 +207,10 @@ bool MessageClient::impl::check_status (QDataStream const& stream) const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
result = OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return QDataStream::Ok == stat;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageClient::MessageClient (QString const& id, QString const& server, port_type server_port, QObject * self)
|
MessageClient::MessageClient (QString const& id, QString const& server, port_type server_port, QObject * self)
|
||||||
@ -262,10 +269,14 @@ void MessageClient::status_update (Frequency f, QString const& mode, QString con
|
|||||||
NetworkMessage::Builder out {&message, NetworkMessage::Status, m_->id_};
|
NetworkMessage::Builder out {&message, NetworkMessage::Status, m_->id_};
|
||||||
out << f << mode.toUtf8 () << dx_call.toUtf8 () << report.toUtf8 () << tx_mode.toUtf8 ()
|
out << f << mode.toUtf8 () << dx_call.toUtf8 () << report.toUtf8 () << tx_mode.toUtf8 ()
|
||||||
<< tx_enabled << transmitting;
|
<< tx_enabled << transmitting;
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,10 +288,14 @@ void MessageClient::decode (bool is_new, QTime time, qint32 snr, float delta_tim
|
|||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::Decode, m_->id_};
|
NetworkMessage::Builder out {&message, NetworkMessage::Decode, m_->id_};
|
||||||
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
|
out << is_new << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,10 +305,14 @@ void MessageClient::clear_decodes ()
|
|||||||
{
|
{
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::Clear, m_->id_};
|
NetworkMessage::Builder out {&message, NetworkMessage::Clear, m_->id_};
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,9 +327,13 @@ void MessageClient::qso_logged (QDateTime time, QString const& dx_call, QString
|
|||||||
NetworkMessage::Builder out {&message, NetworkMessage::QSOLogged, m_->id_};
|
NetworkMessage::Builder out {&message, NetworkMessage::QSOLogged, m_->id_};
|
||||||
out << time << dx_call.toUtf8 () << dx_grid.toUtf8 () << dial_frequency << mode.toUtf8 ()
|
out << time << dx_call.toUtf8 () << dx_grid.toUtf8 () << dial_frequency << mode.toUtf8 ()
|
||||||
<< report_sent.toUtf8 () << report_received.toUtf8 () << tx_power.toUtf8 () << comments.toUtf8 () << name.toUtf8 ();
|
<< report_sent.toUtf8 () << report_received.toUtf8 () << tx_power.toUtf8 () << comments.toUtf8 () << name.toUtf8 ();
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
m_->writeDatagram (message, m_->server_, m_->server_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,12 +34,14 @@ public:
|
|||||||
clock_->start (NetworkMessage::pulse * 1000);
|
clock_->start (NetworkMessage::pulse * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum StreamStatus {Fail, Short, OK};
|
||||||
|
|
||||||
void leave_multicast_group ();
|
void leave_multicast_group ();
|
||||||
void join_multicast_group ();
|
void join_multicast_group ();
|
||||||
void parse_message (QHostAddress const& sender, port_type sender_port, QByteArray const& msg);
|
void parse_message (QHostAddress const& sender, port_type sender_port, QByteArray const& msg);
|
||||||
void tick ();
|
void tick ();
|
||||||
void pending_datagrams ();
|
void pending_datagrams ();
|
||||||
bool check_status (QDataStream const&) const;
|
StreamStatus check_status (QDataStream const&) const;
|
||||||
|
|
||||||
MessageServer * self_;
|
MessageServer * self_;
|
||||||
port_type port_;
|
port_type port_;
|
||||||
@ -110,6 +112,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
|||||||
NetworkMessage::Reader in {msg};
|
NetworkMessage::Reader in {msg};
|
||||||
|
|
||||||
auto id = in.id ();
|
auto id = in.id ();
|
||||||
|
if (OK == check_status (in))
|
||||||
|
{
|
||||||
bool new_client {false};
|
bool new_client {false};
|
||||||
if (!clients_.contains (id))
|
if (!clients_.contains (id))
|
||||||
{
|
{
|
||||||
@ -142,10 +146,10 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
|||||||
QByteArray dx_call;
|
QByteArray dx_call;
|
||||||
QByteArray report;
|
QByteArray report;
|
||||||
QByteArray tx_mode;
|
QByteArray tx_mode;
|
||||||
bool tx_enabled;
|
bool tx_enabled {false};
|
||||||
bool transmitting;
|
bool transmitting {false};
|
||||||
in >> f >> mode >> dx_call >> report >> tx_mode >> tx_enabled >> transmitting;
|
in >> f >> mode >> dx_call >> report >> tx_mode >> tx_enabled >> transmitting;
|
||||||
if (check_status (in))
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call)
|
Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call)
|
||||||
, QString::fromUtf8 (report), QString::fromUtf8 (tx_mode)
|
, QString::fromUtf8 (report), QString::fromUtf8 (tx_mode)
|
||||||
@ -157,7 +161,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
|||||||
case NetworkMessage::Decode:
|
case NetworkMessage::Decode:
|
||||||
{
|
{
|
||||||
// unpack message
|
// unpack message
|
||||||
bool is_new;
|
bool is_new {true};
|
||||||
QTime time;
|
QTime time;
|
||||||
qint32 snr;
|
qint32 snr;
|
||||||
float delta_time;
|
float delta_time;
|
||||||
@ -165,7 +169,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
|||||||
QByteArray mode;
|
QByteArray mode;
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
|
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode >> message;
|
||||||
if (check_status (in))
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency
|
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency
|
||||||
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
|
, QString::fromUtf8 (mode), QString::fromUtf8 (message));
|
||||||
@ -187,7 +191,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
|||||||
QByteArray name;
|
QByteArray name;
|
||||||
in >> time >> dx_call >> dx_grid >> dial_frequency >> mode >> report_sent >> report_received
|
in >> time >> dx_call >> dx_grid >> dial_frequency >> mode >> report_sent >> report_received
|
||||||
>> tx_power >> comments >> name;
|
>> tx_power >> comments >> name;
|
||||||
if (check_status (in))
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->qso_logged (id, time, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid)
|
Q_EMIT self_->qso_logged (id, time, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid)
|
||||||
, dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent)
|
, dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent)
|
||||||
@ -198,7 +202,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NetworkMessage::Close:
|
case NetworkMessage::Close:
|
||||||
if (check_status (in))
|
if (check_status (in) != Fail)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->client_closed (id);
|
Q_EMIT self_->client_closed (id);
|
||||||
clients_.remove (id);
|
clients_.remove (id);
|
||||||
@ -210,6 +214,11 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT self_->error ("MessageServer warning: invalid UDP message received");
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (std::exception const& e)
|
catch (std::exception const& e)
|
||||||
{
|
{
|
||||||
Q_EMIT self_->error (QString {"MessageServer exception: %1"}.arg (e.what ()));
|
Q_EMIT self_->error (QString {"MessageServer exception: %1"}.arg (e.what ()));
|
||||||
@ -234,13 +243,15 @@ void MessageServer::impl::tick ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageServer::impl::check_status (QDataStream const& stream) const
|
auto MessageServer::impl::check_status (QDataStream const& stream) const -> StreamStatus
|
||||||
{
|
{
|
||||||
auto stat = stream.status ();
|
auto stat = stream.status ();
|
||||||
|
StreamStatus result {Fail};
|
||||||
switch (stat)
|
switch (stat)
|
||||||
{
|
{
|
||||||
case QDataStream::ReadPastEnd:
|
case QDataStream::ReadPastEnd:
|
||||||
Q_EMIT self_->error ("Message serialization error: read failed");
|
qDebug () << __PRETTY_FUNCTION__ << " warning: short UDP message received.";
|
||||||
|
result = Short;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QDataStream::ReadCorruptData:
|
case QDataStream::ReadCorruptData:
|
||||||
@ -252,9 +263,10 @@ bool MessageServer::impl::check_status (QDataStream const& stream) const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
result = OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return QDataStream::Ok == stat;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageServer::MessageServer (QObject * parent)
|
MessageServer::MessageServer (QObject * parent)
|
||||||
@ -296,10 +308,14 @@ void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delt
|
|||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::Reply, id};
|
NetworkMessage::Builder out {&message, NetworkMessage::Reply, id};
|
||||||
out << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
|
out << time << snr << delta_time << delta_frequency << mode.toUtf8 () << message_text.toUtf8 ();
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,10 +326,14 @@ void MessageServer::replay (QString const& id)
|
|||||||
{
|
{
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::Replay, id};
|
NetworkMessage::Builder out {&message, NetworkMessage::Replay, id};
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,10 +345,14 @@ void MessageServer::halt_tx (QString const& id, bool auto_only)
|
|||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, id};
|
NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, id};
|
||||||
out << auto_only;
|
out << auto_only;
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,9 +364,13 @@ void MessageServer::free_text (QString const& id, QString const& text)
|
|||||||
QByteArray message;
|
QByteArray message;
|
||||||
NetworkMessage::Builder out {&message, NetworkMessage::FreeText, id};
|
NetworkMessage::Builder out {&message, NetworkMessage::FreeText, id};
|
||||||
out << text.toUtf8 ();
|
out << text.toUtf8 ();
|
||||||
if (m_->check_status (out))
|
if (impl::OK == m_->check_status (out))
|
||||||
{
|
{
|
||||||
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
m_->writeDatagram (message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Q_EMIT error ("Error creating UDP message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user