blob: d5eaf819e788fe0f82bd2f93cd6addadd2164806 [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 Tanous002d39b2022-05-31 08:59:27 -070048 doingWrite = false;
49 inputBuffer.erase(0, bytesWritten);
Ed Tanous2daf6722018-08-23 11:27:23 -070050
Ed Tanous002d39b2022-05-31 08:59:27 -070051 if (ec == boost::asio::error::eof)
52 {
53 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070054 {
Ed Tanous002d39b2022-05-31 08:59:27 -070055 session->close("Error in reading to host port");
Ed Tanous2daf6722018-08-23 11:27:23 -070056 }
Ed Tanous002d39b2022-05-31 08:59:27 -070057 return;
58 }
59 if (ec)
60 {
61 BMCWEB_LOG_ERROR << "Error in host serial write " << ec;
62 return;
63 }
64 doWrite();
Ed Tanous2daf6722018-08-23 11:27:23 -070065 });
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) {
Ed Tanous002d39b2022-05-31 08:59:27 -070080 BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
81 if (ec)
82 {
83 BMCWEB_LOG_ERROR << "Couldn't read from host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070084 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070085 {
Ed Tanous002d39b2022-05-31 08:59:27 -070086 session->close("Error in connecting to host port");
Ed Tanous2daf6722018-08-23 11:27:23 -070087 }
Ed Tanous002d39b2022-05-31 08:59:27 -070088 return;
89 }
90 std::string_view payload(outputBuffer.data(), bytesRead);
91 for (crow::websocket::Connection* session : sessions)
92 {
93 session->sendBinary(payload);
94 }
95 doRead();
Ed Tanous2daf6722018-08-23 11:27:23 -070096 });
97}
98
Ed Tanous23a21a12020-07-25 04:45:05 +000099inline void connectHandler(const boost::system::error_code& ec)
Ed Tanous2daf6722018-08-23 11:27:23 -0700100{
101 if (ec)
102 {
103 BMCWEB_LOG_ERROR << "Couldn't connect to host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -0700104 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -0700105 {
106 session->close("Error in connecting to host port");
107 }
108 return;
109 }
110
111 doWrite();
112 doRead();
113}
114
Ed Tanous23a21a12020-07-25 04:45:05 +0000115inline void requestRoutes(App& app)
Ed Tanous2daf6722018-08-23 11:27:23 -0700116{
117 BMCWEB_ROUTE(app, "/console0")
Ed Tanous432a8902021-06-14 15:28:56 -0700118 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous2daf6722018-08-23 11:27:23 -0700119 .websocket()
Ed Tanous002d39b2022-05-31 08:59:27 -0700120 .onopen(
121 [](crow::websocket::Connection& conn) {
122 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
Ed Tanous2daf6722018-08-23 11:27:23 -0700123
Ed Tanous002d39b2022-05-31 08:59:27 -0700124 sessions.insert(&conn);
125 if (hostSocket == nullptr)
126 {
127 const std::string consoleName("\0obmc-console", 13);
128 boost::asio::local::stream_protocol::endpoint ep(consoleName);
Ed Tanous2daf6722018-08-23 11:27:23 -0700129
Ed Tanous002d39b2022-05-31 08:59:27 -0700130 hostSocket =
131 std::make_unique<boost::asio::local::stream_protocol::socket>(
Ed Tanous2c70f802020-09-28 14:29:23 -0700132 conn.getIoContext());
Ed Tanous002d39b2022-05-31 08:59:27 -0700133 hostSocket->async_connect(ep, connectHandler);
134 }
Ed Tanous2daf6722018-08-23 11:27:23 -0700135 })
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