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