blob: af02dde4cf182a6490fd4d717f8a9ca004fd9d2e [file] [log] [blame]
Ed Tanous2daf6722018-08-23 11:27:23 -07001#pragma once
Ed Tanousc94ad492019-10-10 15:39:33 -07002#include <app.h>
Ed Tanous2daf6722018-08-23 11:27:23 -07003#include <sys/socket.h>
Ed Tanousc94ad492019-10-10 15:39:33 -07004#include <websocket.h>
Ed Tanous2daf6722018-08-23 11:27:23 -07005
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +02006#include <async_resp.hpp>
Ed Tanous2daf6722018-08-23 11:27:23 -07007#include <boost/container/flat_map.hpp>
8#include <boost/container/flat_set.hpp>
Ed Tanous2daf6722018-08-23 11:27:23 -07009
10namespace crow
11{
12namespace obmc_console
13{
14
15static std::unique_ptr<boost::asio::local::stream_protocol::socket> host_socket;
16
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
24void doWrite()
25{
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
38 doingWrite = true;
39 host_socket->async_write_some(
40 boost::asio::buffer(inputBuffer.data(), inputBuffer.size()),
41 [](boost::beast::error_code ec, std::size_t bytes_written) {
42 doingWrite = false;
43 inputBuffer.erase(0, bytes_written);
44
45 if (ec == boost::asio::error::eof)
46 {
Ed Tanous271584a2019-07-09 16:24:22 -070047 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070048 {
49 session->close("Error in reading to host port");
50 }
51 return;
52 }
53 if (ec)
54 {
55 BMCWEB_LOG_ERROR << "Error in host serial write " << ec;
56 return;
57 }
58 doWrite();
59 });
60}
61
62void doRead()
63{
64 BMCWEB_LOG_DEBUG << "Reading from socket";
65 host_socket->async_read_some(
66 boost::asio::buffer(outputBuffer.data(), outputBuffer.size()),
67 [](const boost::system::error_code& ec, std::size_t bytesRead) {
68 BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
69 if (ec)
70 {
71 BMCWEB_LOG_ERROR << "Couldn't read from host serial port: "
72 << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070073 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070074 {
75 session->close("Error in connecting to host port");
76 }
77 return;
78 }
Adriana Kobylakae29b8c2019-04-24 11:19:18 -050079 std::string_view payload(outputBuffer.data(), bytesRead);
Ed Tanous271584a2019-07-09 16:24:22 -070080 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070081 {
Cheng C Yang81bfd112019-01-03 14:57:03 +080082 session->sendBinary(payload);
Ed Tanous2daf6722018-08-23 11:27:23 -070083 }
84 doRead();
85 });
86}
87
88void connectHandler(const boost::system::error_code& ec)
89{
90 if (ec)
91 {
92 BMCWEB_LOG_ERROR << "Couldn't connect to host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070093 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070094 {
95 session->close("Error in connecting to host port");
96 }
97 return;
98 }
99
100 doWrite();
101 doRead();
102}
103
Ed Tanous52cc1122020-07-18 13:51:21 -0700104void requestRoutes(App& app)
Ed Tanous2daf6722018-08-23 11:27:23 -0700105{
106 BMCWEB_ROUTE(app, "/console0")
Ed Tanous8251ffe2019-10-10 14:33:54 -0700107 .requires({"ConfigureComponents", "ConfigureManager"})
Ed Tanous2daf6722018-08-23 11:27:23 -0700108 .websocket()
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +0200109 .onopen([](crow::websocket::Connection& conn,
110 std::shared_ptr<bmcweb::AsyncResp> asyncResp) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700111 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
112
113 sessions.insert(&conn);
114 if (host_socket == nullptr)
115 {
116 const std::string consoleName("\0obmc-console", 13);
117 boost::asio::local::stream_protocol::endpoint ep(consoleName);
118
Ed Tanous2daf6722018-08-23 11:27:23 -0700119 host_socket = std::make_unique<
120 boost::asio::local::stream_protocol::socket>(
Ed Tanousceac6f72018-12-02 11:58:47 -0800121 conn.get_io_context());
Ed Tanous2daf6722018-08-23 11:27:23 -0700122 host_socket->async_connect(ep, connectHandler);
123 }
124 })
125 .onclose(
126 [](crow::websocket::Connection& conn, const std::string& reason) {
127 sessions.erase(&conn);
128 if (sessions.empty())
129 {
130 host_socket = nullptr;
131 inputBuffer.clear();
132 inputBuffer.shrink_to_fit();
133 }
134 })
135 .onmessage([](crow::websocket::Connection& conn,
136 const std::string& data, bool is_binary) {
137 inputBuffer += data;
138 doWrite();
139 });
140}
141} // namespace obmc_console
142} // namespace crow