blob: b8f69435fc00d4011d3b39ec8959c49e814ae545 [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 Tanouscf9e4172022-12-21 09:30:16 -080015// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2c70f802020-09-28 14:29:23 -070016static std::unique_ptr<boost::asio::local::stream_protocol::socket> hostSocket;
Ed Tanous2daf6722018-08-23 11:27:23 -070017
Ed Tanouscf9e4172022-12-21 09:30:16 -080018// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070019static std::array<char, 4096> outputBuffer;
Ed Tanouscf9e4172022-12-21 09:30:16 -080020// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070021static std::string inputBuffer;
22
Ed Tanouscf9e4172022-12-21 09:30:16 -080023// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070024static boost::container::flat_set<crow::websocket::Connection*> sessions;
25
Ed Tanouscf9e4172022-12-21 09:30:16 -080026// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070027static bool doingWrite = false;
28
Ed Tanous23a21a12020-07-25 04:45:05 +000029inline void doWrite()
Ed Tanous2daf6722018-08-23 11:27:23 -070030{
31 if (doingWrite)
32 {
33 BMCWEB_LOG_DEBUG << "Already writing. Bailing out";
34 return;
35 }
36
37 if (inputBuffer.empty())
38 {
39 BMCWEB_LOG_DEBUG << "Outbuffer empty. Bailing out";
40 return;
41 }
42
AppaRao Puli5238bd32020-11-17 11:03:11 +053043 if (!hostSocket)
44 {
45 BMCWEB_LOG_ERROR << "doWrite(): Socket closed.";
46 return;
47 }
48
Ed Tanous2daf6722018-08-23 11:27:23 -070049 doingWrite = true;
Ed Tanous2c70f802020-09-28 14:29:23 -070050 hostSocket->async_write_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070051 boost::asio::buffer(inputBuffer.data(), inputBuffer.size()),
Ed Tanous81ce6092020-12-17 16:54:55 +000052 [](boost::beast::error_code ec, std::size_t bytesWritten) {
Ed Tanous002d39b2022-05-31 08:59:27 -070053 doingWrite = false;
54 inputBuffer.erase(0, bytesWritten);
Ed Tanous2daf6722018-08-23 11:27:23 -070055
Ed Tanous002d39b2022-05-31 08:59:27 -070056 if (ec == boost::asio::error::eof)
57 {
58 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070059 {
Ed Tanous002d39b2022-05-31 08:59:27 -070060 session->close("Error in reading to host port");
Ed Tanous2daf6722018-08-23 11:27:23 -070061 }
Ed Tanous002d39b2022-05-31 08:59:27 -070062 return;
63 }
64 if (ec)
65 {
66 BMCWEB_LOG_ERROR << "Error in host serial write " << ec;
67 return;
68 }
69 doWrite();
Ed Tanous2daf6722018-08-23 11:27:23 -070070 });
71}
72
Ed Tanous23a21a12020-07-25 04:45:05 +000073inline void doRead()
Ed Tanous2daf6722018-08-23 11:27:23 -070074{
AppaRao Puli5238bd32020-11-17 11:03:11 +053075 if (!hostSocket)
76 {
77 BMCWEB_LOG_ERROR << "doRead(): Socket closed.";
78 return;
79 }
80
Ed Tanous2daf6722018-08-23 11:27:23 -070081 BMCWEB_LOG_DEBUG << "Reading from socket";
Ed Tanous2c70f802020-09-28 14:29:23 -070082 hostSocket->async_read_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070083 boost::asio::buffer(outputBuffer.data(), outputBuffer.size()),
84 [](const boost::system::error_code& ec, std::size_t bytesRead) {
Ed Tanous002d39b2022-05-31 08:59:27 -070085 BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
86 if (ec)
87 {
88 BMCWEB_LOG_ERROR << "Couldn't read from host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070089 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070090 {
Ed Tanous002d39b2022-05-31 08:59:27 -070091 session->close("Error in connecting to host port");
Ed Tanous2daf6722018-08-23 11:27:23 -070092 }
Ed Tanous002d39b2022-05-31 08:59:27 -070093 return;
94 }
95 std::string_view payload(outputBuffer.data(), bytesRead);
96 for (crow::websocket::Connection* session : sessions)
97 {
98 session->sendBinary(payload);
99 }
100 doRead();
Ed Tanous2daf6722018-08-23 11:27:23 -0700101 });
102}
103
Ed Tanous23a21a12020-07-25 04:45:05 +0000104inline void connectHandler(const boost::system::error_code& ec)
Ed Tanous2daf6722018-08-23 11:27:23 -0700105{
106 if (ec)
107 {
108 BMCWEB_LOG_ERROR << "Couldn't connect to host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -0700109 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -0700110 {
111 session->close("Error in connecting to host port");
112 }
113 return;
114 }
115
116 doWrite();
117 doRead();
118}
119
Ed Tanous23a21a12020-07-25 04:45:05 +0000120inline void requestRoutes(App& app)
Ed Tanous2daf6722018-08-23 11:27:23 -0700121{
122 BMCWEB_ROUTE(app, "/console0")
Ed Tanous432a8902021-06-14 15:28:56 -0700123 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous2daf6722018-08-23 11:27:23 -0700124 .websocket()
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 .onopen(
126 [](crow::websocket::Connection& conn) {
127 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
Ed Tanous2daf6722018-08-23 11:27:23 -0700128
Ed Tanous002d39b2022-05-31 08:59:27 -0700129 sessions.insert(&conn);
130 if (hostSocket == nullptr)
131 {
132 const std::string consoleName("\0obmc-console", 13);
133 boost::asio::local::stream_protocol::endpoint ep(consoleName);
Ed Tanous2daf6722018-08-23 11:27:23 -0700134
Ed Tanous002d39b2022-05-31 08:59:27 -0700135 hostSocket =
136 std::make_unique<boost::asio::local::stream_protocol::socket>(
Ed Tanous2c70f802020-09-28 14:29:23 -0700137 conn.getIoContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700138 hostSocket->async_connect(ep, connectHandler);
139 }
Ed Tanous2daf6722018-08-23 11:27:23 -0700140 })
Ed Tanouscb13a392020-07-25 19:02:03 +0000141 .onclose([](crow::websocket::Connection& conn,
142 [[maybe_unused]] const std::string& reason) {
AppaRao Puli5238bd32020-11-17 11:03:11 +0530143 BMCWEB_LOG_INFO << "Closing websocket. Reason: " << reason;
144
Ed Tanouscb13a392020-07-25 19:02:03 +0000145 sessions.erase(&conn);
146 if (sessions.empty())
147 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700148 hostSocket = nullptr;
Ed Tanouscb13a392020-07-25 19:02:03 +0000149 inputBuffer.clear();
150 inputBuffer.shrink_to_fit();
151 }
152 })
153 .onmessage([]([[maybe_unused]] crow::websocket::Connection& conn,
Ed Tanous81ce6092020-12-17 16:54:55 +0000154 const std::string& data, [[maybe_unused]] bool isBinary) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700155 inputBuffer += data;
156 doWrite();
157 });
158}
159} // namespace obmc_console
160} // namespace crow