Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
protocol_negotiator.cpp
Go to the documentation of this file.
1/* Flow-IPC: Core
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19
22#include <flow/error/error.hpp>
23#include <cassert>
24#include <utility>
25
26namespace ipc::transport
27{
28
29Protocol_negotiator::Protocol_negotiator(flow::log::Logger* logger_ptr, util::String_view nickname,
30 proto_ver_t local_max_proto_ver, proto_ver_t local_min_proto_ver) :
31 flow::log::Log_context(logger_ptr, Log_component::S_TRANSPORT),
32 m_nickname(nickname),
33 m_local_max_proto_ver(local_max_proto_ver),
34 m_local_min_proto_ver(local_min_proto_ver),
35 m_local_max_proto_ver_sent(false),
36 m_negotiated_proto_ver(S_VER_UNKNOWN)
37{
38 assert((m_local_min_proto_ver > 0) && "Broke contract.");
39 assert((m_local_max_proto_ver >= m_local_min_proto_ver) && "Broke contract.");
40
41 FLOW_LOG_INFO("Protocol_negotiator [" << m_nickname << "]: We speak protocol version range "
42 "[" << m_local_min_proto_ver << ", " << m_local_max_proto_ver << "].");
43}
44
47
49{
50 operator=(std::move(src));
51}
52
54{
55 if (this != &src)
56 {
57 operator=(static_cast<const Protocol_negotiator&>(src));
58 // This (which satisfies our contract, to make src as-if-just-cted) is the only reason we're not `= default`:
59 src.reset();
60 }
61 return *this;
62}
63
65{
68}
69
71{
73}
74
76{
77 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(bool, compute_negotiated_proto_ver, opposing_max_proto_ver, _1);
78 // ^-- Call ourselves and return if err_code is null. If got to present line, err_code is not null.
79
81 {
82 FLOW_LOG_TRACE("Protocol_negotiator [" << m_nickname << "]: We were asked to compute negotiated protocol version "
83 "based on opposing max-version [" << opposing_max_proto_ver << "]; but we have already done so "
84 "in the past (result: [" << negotiated_proto_ver() << "]); no-op. "
85 "Tip: Check for negotiated_proto_ver()=UNKNOWN before calling us.");
86 return false;
87 }
88 // else: As advertised we validate opposing_max_proto_ver for the caller first.
89
90 if (opposing_max_proto_ver <= 0)
91 {
92 FLOW_LOG_WARNING("Protocol_negotiator [" << m_nickname << "]: Negotiation computation: "
93 "We speak preferred (highest) version [" << m_local_max_proto_ver << "]; "
94 "they speak at most [" << opposing_max_proto_ver << "]. The latter value is in and of itself "
95 "invalid -- we cannot trust the other side at all; or there may be a bug in user code here. "
96 "Presumably we will abruptly close this comm pathway shortly.");
99 }
100 // Use the simple algorithm explained/justified in class doc header.
101
102 else if (m_local_max_proto_ver <= opposing_max_proto_ver)
103 {
104 FLOW_LOG_INFO("Protocol_negotiator [" << m_nickname << "]: Negotiation computation: "
105 "We speak preferred (highest) version [" << m_local_max_proto_ver << "]; "
106 "they speak at most [" << opposing_max_proto_ver << "]; therefore we shall speak "
107 "[" << m_local_max_proto_ver << "], unless opposing side lacks backwards-compatibility with it, "
108 "in which case it will abruptly close this comm pathway shortly.");
110 err_code->clear();
111 }
112 else if (opposing_max_proto_ver >= m_local_min_proto_ver)
113 {
114 FLOW_LOG_INFO("Protocol_negotiator [" << m_nickname << "]: Negotiation computation: "
115 "We speak preferred (highest) version [" << m_local_max_proto_ver << "]; "
116 "they speak at most [" << opposing_max_proto_ver << "]; therefore we shall speak "
117 "[" << opposing_max_proto_ver << "], as we are backwards-compatible with that version.");
118 m_negotiated_proto_ver = opposing_max_proto_ver;
119 err_code->clear();
120 }
121 else
122 {
123 FLOW_LOG_WARNING("Protocol_negotiator [" << m_nickname << "]: Negotiation computation: "
124 "We speak preferred (highest) version [" << m_local_max_proto_ver << "]; "
125 "they speak at most [" << opposing_max_proto_ver << "]; therefore we lack backwards-compatibility "
126 "with that older version. Presumably we will abruptly close this comm pathway shortly.");
129 }
130
131 return true;
132} // Protocol_negotiator::compute_negotiated_proto_ver()
133
135{
137 {
138 return S_VER_ALREADY_SENT; // Don't spam logs; they might be calling this for every out-message.
139 }
140 // else
141 FLOW_LOG_INFO("Protocol_negotiator [" << m_nickname << "]: About to send our preferred (highest) version "
142 "[" << m_local_max_proto_ver << "] to opposing side for the first and only time.");
145}
146
147} // namespace ipc::transport
A simple state machine that, assuming the opposing side of a comm pathway uses an equivalent state ma...
static constexpr proto_ver_t S_VER_UNSUPPORTED
A proto_ver_t value, namely zero, which is a reserved value indicating "unsupported version"; it is n...
void reset()
Resets the negotiation state, meaning back to the state as-if just after ctor invoked.
std::string m_nickname
The nickname from ctor. Not const so as to support assignment.
int16_t proto_ver_t
Type sufficient to store a protocol version; positive values identify newer versions of a protocol; w...
Protocol_negotiator(flow::log::Logger *logger_ptr, util::String_view nickname, proto_ver_t local_max_proto_ver, proto_ver_t local_min_proto_ver)
Constructs a comm pathway's negotiator object in initial state wherein: (1) negotiated_proto_ver() re...
proto_ver_t local_max_proto_ver_for_sending()
Returns local_max_proto_ver from ctor the first time it is called and S_VER_ALREADY_SENT subsequently...
proto_ver_t m_local_max_proto_ver
local_max_proto_ver from ctor. Not const so as to support assignment.
bool compute_negotiated_proto_ver(proto_ver_t opposing_max_proto_ver, Error_code *err_code=nullptr)
Based on the presumably-just-received-from-opposing-side value of their local_max_proto_ver,...
proto_ver_t negotiated_proto_ver() const
Returns S_VER_UNKNOWN before compute_negotiated_proto_ver(); then either the positive version of the ...
static constexpr proto_ver_t S_VER_UNKNOWN
A proto_ver_t value, namely a negative one, which is a reserved value indicating "unknown version"; i...
static constexpr proto_ver_t S_VER_ALREADY_SENT
An proto_ver_t value, namely a negative one, which is a reserved value specifically for return by loc...
proto_ver_t m_negotiated_proto_ver
See negotiated_proto_ver().
proto_ver_t m_local_min_proto_ver
local_min_proto_ver from ctor. Not const so as to support assignment.
bool m_local_max_proto_ver_sent
Init value false indicating local_max_proto_ver_for_sending() has not been called; subsequently true.
Protocol_negotiator & operator=(const Protocol_negotiator &src)
Copy-assigns *this to be equal to src.
@ S_PROTOCOL_NEGOTIATION_OPPOSING_VER_INVALID
In protocol negotiation, opposing side sent invalid version value (not positive, not a number,...
@ S_PROTOCOL_NEGOTIATION_OPPOSING_VER_TOO_OLD
In protocol negotiation, opposing side reported its newest protocol version is even older than the mo...
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
flow::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:112
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
Definition: common.hpp:338
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313