blob: b545f960e147befc23686301103e2f33ada0a774 [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
6#include <boost/container/flat_map.hpp>
7#include <boost/container/flat_set.hpp>
8#include <webserver_common.hpp>
9
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
104void requestRoutes(CrowApp& app)
105{
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()
109 .onopen([](crow::websocket::Connection& conn) {
110 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
111
112 sessions.insert(&conn);
113 if (host_socket == nullptr)
114 {
115 const std::string consoleName("\0obmc-console", 13);
116 boost::asio::local::stream_protocol::endpoint ep(consoleName);
117
Ed Tanous2daf6722018-08-23 11:27:23 -0700118 host_socket = std::make_unique<
119 boost::asio::local::stream_protocol::socket>(
Ed Tanousceac6f72018-12-02 11:58:47 -0800120 conn.get_io_context());
Ed Tanous2daf6722018-08-23 11:27:23 -0700121 host_socket->async_connect(ep, connectHandler);
122 }
123 })
124 .onclose(
125 [](crow::websocket::Connection& conn, const std::string& reason) {
126 sessions.erase(&conn);
127 if (sessions.empty())
128 {
129 host_socket = nullptr;
130 inputBuffer.clear();
131 inputBuffer.shrink_to_fit();
132 }
133 })
134 .onmessage([](crow::websocket::Connection& conn,
135 const std::string& data, bool is_binary) {
136 inputBuffer += data;
137 doWrite();
138 });
139}
140} // namespace obmc_console
141} // namespace crow