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 <memory>
9 
10 namespace message
11 {
12 
13 class Handler : public std::enable_shared_from_this<Handler>
14 {
15   public:
16     /**
17      * @brief Create a Handler intended for a full transaction
18      *        that may or may not use asynchronous responses
19      */
20     Handler(std::shared_ptr<udpsocket::Channel> channel,
21             std::shared_ptr<boost::asio::io_context> io,
22             uint32_t sessionID = message::Message::MESSAGE_INVALID_SESSION_ID) :
23         sessionID(sessionID),
24         channel(channel), io(io)
25     {
26     }
27 
28     /**
29      * @brief Create a Handler intended for a send only (SOL)
30      */
31     Handler(std::shared_ptr<udpsocket::Channel> channel,
32             uint32_t sessionID = message::Message::MESSAGE_INVALID_SESSION_ID) :
33         sessionID(sessionID),
34         channel(channel), io(nullptr)
35     {
36     }
37 
38     ~Handler();
39     Handler() = delete;
40     Handler(const Handler&) = delete;
41     Handler& operator=(const Handler&) = delete;
42     Handler(Handler&&) = delete;
43     Handler& operator=(Handler&&) = delete;
44 
45     /**
46      * @brief Process the incoming IPMI message
47      *
48      * The incoming payload is read from the channel. If a message is read, it
49      * is passed onto executeCommand, which may or may not execute the command
50      * asynchrounously. If the command is executed asynchrounously, a shared_ptr
51      * of self via shared_from_this will keep this object alive until the
52      * response is ready. Then on the destructor, the response will be sent.
53      */
54     void processIncoming();
55 
56     /** @brief Set socket channel in session object */
57     void setChannelInSession() const;
58 
59     /** @brief Send the SOL payload
60      *
61      *  The SOL payload is flattened and sent out on the socket
62      *
63      *  @param[in] input - SOL Payload
64      */
65     void sendSOLPayload(const std::vector<uint8_t>& input);
66 
67     /** @brief Send the unsolicited IPMI payload to the remote console.
68      *
69      *  This is used by commands like SOL activating, in which case the BMC
70      *  has to notify the remote console that a SOL payload is activating
71      *  on another channel.
72      *
73      *  @param[in] netfn - Net function.
74      *  @param[in] cmd - Command.
75      *  @param[in] input - Command request data.
76      */
77     void sendUnsolicitedIPMIPayload(uint8_t netfn, uint8_t cmd,
78                                     const std::vector<uint8_t>& input);
79 
80     // BMC Session ID for the Channel
81     session::SessionID sessionID;
82 
83     /** @brief response to send back */
84     std::optional<std::vector<uint8_t>> outPayload;
85 
86   private:
87     /**
88      * @brief Receive the IPMI packet
89      *
90      * Read the data on the socket, get the parser based on the Session
91      * header type and flatten the payload and generate the IPMI message
92      */
93     bool receive();
94 
95     /**
96      * @brief Get Session data from the IPMI packet
97      *
98      */
99     void updSessionData(std::shared_ptr<Message>& inMessage);
100 
101     /**
102      * @brief Process the incoming IPMI message
103      *
104      * The incoming message payload is handled and the command handler for
105      * the Network function and Command is executed and the response message
106      * is returned
107      */
108     void executeCommand();
109 
110     /** @brief Send the outgoing message
111      *
112      *  The payload in the outgoing message is flattened and sent out on the
113      *  socket
114      *
115      *  @param[in] outMessage - Outgoing Message
116      */
117     void send(std::shared_ptr<Message> outMessage);
118 
119 #ifdef RMCP_PING
120     /** @brief Send the outgoing ASF message
121      *
122      *  The outgoing ASF message contains only ASF message header
123      *  which is flattened and sent out on the socket
124      */
125     void sendASF();
126 #endif // RMCP_PING
127 
128     /** @brief Write the packet to the socket
129      *
130      *  @param[in] packet - Outgoing packet
131      */
132     void writeData(const std::vector<uint8_t>& packet);
133 
134     /** @brief Socket channel for communicating with the remote client.*/
135     std::shared_ptr<udpsocket::Channel> channel;
136 
137     /** @brief asio io context to run asynchrounously */
138     std::shared_ptr<boost::asio::io_context> io;
139 
140     parser::SessionHeader sessionHeader = parser::SessionHeader::IPMI20;
141 
142     std::shared_ptr<message::Message> inMessage;
143 };
144 
145 } // namespace message
146