1 #pragma once
2 
3 #include "message.hpp"
4 #include "message_parsers.hpp"
5 #include "session.hpp"
6 #include "sol/console_buffer.hpp"
7 
8 #include <iostream>
9 #include <memory>
10 #include <numeric>
11 
12 namespace message
13 {
14 
15 class Handler
16 {
17   public:
18     explicit Handler(
19         std::shared_ptr<udpsocket::Channel> channel,
20         uint32_t sessionID = message::Message::MESSAGE_INVALID_SESSION_ID) :
21         sessionID(sessionID),
22         channel(channel)
23     {
24     }
25 
26     Handler() = delete;
27     ~Handler() = default;
28     Handler(const Handler&) = default;
29     Handler& operator=(const Handler&) = default;
30     Handler(Handler&&) = default;
31     Handler& operator=(Handler&&) = default;
32 
33     /**
34      * @brief Receive the IPMI packet
35      *
36      * Read the data on the socket, get the parser based on the Session
37      * header type and flatten the payload and generate the IPMI message
38      *
39      * @return IPMI Message on success and nullptr on failure
40      *
41      */
42     std::shared_ptr<Message> receive();
43 
44     /**
45      * @brief Process the incoming IPMI message
46      *
47      * The incoming message payload is handled and the command handler for
48      * the Network function and Command is executed and the response message
49      * is returned
50      *
51      * @param[in] inMessage - Incoming Message
52      *
53      * @return Outgoing message on success and nullptr on failure
54      */
55     std::shared_ptr<Message> executeCommand(std::shared_ptr<Message> inMessage);
56 
57     /** @brief Send the outgoing message
58      *
59      *  The payload in the outgoing message is flattened and sent out on the
60      *  socket
61      *
62      *  @param[in] outMessage - Outgoing Message
63      */
64     void send(std::shared_ptr<Message> outMessage);
65 
66     /** @brief Set socket channel in session object */
67     void setChannelInSession() const;
68 
69     /** @brief Send the SOL payload
70      *
71      *  The SOL payload is flattened and sent out on the socket
72      *
73      *  @param[in] input - SOL Payload
74      */
75     void sendSOLPayload(const std::vector<uint8_t>& input);
76 
77     /** @brief Send the unsolicited IPMI payload to the remote console.
78      *
79      *  This is used by commands like SOL activating, in which case the BMC
80      *  has to notify the remote console that a SOL payload is activating
81      *  on another channel.
82      *
83      *  @param[in] netfn - Net function.
84      *  @param[in] cmd - Command.
85      *  @param[in] input - Command request data.
86      */
87     void sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
88                                     const std::vector<uint8_t>& input);
89 
90     // BMC Session ID for the Channel
91     session::SessionID sessionID;
92 
93   private:
94     /** @brief Socket channel for communicating with the remote client.*/
95     std::shared_ptr<udpsocket::Channel> channel;
96 
97     parser::SessionHeader sessionHeader = parser::SessionHeader::IPMI20;
98 
99     /**
100      * @brief Create the response IPMI message
101      *
102      * The IPMI outgoing message is constructed out of payload and the
103      * corresponding fields are populated.For the payload type IPMI, the
104      * LAN message header and trailer are added.
105      *
106      * @tparam[in] T - Outgoing message payload type
107      * @param[in] output - Payload for outgoing message
108      * @param[in] inMessage - Incoming IPMI message
109      *
110      * @return Outgoing message on success and nullptr on failure
111      */
112     template <PayloadType T>
113     std::shared_ptr<Message> createResponse(std::vector<uint8_t>& output,
114                                             std::shared_ptr<Message> inMessage)
115     {
116         auto outMessage = std::make_shared<Message>();
117         outMessage->payloadType = T;
118         outMessage->payload = output;
119         return outMessage;
120     }
121 
122     /**
123      * @brief Extract the command from the IPMI payload
124      *
125      * @param[in] message - Incoming message
126      *
127      * @return Command ID in the incoming message
128      */
129     uint32_t getCommand(std::shared_ptr<Message> message);
130 
131     /**
132      * @brief Calculate 8 bit 2's complement checksum
133      *
134      * Initialize checksum to 0. For each byte, checksum = (checksum + byte)
135      * modulo 256. Then checksum = - checksum. When the checksum and the
136      * bytes are added together, modulo 256, the result should be 0.
137      */
138     uint8_t crc8bit(const uint8_t* ptr, const size_t len)
139     {
140         return (0x100 - std::accumulate(ptr, ptr + len, 0));
141     }
142 };
143 
144 } // namespace message
145