blob: 436f6c6cf1ae8cb1d0a90deab52a0f326a4ba480 [file] [log] [blame]
Ed Tanous2daf6722018-08-23 11:27:23 -07001#pragma once
2#include <crow/app.h>
3#include <crow/websocket.h>
4#include <sys/socket.h>
5
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 {
47 for (auto session : sessions)
48 {
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;
73 for (auto session : sessions)
74 {
75 session->close("Error in connecting to host port");
76 }
77 return;
78 }
79 boost::beast::string_view payload(outputBuffer.data(), bytesRead);
80 for (auto session : sessions)
81 {
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;
93 for (auto session : sessions)
94 {
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")
107 .websocket()
108 .onopen([](crow::websocket::Connection& conn) {
109 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
110
111 sessions.insert(&conn);
112 if (host_socket == nullptr)
113 {
114 const std::string consoleName("\0obmc-console", 13);
115 boost::asio::local::stream_protocol::endpoint ep(consoleName);
116
Ed Tanous2daf6722018-08-23 11:27:23 -0700117 host_socket = std::make_unique<
118 boost::asio::local::stream_protocol::socket>(
119 conn.getIoService());
120 host_socket->async_connect(ep, connectHandler);
121 }
122 })
123 .onclose(
124 [](crow::websocket::Connection& conn, const std::string& reason) {
125 sessions.erase(&conn);
126 if (sessions.empty())
127 {
128 host_socket = nullptr;
129 inputBuffer.clear();
130 inputBuffer.shrink_to_fit();
131 }
132 })
133 .onmessage([](crow::websocket::Connection& conn,
134 const std::string& data, bool is_binary) {
135 inputBuffer += data;
136 doWrite();
137 });
138}
139} // namespace obmc_console
140} // namespace crow