blob: 478649ac8d747b504d440e473a8302c2e58dede0 [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_map.hpp>
8#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 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
18static std::array<char, 4096> outputBuffer;
19static std::string inputBuffer;
20
21static boost::container::flat_set<crow::websocket::Connection*> sessions;
22
23static bool doingWrite = false;
24
Ed Tanous23a21a12020-07-25 04:45:05 +000025inline void doWrite()
Ed Tanous2daf6722018-08-23 11:27:23 -070026{
27 if (doingWrite)
28 {
29 BMCWEB_LOG_DEBUG << "Already writing. Bailing out";
30 return;
31 }
32
33 if (inputBuffer.empty())
34 {
35 BMCWEB_LOG_DEBUG << "Outbuffer empty. Bailing out";
36 return;
37 }
38
AppaRao Puli5238bd32020-11-17 11:03:11 +053039 if (!hostSocket)
40 {
41 BMCWEB_LOG_ERROR << "doWrite(): Socket closed.";
42 return;
43 }
44
Ed Tanous2daf6722018-08-23 11:27:23 -070045 doingWrite = true;
Ed Tanous2c70f802020-09-28 14:29:23 -070046 hostSocket->async_write_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070047 boost::asio::buffer(inputBuffer.data(), inputBuffer.size()),
Ed Tanous81ce6092020-12-17 16:54:55 +000048 [](boost::beast::error_code ec, std::size_t bytesWritten) {
Ed Tanous2daf6722018-08-23 11:27:23 -070049 doingWrite = false;
Ed Tanous81ce6092020-12-17 16:54:55 +000050 inputBuffer.erase(0, bytesWritten);
Ed Tanous2daf6722018-08-23 11:27:23 -070051
52 if (ec == boost::asio::error::eof)
53 {
Ed Tanous271584a2019-07-09 16:24:22 -070054 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070055 {
56 session->close("Error in reading to host port");
57 }
58 return;
59 }
60 if (ec)
61 {
62 BMCWEB_LOG_ERROR << "Error in host serial write " << ec;
63 return;
64 }
65 doWrite();
66 });
67}
68
Ed Tanous23a21a12020-07-25 04:45:05 +000069inline void doRead()
Ed Tanous2daf6722018-08-23 11:27:23 -070070{
AppaRao Puli5238bd32020-11-17 11:03:11 +053071 if (!hostSocket)
72 {
73 BMCWEB_LOG_ERROR << "doRead(): Socket closed.";
74 return;
75 }
76
Ed Tanous2daf6722018-08-23 11:27:23 -070077 BMCWEB_LOG_DEBUG << "Reading from socket";
Ed Tanous2c70f802020-09-28 14:29:23 -070078 hostSocket->async_read_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070079 boost::asio::buffer(outputBuffer.data(), outputBuffer.size()),
80 [](const boost::system::error_code& ec, std::size_t bytesRead) {
81 BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
82 if (ec)
83 {
84 BMCWEB_LOG_ERROR << "Couldn't read from host serial port: "
85 << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070086 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070087 {
88 session->close("Error in connecting to host port");
89 }
90 return;
91 }
Adriana Kobylakae29b8c2019-04-24 11:19:18 -050092 std::string_view payload(outputBuffer.data(), bytesRead);
Ed Tanous271584a2019-07-09 16:24:22 -070093 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070094 {
Cheng C Yang81bfd112019-01-03 14:57:03 +080095 session->sendBinary(payload);
Ed Tanous2daf6722018-08-23 11:27:23 -070096 }
97 doRead();
98 });
99}
100
Ed Tanous23a21a12020-07-25 04:45:05 +0000101inline void connectHandler(const boost::system::error_code& ec)
Ed Tanous2daf6722018-08-23 11:27:23 -0700102{
103 if (ec)
104 {
105 BMCWEB_LOG_ERROR << "Couldn't connect to host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -0700106 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -0700107 {
108 session->close("Error in connecting to host port");
109 }
110 return;
111 }
112
113 doWrite();
114 doRead();
115}
116
Ed Tanous23a21a12020-07-25 04:45:05 +0000117inline void requestRoutes(App& app)
Ed Tanous2daf6722018-08-23 11:27:23 -0700118{
119 BMCWEB_ROUTE(app, "/console0")
Ed Tanous432a8902021-06-14 15:28:56 -0700120 .privileges({{"ConfigureComponents", "ConfigureManager"}})
Ed Tanous2daf6722018-08-23 11:27:23 -0700121 .websocket()
Gunnar Millsccd584f2021-11-16 11:36:33 -0600122 .onopen([](crow::websocket::Connection& conn,
123 const std::shared_ptr<bmcweb::AsyncResp>&) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700124 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
125
126 sessions.insert(&conn);
Ed Tanous2c70f802020-09-28 14:29:23 -0700127 if (hostSocket == nullptr)
Ed Tanous2daf6722018-08-23 11:27:23 -0700128 {
129 const std::string consoleName("\0obmc-console", 13);
130 boost::asio::local::stream_protocol::endpoint ep(consoleName);
131
Ed Tanous2c70f802020-09-28 14:29:23 -0700132 hostSocket = std::make_unique<
Ed Tanous2daf6722018-08-23 11:27:23 -0700133 boost::asio::local::stream_protocol::socket>(
Ed Tanous2c70f802020-09-28 14:29:23 -0700134 conn.getIoContext());
135 hostSocket->async_connect(ep, connectHandler);
Ed Tanous2daf6722018-08-23 11:27:23 -0700136 }
137 })
Ed Tanouscb13a392020-07-25 19:02:03 +0000138 .onclose([](crow::websocket::Connection& conn,
139 [[maybe_unused]] const std::string& reason) {
AppaRao Puli5238bd32020-11-17 11:03:11 +0530140 BMCWEB_LOG_INFO << "Closing websocket. Reason: " << reason;
141
Ed Tanouscb13a392020-07-25 19:02:03 +0000142 sessions.erase(&conn);
143 if (sessions.empty())
144 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700145 hostSocket = nullptr;
Ed Tanouscb13a392020-07-25 19:02:03 +0000146 inputBuffer.clear();
147 inputBuffer.shrink_to_fit();
148 }
149 })
150 .onmessage([]([[maybe_unused]] crow::websocket::Connection& conn,
Ed Tanous81ce6092020-12-17 16:54:55 +0000151 const std::string& data, [[maybe_unused]] bool isBinary) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700152 inputBuffer += data;
153 doWrite();
154 });
155}
156} // namespace obmc_console
157} // namespace crow