blob: 4702bbe83c22785bf5469afb78c8fb4be373418f [file] [log] [blame]
Vernon Mauery9e801a22018-10-12 13:20:49 -07001#include "sol_context.hpp"
2
Tom Josephfbcac2e2017-03-14 18:15:07 +05303#include "main.hpp"
Vernon Mauery2085ae02021-06-10 11:51:00 -07004#include "message_handler.hpp"
Tom Josephfbcac2e2017-03-14 18:15:07 +05305#include "sd_event_loop.hpp"
Vernon Mauery2085ae02021-06-10 11:51:00 -07006#include "sessions_manager.hpp"
Tom Josephfbcac2e2017-03-14 18:15:07 +05307#include "sol_manager.hpp"
8
George Liu7b7f25f2022-07-04 17:07:32 +08009#include <errno.h>
10
11#include <phosphor-logging/lg2.hpp>
Vernon Mauery9e801a22018-10-12 13:20:49 -070012
Tom Josephfbcac2e2017-03-14 18:15:07 +053013namespace sol
14{
Tom Josephfbcac2e2017-03-14 18:15:07 +053015using namespace phosphor::logging;
16
Vernon Mauery6f353e82018-11-09 08:43:24 -080017Context::Context(std::shared_ptr<boost::asio::io_context> io,
18 uint8_t maxRetryCount, uint8_t sendThreshold, uint8_t instance,
19 session::SessionID sessionID) :
20 accumulateTimer(*io),
21 retryTimer(*io), maxRetryCount(maxRetryCount), retryCounter(maxRetryCount),
22 sendThreshold(sendThreshold), payloadInstance(instance),
23 sessionID(sessionID)
24{
Vernon Mauery2085ae02021-06-10 11:51:00 -070025 session = session::Manager::get().getSession(sessionID);
Vernon Mauerya6ad5e12020-02-21 14:54:24 -080026}
27
28std::shared_ptr<Context>
29 Context::makeContext(std::shared_ptr<boost::asio::io_context> io,
30 uint8_t maxRetryCount, uint8_t sendThreshold,
31 uint8_t instance, session::SessionID sessionID)
32{
33 auto ctx = std::make_shared<Context>(io, maxRetryCount, sendThreshold,
34 instance, sessionID);
35 ctx->enableAccumulateTimer(true);
36 return ctx;
Vernon Mauery6f353e82018-11-09 08:43:24 -080037}
38
39void Context::enableAccumulateTimer(bool enable)
40{
41 // fetch the timeout from the SOL manager
Vernon Mauery2085ae02021-06-10 11:51:00 -070042 std::chrono::microseconds interval = sol::Manager::get().accumulateInterval;
Vernon Mauery6f353e82018-11-09 08:43:24 -080043 if (enable)
44 {
45 accumulateTimer.expires_after(interval);
Vernon Mauerya6ad5e12020-02-21 14:54:24 -080046 std::weak_ptr<Context> weakRef = weak_from_this();
47 accumulateTimer.async_wait(
48 [weakRef](const boost::system::error_code& ec) {
49 std::shared_ptr<Context> self = weakRef.lock();
50 if (!ec && self)
51 {
52 self->charAccTimerHandler();
53 }
54 });
Vernon Mauery6f353e82018-11-09 08:43:24 -080055 }
56 else
57 {
58 accumulateTimer.cancel();
59 }
60}
61
62void Context::enableRetryTimer(bool enable)
63{
64 if (enable)
65 {
66 // fetch the timeout from the SOL manager
Vernon Mauery2085ae02021-06-10 11:51:00 -070067 std::chrono::microseconds interval = sol::Manager::get().retryInterval;
Vernon Mauery6f353e82018-11-09 08:43:24 -080068 retryTimer.expires_after(interval);
Vernon Mauerya6ad5e12020-02-21 14:54:24 -080069 std::weak_ptr<Context> weakRef = weak_from_this();
70 retryTimer.async_wait([weakRef](const boost::system::error_code& ec) {
71 std::shared_ptr<Context> self = weakRef.lock();
72 if (!ec && self)
Vernon Mauery6f353e82018-11-09 08:43:24 -080073 {
Vernon Mauerya6ad5e12020-02-21 14:54:24 -080074 self->retryTimerHandler();
Vernon Mauery6f353e82018-11-09 08:43:24 -080075 }
76 });
77 }
78 else
79 {
80 retryTimer.cancel();
81 }
82}
83
Vernon Mauery9e801a22018-10-12 13:20:49 -070084void Context::processInboundPayload(uint8_t seqNum, uint8_t ackSeqNum,
85 uint8_t count, bool status,
Vernon Mauery70fd29c2017-11-30 13:11:43 -080086 const std::vector<uint8_t>& input)
Tom Josephfbcac2e2017-03-14 18:15:07 +053087{
88 uint8_t respAckSeqNum = 0;
89 uint8_t acceptedCount = 0;
90 auto ack = false;
91
92 /*
93 * Check if the Inbound sequence number is same as the expected one.
94 * If the Packet Sequence Number is 0, it is an ACK-Only packet. Multiple
95 * outstanding sequence numbers are not supported in this version of the SOL
96 * specification. Retried packets use the same sequence number as the first
97 * packet.
98 */
Vernon Mauery9e801a22018-10-12 13:20:49 -070099 if (seqNum && (seqNum != seqNums.get(true)))
Tom Josephfbcac2e2017-03-14 18:15:07 +0530100 {
George Liu7b7f25f2022-07-04 17:07:32 +0800101 lg2::info("Out of sequence SOL packet - packet is dropped");
Tom Josephfbcac2e2017-03-14 18:15:07 +0530102 return;
103 }
104
105 /*
106 * Check if the expected ACK/NACK sequence number is same as the
107 * ACK/NACK sequence number in the packet. If packet ACK/NACK sequence
108 * number is 0, then it is an informational packet. No request packet being
109 * ACK'd or NACK'd.
110 */
111 if (ackSeqNum && (ackSeqNum != seqNums.get(false)))
112 {
George Liu7b7f25f2022-07-04 17:07:32 +0800113 lg2::info("Out of sequence ack number - SOL packet is dropped");
Tom Josephfbcac2e2017-03-14 18:15:07 +0530114 return;
115 }
116
117 /*
118 * Retry the SOL payload packet in the following conditions:
119 *
120 * a) NACK in Operation/Status
121 * b) Accepted Character Count does not match with the sent out SOL payload
122 * c) Non-zero Packet ACK/NACK Sequence Number
123 */
124 if (status || ((count != expectedCharCount) && ackSeqNum))
125 {
126 resendPayload(noClear);
Vernon Mauery6f353e82018-11-09 08:43:24 -0800127 enableRetryTimer(false);
128 enableRetryTimer(true);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530129 return;
130 }
131 /*
132 * Clear the sent data once the acknowledgment sequence number matches
133 * and the expected character count matches.
134 */
135 else if ((count == expectedCharCount) && ackSeqNum)
136 {
137 // Clear the Host Console Buffer
Vernon Mauery2085ae02021-06-10 11:51:00 -0700138 sol::Manager::get().dataBuffer.erase(count);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530139
140 // Once it is acknowledged stop the retry interval timer
Vernon Mauery6f353e82018-11-09 08:43:24 -0800141 enableRetryTimer(false);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530142
143 retryCounter = maxRetryCount;
144 expectedCharCount = 0;
145 payloadCache.clear();
146 }
147
148 // Write character data to the Host Console
149 if (!input.empty() && seqNum)
150 {
Vernon Mauery2085ae02021-06-10 11:51:00 -0700151 auto rc = sol::Manager::get().writeConsoleSocket(input);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530152 if (rc)
153 {
George Liu7b7f25f2022-07-04 17:07:32 +0800154 lg2::error("Writing to console socket descriptor failed: {ERROR}",
155 "ERROR", strerror(errno));
Tom Josephfbcac2e2017-03-14 18:15:07 +0530156 ack = true;
157 }
158 else
159 {
160 respAckSeqNum = seqNum;
161 ack = false;
162 acceptedCount = input.size();
163 }
164 }
Tom Joseph694fc0c2017-08-21 11:47:25 +0530165 /*
166 * SOL payload with no character data and valid sequence number can be used
167 * as method to keep the SOL session active.
168 */
169 else if (input.empty() && seqNum)
170 {
171 respAckSeqNum = seqNum;
172 }
Tom Josephfbcac2e2017-03-14 18:15:07 +0530173
174 if (seqNum != 0)
175 {
176 seqNums.incInboundSeqNum();
177 prepareResponse(respAckSeqNum, acceptedCount, ack);
178 }
179 else
180 {
Vernon Mauery6f353e82018-11-09 08:43:24 -0800181 enableAccumulateTimer(true);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530182 }
183}
184
Tom Joseph75e15db2017-03-14 18:16:22 +0530185void Context::prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack)
186{
Vernon Mauery2085ae02021-06-10 11:51:00 -0700187 auto bufferSize = sol::Manager::get().dataBuffer.size();
Tom Joseph75e15db2017-03-14 18:16:22 +0530188
189 /* Sent a ACK only response */
190 if (payloadCache.size() != 0 || (bufferSize < sendThreshold))
191 {
Vernon Mauery6f353e82018-11-09 08:43:24 -0800192 enableAccumulateTimer(true);
Tom Joseph75e15db2017-03-14 18:16:22 +0530193
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800194 std::vector<uint8_t> outPayload(sizeof(Payload));
Tom Joseph75e15db2017-03-14 18:16:22 +0530195 auto response = reinterpret_cast<Payload*>(outPayload.data());
196 response->packetSeqNum = 0;
197 response->packetAckSeqNum = ackSeqNum;
198 response->acceptedCharCount = count;
199 response->outOperation.ack = ack;
200 sendPayload(outPayload);
201 return;
202 }
203
204 auto readSize = std::min(bufferSize, MAX_PAYLOAD_SIZE);
205 payloadCache.resize(sizeof(Payload) + readSize);
206 auto response = reinterpret_cast<Payload*>(payloadCache.data());
207 response->packetAckSeqNum = ackSeqNum;
208 response->acceptedCharCount = count;
209 response->outOperation.ack = ack;
210 response->packetSeqNum = seqNums.incOutboundSeqNum();
211
Vernon Mauery2085ae02021-06-10 11:51:00 -0700212 auto handle = sol::Manager::get().dataBuffer.read();
Tom Joseph75e15db2017-03-14 18:16:22 +0530213 std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
214 expectedCharCount = readSize;
215
Vernon Mauery6f353e82018-11-09 08:43:24 -0800216 enableRetryTimer(true);
217 enableAccumulateTimer(false);
Tom Joseph75e15db2017-03-14 18:16:22 +0530218
219 sendPayload(payloadCache);
220}
221
Tom Joseph73063142017-03-14 18:20:20 +0530222int Context::sendOutboundPayload()
223{
224 if (payloadCache.size() != 0)
225 {
Vernon Mauery6f353e82018-11-09 08:43:24 -0800226 enableAccumulateTimer(true);
Tom Joseph73063142017-03-14 18:20:20 +0530227 return -1;
228 }
229
Vernon Mauery2085ae02021-06-10 11:51:00 -0700230 auto bufferSize = sol::Manager::get().dataBuffer.size();
Tom Joseph73063142017-03-14 18:20:20 +0530231 auto readSize = std::min(bufferSize, MAX_PAYLOAD_SIZE);
232
233 payloadCache.resize(sizeof(Payload) + readSize);
234 auto response = reinterpret_cast<Payload*>(payloadCache.data());
235 response->packetAckSeqNum = 0;
236 response->acceptedCharCount = 0;
237 response->outOperation.ack = false;
238 response->packetSeqNum = seqNums.incOutboundSeqNum();
239
Vernon Mauery2085ae02021-06-10 11:51:00 -0700240 auto handle = sol::Manager::get().dataBuffer.read();
Tom Joseph73063142017-03-14 18:20:20 +0530241 std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
242 expectedCharCount = readSize;
243
Vernon Mauery6f353e82018-11-09 08:43:24 -0800244 enableRetryTimer(true);
245 enableAccumulateTimer(false);
Tom Joseph73063142017-03-14 18:20:20 +0530246
247 sendPayload(payloadCache);
248
249 return 0;
250}
251
Tom Joseph75e15db2017-03-14 18:16:22 +0530252void Context::resendPayload(bool clear)
Tom Josephfbcac2e2017-03-14 18:15:07 +0530253{
Tom Joseph2fd466f2017-03-30 08:16:47 +0530254 sendPayload(payloadCache);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530255
Vernon Mauery9e801a22018-10-12 13:20:49 -0700256 if (clear)
Tom Joseph2fd466f2017-03-30 08:16:47 +0530257 {
258 payloadCache.clear();
259 expectedCharCount = 0;
Vernon Mauery2085ae02021-06-10 11:51:00 -0700260 sol::Manager::get().dataBuffer.erase(expectedCharCount);
Tom Joseph2fd466f2017-03-30 08:16:47 +0530261 }
Tom Josephfbcac2e2017-03-14 18:15:07 +0530262}
263
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800264void Context::sendPayload(const std::vector<uint8_t>& out) const
Tom Josephfbcac2e2017-03-14 18:15:07 +0530265{
Tom Joseph22596f22017-03-31 10:52:27 +0530266 message::Handler msgHandler(session->channelPtr, sessionID);
267
268 msgHandler.sendSOLPayload(out);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530269}
270
Vernon Mauery6f353e82018-11-09 08:43:24 -0800271void Context::charAccTimerHandler()
272{
Vernon Mauery2085ae02021-06-10 11:51:00 -0700273 auto bufferSize = sol::Manager::get().dataBuffer.size();
Vernon Mauery6f353e82018-11-09 08:43:24 -0800274
275 try
276 {
277 if (bufferSize > 0)
278 {
279 int rc = sendOutboundPayload();
280 if (rc == 0)
281 {
282 return;
283 }
284 }
285 enableAccumulateTimer(true);
286 }
Patrick Williams12d199b2021-10-06 12:36:48 -0500287 catch (const std::exception& e)
Vernon Mauery6f353e82018-11-09 08:43:24 -0800288 {
George Liu7b7f25f2022-07-04 17:07:32 +0800289 lg2::error("Failed to call the sendOutboundPayload method: {ERROR}",
290 "ERROR", e);
Vernon Mauery6f353e82018-11-09 08:43:24 -0800291 }
292}
293
294void Context::retryTimerHandler()
295{
296 try
297 {
298 if (retryCounter)
299 {
300 --retryCounter;
301 enableRetryTimer(true);
302 resendPayload(sol::Context::noClear);
303 }
304 else
305 {
306 retryCounter = maxRetryCount;
307 resendPayload(sol::Context::clear);
308 enableRetryTimer(false);
309 enableAccumulateTimer(true);
310 }
311 }
Patrick Williams12d199b2021-10-06 12:36:48 -0500312 catch (const std::exception& e)
Vernon Mauery6f353e82018-11-09 08:43:24 -0800313 {
George Liu7b7f25f2022-07-04 17:07:32 +0800314 lg2::error("Failed to retry timer: {ERROR}", "ERROR", e);
Vernon Mauery6f353e82018-11-09 08:43:24 -0800315 }
316}
Tom Josephfbcac2e2017-03-14 18:15:07 +0530317} // namespace sol