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