blob: 7329ed297e9e873eae19b6d20c5e826cc718e121 [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"
4#include "sd_event_loop.hpp"
Tom Josephfbcac2e2017-03-14 18:15:07 +05305#include "sol_manager.hpp"
6
Vernon Mauery9e801a22018-10-12 13:20:49 -07007#include <phosphor-logging/log.hpp>
8
Tom Josephfbcac2e2017-03-14 18:15:07 +05309namespace sol
10{
11
12using namespace phosphor::logging;
13
Vernon Mauery9e801a22018-10-12 13:20:49 -070014void Context::processInboundPayload(uint8_t seqNum, uint8_t ackSeqNum,
15 uint8_t count, bool status,
Vernon Mauery70fd29c2017-11-30 13:11:43 -080016 const std::vector<uint8_t>& input)
Tom Josephfbcac2e2017-03-14 18:15:07 +053017{
18 uint8_t respAckSeqNum = 0;
19 uint8_t acceptedCount = 0;
20 auto ack = false;
21
22 /*
23 * Check if the Inbound sequence number is same as the expected one.
24 * If the Packet Sequence Number is 0, it is an ACK-Only packet. Multiple
25 * outstanding sequence numbers are not supported in this version of the SOL
26 * specification. Retried packets use the same sequence number as the first
27 * packet.
28 */
Vernon Mauery9e801a22018-10-12 13:20:49 -070029 if (seqNum && (seqNum != seqNums.get(true)))
Tom Josephfbcac2e2017-03-14 18:15:07 +053030 {
31 log<level::INFO>("Out of sequence SOL packet - packet is dropped");
32 return;
33 }
34
35 /*
36 * Check if the expected ACK/NACK sequence number is same as the
37 * ACK/NACK sequence number in the packet. If packet ACK/NACK sequence
38 * number is 0, then it is an informational packet. No request packet being
39 * ACK'd or NACK'd.
40 */
41 if (ackSeqNum && (ackSeqNum != seqNums.get(false)))
42 {
43 log<level::INFO>("Out of sequence ack number - SOL packet is dropped");
44 return;
45 }
46
47 /*
48 * Retry the SOL payload packet in the following conditions:
49 *
50 * a) NACK in Operation/Status
51 * b) Accepted Character Count does not match with the sent out SOL payload
52 * c) Non-zero Packet ACK/NACK Sequence Number
53 */
54 if (status || ((count != expectedCharCount) && ackSeqNum))
55 {
56 resendPayload(noClear);
Vernon Mauery9e801a22018-10-12 13:20:49 -070057 std::get<eventloop::EventLoop&>(singletonPool)
58 .switchTimer(payloadInstance, eventloop::Timers::RETRY, false);
59 std::get<eventloop::EventLoop&>(singletonPool)
60 .switchTimer(payloadInstance, eventloop::Timers::RETRY, true);
Tom Josephfbcac2e2017-03-14 18:15:07 +053061 return;
62 }
63 /*
64 * Clear the sent data once the acknowledgment sequence number matches
65 * and the expected character count matches.
66 */
67 else if ((count == expectedCharCount) && ackSeqNum)
68 {
69 // Clear the Host Console Buffer
70 std::get<sol::Manager&>(singletonPool).dataBuffer.erase(count);
71
72 // Once it is acknowledged stop the retry interval timer
Vernon Mauery9e801a22018-10-12 13:20:49 -070073 std::get<eventloop::EventLoop&>(singletonPool)
74 .switchTimer(payloadInstance, eventloop::Timers::RETRY, false);
Tom Josephfbcac2e2017-03-14 18:15:07 +053075
76 retryCounter = maxRetryCount;
77 expectedCharCount = 0;
78 payloadCache.clear();
79 }
80
81 // Write character data to the Host Console
82 if (!input.empty() && seqNum)
83 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070084 auto rc =
85 std::get<sol::Manager&>(singletonPool).writeConsoleSocket(input);
Tom Josephfbcac2e2017-03-14 18:15:07 +053086 if (rc)
87 {
88 log<level::ERR>("Writing to console socket descriptor failed");
89 ack = true;
90 }
91 else
92 {
93 respAckSeqNum = seqNum;
94 ack = false;
95 acceptedCount = input.size();
96 }
97 }
Tom Joseph694fc0c2017-08-21 11:47:25 +053098 /*
99 * SOL payload with no character data and valid sequence number can be used
100 * as method to keep the SOL session active.
101 */
102 else if (input.empty() && seqNum)
103 {
104 respAckSeqNum = seqNum;
105 }
Tom Josephfbcac2e2017-03-14 18:15:07 +0530106
107 if (seqNum != 0)
108 {
109 seqNums.incInboundSeqNum();
110 prepareResponse(respAckSeqNum, acceptedCount, ack);
111 }
112 else
113 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700114 std::get<eventloop::EventLoop&>(singletonPool)
115 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530116 }
117}
118
Tom Joseph75e15db2017-03-14 18:16:22 +0530119void Context::prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack)
120{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700121 auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.size();
Tom Joseph75e15db2017-03-14 18:16:22 +0530122
123 /* Sent a ACK only response */
124 if (payloadCache.size() != 0 || (bufferSize < sendThreshold))
125 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700126 std::get<eventloop::EventLoop&>(singletonPool)
127 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true);
Tom Joseph75e15db2017-03-14 18:16:22 +0530128
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800129 std::vector<uint8_t> outPayload(sizeof(Payload));
Tom Joseph75e15db2017-03-14 18:16:22 +0530130 auto response = reinterpret_cast<Payload*>(outPayload.data());
131 response->packetSeqNum = 0;
132 response->packetAckSeqNum = ackSeqNum;
133 response->acceptedCharCount = count;
134 response->outOperation.ack = ack;
135 sendPayload(outPayload);
136 return;
137 }
138
139 auto readSize = std::min(bufferSize, MAX_PAYLOAD_SIZE);
140 payloadCache.resize(sizeof(Payload) + readSize);
141 auto response = reinterpret_cast<Payload*>(payloadCache.data());
142 response->packetAckSeqNum = ackSeqNum;
143 response->acceptedCharCount = count;
144 response->outOperation.ack = ack;
145 response->packetSeqNum = seqNums.incOutboundSeqNum();
146
Tom Joseph75e15db2017-03-14 18:16:22 +0530147 auto handle = std::get<sol::Manager&>(singletonPool).dataBuffer.read();
148 std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
149 expectedCharCount = readSize;
150
Vernon Mauery9e801a22018-10-12 13:20:49 -0700151 std::get<eventloop::EventLoop&>(singletonPool)
152 .switchTimer(payloadInstance, eventloop::Timers::RETRY, true);
153 std::get<eventloop::EventLoop&>(singletonPool)
154 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, false);
Tom Joseph75e15db2017-03-14 18:16:22 +0530155
156 sendPayload(payloadCache);
157}
158
Tom Joseph73063142017-03-14 18:20:20 +0530159int Context::sendOutboundPayload()
160{
161 if (payloadCache.size() != 0)
162 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700163 std::get<eventloop::EventLoop&>(singletonPool)
164 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true);
Tom Joseph73063142017-03-14 18:20:20 +0530165 return -1;
166 }
167
168 auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.size();
169 auto readSize = std::min(bufferSize, MAX_PAYLOAD_SIZE);
170
171 payloadCache.resize(sizeof(Payload) + readSize);
172 auto response = reinterpret_cast<Payload*>(payloadCache.data());
173 response->packetAckSeqNum = 0;
174 response->acceptedCharCount = 0;
175 response->outOperation.ack = false;
176 response->packetSeqNum = seqNums.incOutboundSeqNum();
177
178 auto handle = std::get<sol::Manager&>(singletonPool).dataBuffer.read();
179 std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload));
180 expectedCharCount = readSize;
181
Vernon Mauery9e801a22018-10-12 13:20:49 -0700182 std::get<eventloop::EventLoop&>(singletonPool)
183 .switchTimer(payloadInstance, eventloop::Timers::RETRY, true);
184 std::get<eventloop::EventLoop&>(singletonPool)
185 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, false);
Tom Joseph73063142017-03-14 18:20:20 +0530186
187 sendPayload(payloadCache);
188
189 return 0;
190}
191
Tom Joseph75e15db2017-03-14 18:16:22 +0530192void Context::resendPayload(bool clear)
Tom Josephfbcac2e2017-03-14 18:15:07 +0530193{
Tom Joseph2fd466f2017-03-30 08:16:47 +0530194 sendPayload(payloadCache);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530195
Vernon Mauery9e801a22018-10-12 13:20:49 -0700196 if (clear)
Tom Joseph2fd466f2017-03-30 08:16:47 +0530197 {
198 payloadCache.clear();
199 expectedCharCount = 0;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700200 std::get<sol::Manager&>(singletonPool)
201 .dataBuffer.erase(expectedCharCount);
Tom Joseph2fd466f2017-03-30 08:16:47 +0530202 }
Tom Josephfbcac2e2017-03-14 18:15:07 +0530203}
204
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800205void Context::sendPayload(const std::vector<uint8_t>& out) const
Tom Josephfbcac2e2017-03-14 18:15:07 +0530206{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700207 auto session =
208 (std::get<session::Manager&>(singletonPool).getSession(sessionID))
209 .lock();
Tom Josephfbcac2e2017-03-14 18:15:07 +0530210
Tom Joseph22596f22017-03-31 10:52:27 +0530211 message::Handler msgHandler(session->channelPtr, sessionID);
212
213 msgHandler.sendSOLPayload(out);
Tom Josephfbcac2e2017-03-14 18:15:07 +0530214}
215
216} // namespace sol