blob: 9e5e058b8542d89134bf855bc450feb3552a11f2 [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>
9#include <webserver_common.hpp>
10
11namespace crow
12{
13namespace obmc_console
14{
15
16static std::unique_ptr<boost::asio::local::stream_protocol::socket> host_socket;
17
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
25void doWrite()
26{
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
39 doingWrite = true;
40 host_socket->async_write_some(
41 boost::asio::buffer(inputBuffer.data(), inputBuffer.size()),
42 [](boost::beast::error_code ec, std::size_t bytes_written) {
43 doingWrite = false;
44 inputBuffer.erase(0, bytes_written);
45
46 if (ec == boost::asio::error::eof)
47 {
Ed Tanous271584a2019-07-09 16:24:22 -070048 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070049 {
50 session->close("Error in reading to host port");
51 }
52 return;
53 }
54 if (ec)
55 {
56 BMCWEB_LOG_ERROR << "Error in host serial write " << ec;
57 return;
58 }
59 doWrite();
60 });
61}
62
63void doRead()
64{
65 BMCWEB_LOG_DEBUG << "Reading from socket";
66 host_socket->async_read_some(
67 boost::asio::buffer(outputBuffer.data(), outputBuffer.size()),
68 [](const boost::system::error_code& ec, std::size_t bytesRead) {
69 BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
70 if (ec)
71 {
72 BMCWEB_LOG_ERROR << "Couldn't read from host serial port: "
73 << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070074 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070075 {
76 session->close("Error in connecting to host port");
77 }
78 return;
79 }
Adriana Kobylakae29b8c2019-04-24 11:19:18 -050080 std::string_view payload(outputBuffer.data(), bytesRead);
Ed Tanous271584a2019-07-09 16:24:22 -070081 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070082 {
Cheng C Yang81bfd112019-01-03 14:57:03 +080083 session->sendBinary(payload);
Ed Tanous2daf6722018-08-23 11:27:23 -070084 }
85 doRead();
86 });
87}
88
89void connectHandler(const boost::system::error_code& ec)
90{
91 if (ec)
92 {
93 BMCWEB_LOG_ERROR << "Couldn't connect to host serial port: " << ec;
Ed Tanous271584a2019-07-09 16:24:22 -070094 for (crow::websocket::Connection* session : sessions)
Ed Tanous2daf6722018-08-23 11:27:23 -070095 {
96 session->close("Error in connecting to host port");
97 }
98 return;
99 }
100
101 doWrite();
102 doRead();
103}
104
105void requestRoutes(CrowApp& app)
106{
107 BMCWEB_ROUTE(app, "/console0")
Ed Tanous8251ffe2019-10-10 14:33:54 -0700108 .requires({"ConfigureComponents", "ConfigureManager"})
Ed Tanous2daf6722018-08-23 11:27:23 -0700109 .websocket()
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +0200110 .onopen([](crow::websocket::Connection& conn,
111 std::shared_ptr<bmcweb::AsyncResp> asyncResp) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700112 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
113
114 sessions.insert(&conn);
115 if (host_socket == nullptr)
116 {
117 const std::string consoleName("\0obmc-console", 13);
118 boost::asio::local::stream_protocol::endpoint ep(consoleName);
119
Ed Tanous2daf6722018-08-23 11:27:23 -0700120 host_socket = std::make_unique<
121 boost::asio::local::stream_protocol::socket>(
Ed Tanousceac6f72018-12-02 11:58:47 -0800122 conn.get_io_context());
Ed Tanous2daf6722018-08-23 11:27:23 -0700123 host_socket->async_connect(ep, connectHandler);
124 }
125 })
126 .onclose(
127 [](crow::websocket::Connection& conn, const std::string& reason) {
128 sessions.erase(&conn);
129 if (sessions.empty())
130 {
131 host_socket = nullptr;
132 inputBuffer.clear();
133 inputBuffer.shrink_to_fit();
134 }
135 })
136 .onmessage([](crow::websocket::Connection& conn,
137 const std::string& data, bool is_binary) {
138 inputBuffer += data;
139 doWrite();
140 });
141}
142} // namespace obmc_console
143} // namespace crow