blob: 3ab13ee4c2e10427c5d11d3d60b20025648fe6cc [file] [log] [blame]
Ed Tanous2daf6722018-08-23 11:27:23 -07001#pragma once
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08002#include "app.hpp"
3#include "async_resp.hpp"
4
Ed Tanous2daf6722018-08-23 11:27:23 -07005#include <sys/socket.h>
6
Ed Tanousd4d77e32020-08-18 00:07:28 -07007#include <boost/asio/local/stream_protocol.hpp>
Ed Tanous2daf6722018-08-23 11:27:23 -07008#include <boost/container/flat_set.hpp>
Ed Tanous04e438c2020-10-03 08:06:26 -07009#include <websocket.hpp>
Ed Tanous2daf6722018-08-23 11:27:23 -070010
11namespace crow
12{
13namespace obmc_console
14{
15
Ed Tanouscf9e4172022-12-21 09:30:16 -080016// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2c70f802020-09-28 14:29:23 -070017static std::unique_ptr<boost::asio::local::stream_protocol::socket> hostSocket;
Ed Tanous2daf6722018-08-23 11:27:23 -070018
Ed Tanouscf9e4172022-12-21 09:30:16 -080019// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070020static std::array<char, 4096> outputBuffer;
Ed Tanouscf9e4172022-12-21 09:30:16 -080021// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070022static std::string inputBuffer;
23
Ed Tanouscf9e4172022-12-21 09:30:16 -080024// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070025static boost::container::flat_set<crow::websocket::Connection*> sessions;
26
Ed Tanouscf9e4172022-12-21 09:30:16 -080027// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Ed Tanous2daf6722018-08-23 11:27:23 -070028static bool doingWrite = false;
29
Ed Tanous23a21a12020-07-25 04:45:05 +000030inline void doWrite()
Ed Tanous2daf6722018-08-23 11:27:23 -070031{
32 if (doingWrite)
33 {
34 BMCWEB_LOG_DEBUG << "Already writing. Bailing out";
35 return;
36 }
37
38 if (inputBuffer.empty())
39 {
40 BMCWEB_LOG_DEBUG << "Outbuffer empty. Bailing out";
41 return;
42 }
43
AppaRao Puli5238bd32020-11-17 11:03:11 +053044 if (!hostSocket)
45 {
46 BMCWEB_LOG_ERROR << "doWrite(): Socket closed.";
47 return;
48 }
49
Ed Tanous2daf6722018-08-23 11:27:23 -070050 doingWrite = true;
Ed Tanous2c70f802020-09-28 14:29:23 -070051 hostSocket->async_write_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070052 boost::asio::buffer(inputBuffer.data(), inputBuffer.size()),
Ed Tanous81ce6092020-12-17 16:54:55 +000053 [](boost::beast::error_code ec, std::size_t bytesWritten) {
Ed Tanous002d39b2022-05-31 08:59:27 -070054 doingWrite = false;
55 inputBuffer.erase(0, bytesWritten);
Ed Tanous2daf6722018-08-23 11:27:23 -070056
Ed Tanous002d39b2022-05-31 08:59:27 -070057 if (ec == boost::asio::error::eof)
58 {
59 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070060 {
Ed Tanous002d39b2022-05-31 08:59:27 -070061 session->close("Error in reading to host port");
Ed Tanous2daf6722018-08-23 11:27:23 -070062 }
Ed Tanous002d39b2022-05-31 08:59:27 -070063 return;
64 }
65 if (ec)
66 {
67 BMCWEB_LOG_ERROR << "Error in host serial write " << ec;
68 return;
69 }
70 doWrite();
Ed Tanous2daf6722018-08-23 11:27:23 -070071 });
72}
73
Ed Tanous23a21a12020-07-25 04:45:05 +000074inline void doRead()
Ed Tanous2daf6722018-08-23 11:27:23 -070075{
AppaRao Puli5238bd32020-11-17 11:03:11 +053076 if (!hostSocket)
77 {
78 BMCWEB_LOG_ERROR << "doRead(): Socket closed.";
79 return;
80 }
81
Ed Tanous2daf6722018-08-23 11:27:23 -070082 BMCWEB_LOG_DEBUG << "Reading from socket";
Ed Tanous2c70f802020-09-28 14:29:23 -070083 hostSocket->async_read_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070084 boost::asio::buffer(outputBuffer.data(), outputBuffer.size()),
85 [](const boost::system::error_code& ec, std::size_t bytesRead) {
Ed Tanous002d39b2022-05-31 08:59:27 -070086 BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
87 if (ec)
88 {
89 BMCWEB_LOG_ERROR << "Couldn't read from host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070090 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070091 {
Ed Tanous002d39b2022-05-31 08:59:27 -070092 session->close("Error in connecting to host port");
Ed Tanous2daf6722018-08-23 11:27:23 -070093 }
Ed Tanous002d39b2022-05-31 08:59:27 -070094 return;
95 }
96 std::string_view payload(outputBuffer.data(), bytesRead);
97 for (crow::websocket::Connection* session : sessions)
98 {
99 session->sendBinary(payload);
100 }
101 doRead();
Ed Tanous2daf6722018-08-23 11:27:23 -0700102 });
103}
104
Ed Tanous23a21a12020-07-25 04:45:05 +0000105inline void connectHandler(const boost::system::error_code& ec)
Ed Tanous2daf6722018-08-23 11:27:23 -0700106{
107 if (ec)
108 {
109 BMCWEB_LOG_ERROR << "Couldn't connect to host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -0700110 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -0700111 {
112 session->close("Error in connecting to host port");
113 }
114 return;
115 }
116
117 doWrite();
118 doRead();
119}
120
Ed Tanous23a21a12020-07-25 04:45:05 +0000121inline void requestRoutes(App& app)
Ed Tanous2daf6722018-08-23 11:27:23 -0700122{
123 BMCWEB_ROUTE(app, "/console0")
Ed Tanous432a8902021-06-14 15:28:56 -0700124 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous2daf6722018-08-23 11:27:23 -0700125 .websocket()
Ed Tanous002d39b2022-05-31 08:59:27 -0700126 .onopen(
127 [](crow::websocket::Connection& conn) {
128 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
Ed Tanous2daf6722018-08-23 11:27:23 -0700129
Ed Tanous002d39b2022-05-31 08:59:27 -0700130 sessions.insert(&conn);
131 if (hostSocket == nullptr)
132 {
133 const std::string consoleName("\0obmc-console", 13);
134 boost::asio::local::stream_protocol::endpoint ep(consoleName);
Ed Tanous2daf6722018-08-23 11:27:23 -0700135
Ed Tanous002d39b2022-05-31 08:59:27 -0700136 hostSocket =
137 std::make_unique<boost::asio::local::stream_protocol::socket>(
Ed Tanous2c70f802020-09-28 14:29:23 -0700138 conn.getIoContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700139 hostSocket->async_connect(ep, connectHandler);
140 }
Ed Tanous2daf6722018-08-23 11:27:23 -0700141 })
Ed Tanouscb13a392020-07-25 19:02:03 +0000142 .onclose([](crow::websocket::Connection& conn,
143 [[maybe_unused]] const std::string& reason) {
AppaRao Puli5238bd32020-11-17 11:03:11 +0530144 BMCWEB_LOG_INFO << "Closing websocket. Reason: " << reason;
145
Ed Tanouscb13a392020-07-25 19:02:03 +0000146 sessions.erase(&conn);
147 if (sessions.empty())
148 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700149 hostSocket = nullptr;
Ed Tanouscb13a392020-07-25 19:02:03 +0000150 inputBuffer.clear();
151 inputBuffer.shrink_to_fit();
152 }
153 })
154 .onmessage([]([[maybe_unused]] crow::websocket::Connection& conn,
Ed Tanous81ce6092020-12-17 16:54:55 +0000155 const std::string& data, [[maybe_unused]] bool isBinary) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700156 inputBuffer += data;
157 doWrite();
158 });
159}
160} // namespace obmc_console
161} // namespace crow