1 #include "sol_context.hpp" 2 3 #include "main.hpp" 4 #include "sd_event_loop.hpp" 5 #include "sol_manager.hpp" 6 7 #include <phosphor-logging/log.hpp> 8 9 namespace sol 10 { 11 12 using namespace phosphor::logging; 13 14 void Context::processInboundPayload(uint8_t seqNum, uint8_t ackSeqNum, 15 uint8_t count, bool status, 16 const std::vector<uint8_t>& input) 17 { 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 */ 29 if (seqNum && (seqNum != seqNums.get(true))) 30 { 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); 57 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); 61 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 73 std::get<eventloop::EventLoop&>(singletonPool) 74 .switchTimer(payloadInstance, eventloop::Timers::RETRY, false); 75 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 { 84 auto rc = 85 std::get<sol::Manager&>(singletonPool).writeConsoleSocket(input); 86 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 } 98 /* 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 } 106 107 if (seqNum != 0) 108 { 109 seqNums.incInboundSeqNum(); 110 prepareResponse(respAckSeqNum, acceptedCount, ack); 111 } 112 else 113 { 114 std::get<eventloop::EventLoop&>(singletonPool) 115 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true); 116 } 117 } 118 119 void Context::prepareResponse(uint8_t ackSeqNum, uint8_t count, bool ack) 120 { 121 auto bufferSize = std::get<sol::Manager&>(singletonPool).dataBuffer.size(); 122 123 /* Sent a ACK only response */ 124 if (payloadCache.size() != 0 || (bufferSize < sendThreshold)) 125 { 126 std::get<eventloop::EventLoop&>(singletonPool) 127 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true); 128 129 std::vector<uint8_t> outPayload(sizeof(Payload)); 130 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 147 auto handle = std::get<sol::Manager&>(singletonPool).dataBuffer.read(); 148 std::copy_n(handle, readSize, payloadCache.data() + sizeof(Payload)); 149 expectedCharCount = readSize; 150 151 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); 155 156 sendPayload(payloadCache); 157 } 158 159 int Context::sendOutboundPayload() 160 { 161 if (payloadCache.size() != 0) 162 { 163 std::get<eventloop::EventLoop&>(singletonPool) 164 .switchTimer(payloadInstance, eventloop::Timers::ACCUMULATE, true); 165 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 182 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); 186 187 sendPayload(payloadCache); 188 189 return 0; 190 } 191 192 void Context::resendPayload(bool clear) 193 { 194 sendPayload(payloadCache); 195 196 if (clear) 197 { 198 payloadCache.clear(); 199 expectedCharCount = 0; 200 std::get<sol::Manager&>(singletonPool) 201 .dataBuffer.erase(expectedCharCount); 202 } 203 } 204 205 void Context::sendPayload(const std::vector<uint8_t>& out) const 206 { 207 auto session = 208 std::get<session::Manager&>(singletonPool).getSession(sessionID); 209 210 message::Handler msgHandler(session->channelPtr, sessionID); 211 212 msgHandler.sendSOLPayload(out); 213 } 214 215 } // namespace sol 216