blob: fc99d41fefc97fbc52b92debf525200ed5507327 [file] [log] [blame]
Ed Tanous2daf6722018-08-23 11:27:23 -07001#pragma once
Ed Tanous2daf6722018-08-23 11:27:23 -07002#include <sys/socket.h>
3
Ed Tanous04e438c2020-10-03 08:06:26 -07004#include <app.hpp>
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +02005#include <async_resp.hpp>
Ed Tanousd4d77e32020-08-18 00:07:28 -07006#include <boost/asio/local/stream_protocol.hpp>
Ed Tanous2daf6722018-08-23 11:27:23 -07007#include <boost/container/flat_set.hpp>
Ed Tanous04e438c2020-10-03 08:06:26 -07008#include <websocket.hpp>
Ed Tanous2daf6722018-08-23 11:27:23 -07009
10namespace crow
11{
12namespace obmc_console
13{
14
Ed Tanous2c70f802020-09-28 14:29:23 -070015static std::unique_ptr<boost::asio::local::stream_protocol::socket> hostSocket;
Ed Tanous2daf6722018-08-23 11:27:23 -070016
17static std::array<char, 4096> outputBuffer;
18static std::string inputBuffer;
19
20static boost::container::flat_set<crow::websocket::Connection*> sessions;
21
22static bool doingWrite = false;
23
Ed Tanous23a21a12020-07-25 04:45:05 +000024inline void doWrite()
Ed Tanous2daf6722018-08-23 11:27:23 -070025{
26 if (doingWrite)
27 {
28 BMCWEB_LOG_DEBUG << "Already writing. Bailing out";
29 return;
30 }
31
32 if (inputBuffer.empty())
33 {
34 BMCWEB_LOG_DEBUG << "Outbuffer empty. Bailing out";
35 return;
36 }
37
AppaRao Puli5238bd32020-11-17 11:03:11 +053038 if (!hostSocket)
39 {
40 BMCWEB_LOG_ERROR << "doWrite(): Socket closed.";
41 return;
42 }
43
Ed Tanous2daf6722018-08-23 11:27:23 -070044 doingWrite = true;
Ed Tanous2c70f802020-09-28 14:29:23 -070045 hostSocket->async_write_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070046 boost::asio::buffer(inputBuffer.data(), inputBuffer.size()),
Ed Tanous81ce6092020-12-17 16:54:55 +000047 [](boost::beast::error_code ec, std::size_t bytesWritten) {
Ed Tanous2daf6722018-08-23 11:27:23 -070048 doingWrite = false;
Ed Tanous81ce6092020-12-17 16:54:55 +000049 inputBuffer.erase(0, bytesWritten);
Ed Tanous2daf6722018-08-23 11:27:23 -070050
51 if (ec == boost::asio::error::eof)
52 {
Ed Tanous271584a2019-07-09 16:24:22 -070053 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070054 {
55 session->close("Error in reading to host port");
56 }
57 return;
58 }
59 if (ec)
60 {
61 BMCWEB_LOG_ERROR << "Error in host serial write " << ec;
62 return;
63 }
64 doWrite();
65 });
66}
67
Ed Tanous23a21a12020-07-25 04:45:05 +000068inline void doRead()
Ed Tanous2daf6722018-08-23 11:27:23 -070069{
AppaRao Puli5238bd32020-11-17 11:03:11 +053070 if (!hostSocket)
71 {
72 BMCWEB_LOG_ERROR << "doRead(): Socket closed.";
73 return;
74 }
75
Ed Tanous2daf6722018-08-23 11:27:23 -070076 BMCWEB_LOG_DEBUG << "Reading from socket";
Ed Tanous2c70f802020-09-28 14:29:23 -070077 hostSocket->async_read_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070078 boost::asio::buffer(outputBuffer.data(), outputBuffer.size()),
79 [](const boost::system::error_code& ec, std::size_t bytesRead) {
80 BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
81 if (ec)
82 {
83 BMCWEB_LOG_ERROR << "Couldn't read from host serial port: "
84 << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070085 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070086 {
87 session->close("Error in connecting to host port");
88 }
89 return;
90 }
Adriana Kobylakae29b8c2019-04-24 11:19:18 -050091 std::string_view payload(outputBuffer.data(), bytesRead);
Ed Tanous271584a2019-07-09 16:24:22 -070092 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070093 {
Cheng C Yang81bfd112019-01-03 14:57:03 +080094 session->sendBinary(payload);
Ed Tanous2daf6722018-08-23 11:27:23 -070095 }
96 doRead();
97 });
98}
99
Ed Tanous23a21a12020-07-25 04:45:05 +0000100inline void connectHandler(const boost::system::error_code& ec)
Ed Tanous2daf6722018-08-23 11:27:23 -0700101{
102 if (ec)
103 {
104 BMCWEB_LOG_ERROR << "Couldn't connect to host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -0700105 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -0700106 {
107 session->close("Error in connecting to host port");
108 }
109 return;
110 }
111
112 doWrite();
113 doRead();
114}
115
Ed Tanous23a21a12020-07-25 04:45:05 +0000116inline void requestRoutes(App& app)
Ed Tanous2daf6722018-08-23 11:27:23 -0700117{
118 BMCWEB_ROUTE(app, "/console0")
Ed Tanous432a8902021-06-14 15:28:56 -0700119 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous2daf6722018-08-23 11:27:23 -0700120 .websocket()
zhanghch0577726382021-10-21 14:07:57 +0800121 .onopen([](crow::websocket::Connection& conn) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700122 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
123
124 sessions.insert(&conn);
Ed Tanous2c70f802020-09-28 14:29:23 -0700125 if (hostSocket == nullptr)
Ed Tanous2daf6722018-08-23 11:27:23 -0700126 {
127 const std::string consoleName("\0obmc-console", 13);
128 boost::asio::local::stream_protocol::endpoint ep(consoleName);
129
Ed Tanous2c70f802020-09-28 14:29:23 -0700130 hostSocket = std::make_unique<
Ed Tanous2daf6722018-08-23 11:27:23 -0700131 boost::asio::local::stream_protocol::socket>(
Ed Tanous2c70f802020-09-28 14:29:23 -0700132 conn.getIoContext());
133 hostSocket->async_connect(ep, connectHandler);
Ed Tanous2daf6722018-08-23 11:27:23 -0700134 }
135 })
Ed Tanouscb13a392020-07-25 19:02:03 +0000136 .onclose([](crow::websocket::Connection& conn,
137 [[maybe_unused]] const std::string& reason) {
AppaRao Puli5238bd32020-11-17 11:03:11 +0530138 BMCWEB_LOG_INFO << "Closing websocket. Reason: " << reason;
139
Ed Tanouscb13a392020-07-25 19:02:03 +0000140 sessions.erase(&conn);
141 if (sessions.empty())
142 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700143 hostSocket = nullptr;
Ed Tanouscb13a392020-07-25 19:02:03 +0000144 inputBuffer.clear();
145 inputBuffer.shrink_to_fit();
146 }
147 })
148 .onmessage([]([[maybe_unused]] crow::websocket::Connection& conn,
Ed Tanous81ce6092020-12-17 16:54:55 +0000149 const std::string& data, [[maybe_unused]] bool isBinary) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700150 inputBuffer += data;
151 doWrite();
152 });
153}
154} // namespace obmc_console
155} // namespace crow