diff --git a/src/svxlink/reflector/ReflectorClient.cpp b/src/svxlink/reflector/ReflectorClient.cpp index 354b0611..ea2cc06a 100644 --- a/src/svxlink/reflector/ReflectorClient.cpp +++ b/src/svxlink/reflector/ReflectorClient.cpp @@ -357,24 +357,35 @@ void ReflectorClient::handleMsgProtoVer(std::istream& is) MsgProtoVer msg; if (!msg.unpack(is)) { - cout << "Client " << m_con->remoteHost() << ":" << m_con->remotePort() - << " ERROR: Could not unpack MsgProtoVer\n"; + std::cout << "Client " << m_con->remoteHost() << ":" << m_con->remotePort() + << " ERROR: Could not unpack MsgProtoVer\n"; sendError("Illegal MsgProtoVer protocol message received"); return; } m_client_proto_ver.set(msg.majorVer(), msg.minorVer()); - ProtoVerRange valid_proto_ver_range( - ProtoVer(MIN_MAJOR_VER, MIN_MINOR_VER), - ProtoVer(MsgProtoVer::MAJOR, MsgProtoVer::MINOR)); - if (!valid_proto_ver_range.isWithinRange(m_client_proto_ver)) + ProtoVer max_proto_ver(MsgProtoVer::MAJOR, MsgProtoVer::MINOR); + if (m_client_proto_ver > max_proto_ver) { - cout << "Client " << m_con->remoteHost() << ":" << m_con->remotePort() - << " Incompatible protocol version: " - << msg.majorVer() << "." << msg.minorVer() << ". Should be " - << MsgProtoVer::MAJOR << "." << MsgProtoVer::MINOR << "." << endl; - stringstream ss; + std::cout << "Client " << m_con->remoteHost() << ":" << m_con->remotePort() + << " use protocol version " + << msg.majorVer() << "." << msg.minorVer() + << " which is newer than we can handle. Asking for downgrade to " + << MsgProtoVer::MAJOR << "." << MsgProtoVer::MINOR << "." + << std::endl; + sendMsg(MsgProtoVerDowngrade()); + return; + } + else if (m_client_proto_ver < ProtoVer(MIN_MAJOR_VER, MIN_MINOR_VER)) + { + std::cout << "Client " << m_con->remoteHost() << ":" << m_con->remotePort() + << " is using protocol version " + << msg.majorVer() << "." << msg.minorVer() + << " which is too old. Must at least be version " + << MIN_MAJOR_VER << "." << MIN_MINOR_VER << "." << std::endl; + std::ostringstream ss; ss << "Unsupported protocol version " << msg.majorVer() << "." - << msg.minorVer(); + << msg.minorVer() << ". Must be at least " + << MIN_MAJOR_VER << "." << MIN_MINOR_VER << "."; sendError(ss.str()); return; } diff --git a/src/svxlink/reflector/ReflectorMsg.h b/src/svxlink/reflector/ReflectorMsg.h index 3f919c44..d544e2ae 100644 --- a/src/svxlink/reflector/ReflectorMsg.h +++ b/src/svxlink/reflector/ReflectorMsg.h @@ -224,32 +224,6 @@ class ReflectorUdpMsgBase : public ReflectorUdpMsg /************************** Administrative Messages **************************/ -/** -@brief Protocol version TCP network message -@author Tobias Blomberg / SM0SVX -@date 2017-02-12 - -This is the first message exchanged between the client and the server. It tells -the server what protocol version that the client supports. If the client use a -protocol version that the server does not support, the client is denied access. -*/ -class MsgProtoVer : public ReflectorMsgBase<5> -{ - public: - static const uint16_t MAJOR = 2; - static const uint16_t MINOR = 0; - MsgProtoVer(void) : m_major(MAJOR), m_minor(MINOR) {} - uint16_t majorVer(void) const { return m_major; } - uint16_t minorVer(void) const { return m_minor; } - - ASYNC_MSG_MEMBERS(m_major, m_minor); - - private: - uint16_t m_major; - uint16_t m_minor; -}; /* MsgProtoVer */ - - /** @brief Heartbeat TCP network message @author Tobias Blomberg / SM0SVX @@ -265,6 +239,65 @@ class MsgHeartbeat : public ReflectorMsgBase<1> }; /* MsgHeartbeat */ +/** +@brief Protocol version TCP network message +@author Tobias Blomberg / SM0SVX +@date 2017-02-12 + +This is the first message exchanged between the client and the server. It is +sent by the client to tell the server what protocol version that the client +supports. If the client use a protocol version that the server does not +support, the client is denied access. Alternatively, if the client protocol +version is larger than what the server supports, the server may send a +MsgProtoVerDowngrade message to ask the client to use an older version of the +protocol. +*/ +class MsgProtoVer : public ReflectorMsgBase<5> +{ + public: + static const uint16_t MAJOR = 2; + static const uint16_t MINOR = 0; + MsgProtoVer(void) : m_major(MAJOR), m_minor(MINOR) {} + MsgProtoVer(uint16_t major, uint16_t minor) + : m_major(major), m_minor(minor) {} + uint16_t majorVer(void) const { return m_major; } + uint16_t minorVer(void) const { return m_minor; } + + ASYNC_MSG_MEMBERS(m_major, m_minor); + + private: + uint16_t m_major; + uint16_t m_minor; +}; /* MsgProtoVer */ + + +/** +@brief Protocol version downgrade request +@author Tobias Blomberg / SM0SVX +@date 2019-10-19 + +This message is sent by the reflector server to a client that announces a newer +protocol version than the server is able to support. The client should resend +the MsgProtoVer message set to a version number no larger than what the server +indicates in this message. The client must then use only protocol messages +compatible with the lower protocol version. +*/ +class MsgProtoVerDowngrade : public ReflectorMsgBase<6> +{ + public: + MsgProtoVerDowngrade(void) + : m_major(MsgProtoVer::MAJOR), m_minor(MsgProtoVer::MINOR) {} + uint16_t majorVer(void) const { return m_major; } + uint16_t minorVer(void) const { return m_minor; } + + ASYNC_MSG_MEMBERS(m_major, m_minor); + + private: + uint16_t m_major; + uint16_t m_minor; +}; /* MsgProtoVerDowngrade */ + + /** @brief Authentication challenge TCP network message @author Tobias Blomberg / SM0SVX diff --git a/src/svxlink/svxlink/ReflectorLogic.cpp b/src/svxlink/svxlink/ReflectorLogic.cpp index 2d401f32..dbc563d7 100644 --- a/src/svxlink/svxlink/ReflectorLogic.cpp +++ b/src/svxlink/svxlink/ReflectorLogic.cpp @@ -657,6 +657,9 @@ void ReflectorLogic::onFrameReceived(FramedTcpConnection *con, case MsgError::TYPE: handleMsgError(ss); break; + case MsgProtoVerDowngrade::TYPE: + handleMsgProtoVerDowngrade(ss); + break; case MsgAuthChallenge::TYPE: handleMsgAuthChallenge(ss); break; @@ -711,6 +714,23 @@ void ReflectorLogic::handleMsgError(std::istream& is) } /* ReflectorLogic::handleMsgError */ +void ReflectorLogic::handleMsgProtoVerDowngrade(std::istream& is) +{ + MsgProtoVerDowngrade msg; + if (!msg.unpack(is)) + { + cerr << "*** ERROR[" << name() << "]: Could not unpack MsgProtoVerDowngrade" << endl; + disconnect(); + return; + } + cout << name() << ": Server too old and we cannot downgrade to protocol version " + << msg.majorVer() << "." << msg.minorVer() << " from " + << MsgProtoVer::MAJOR << "." << MsgProtoVer::MINOR + << endl; + disconnect(); +} /* ReflectorLogic::handleMsgProtoVerDowngrade */ + + void ReflectorLogic::handleMsgAuthChallenge(std::istream& is) { if (m_con_state != STATE_EXPECT_AUTH_CHALLENGE) diff --git a/src/svxlink/svxlink/ReflectorLogic.h b/src/svxlink/svxlink/ReflectorLogic.h index f42e6fd5..26ab52f8 100644 --- a/src/svxlink/svxlink/ReflectorLogic.h +++ b/src/svxlink/svxlink/ReflectorLogic.h @@ -253,6 +253,7 @@ class ReflectorLogic : public LogicBase void onFrameReceived(Async::FramedTcpConnection *con, std::vector& data); void handleMsgError(std::istream& is); + void handleMsgProtoVerDowngrade(std::istream& is); void handleMsgAuthChallenge(std::istream& is); void handleMsgNodeList(std::istream& is); void handleMsgNodeJoined(std::istream& is); diff --git a/src/versions b/src/versions index a6f0485c..aa8f2c36 100644 --- a/src/versions +++ b/src/versions @@ -11,7 +11,7 @@ LIBECHOLIB=1.3.3 LIBASYNC=1.6.0.99.3-reflector_tg # SvxLink versions -SVXLINK=1.7.99.10-reflector_tg +SVXLINK=1.7.99.11-reflector_tg MODULE_HELP=1.0.0 MODULE_PARROT=1.1.1 MODULE_ECHO_LINK=1.5.0