blob: 06df7fd1b14ef396516fb92023aa3e0424a7597b [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 Tanousd4d77e32020-08-18 00:07:28 -07007#include <boost/asio/local/stream_protocol.hpp>
Ed Tanous2daf6722018-08-23 11:27:23 -07008#include <boost/container/flat_map.hpp>
9#include <boost/container/flat_set.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
39 doingWrite = true;
Ed Tanous2c70f802020-09-28 14:29:23 -070040 hostSocket->async_write_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070041 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
Ed Tanous23a21a12020-07-25 04:45:05 +000063inline void doRead()
Ed Tanous2daf6722018-08-23 11:27:23 -070064{
65 BMCWEB_LOG_DEBUG << "Reading from socket";
Ed Tanous2c70f802020-09-28 14:29:23 -070066 hostSocket->async_read_some(
Ed Tanous2daf6722018-08-23 11:27:23 -070067 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
Ed Tanous23a21a12020-07-25 04:45:05 +000089inline void connectHandler(const boost::system::error_code& ec)
Ed Tanous2daf6722018-08-23 11:27:23 -070090{
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
Ed Tanous23a21a12020-07-25 04:45:05 +0000105inline void requestRoutes(App& app)
Ed Tanous2daf6722018-08-23 11:27:23 -0700106{
107 BMCWEB_ROUTE(app, "/console0")
Ed Tanous23a21a12020-07-25 04:45:05 +0000108 .privileges({"ConfigureComponents", "ConfigureManager"})
Ed Tanous2daf6722018-08-23 11:27:23 -0700109 .websocket()
Iwona Klimaszewskac0a1c8a2019-07-12 18:26:38 +0200110 .onopen([](crow::websocket::Connection& conn,
Ed Tanouscb13a392020-07-25 19:02:03 +0000111 std::shared_ptr<bmcweb::AsyncResp>) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700112 BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
113
114 sessions.insert(&conn);
Ed Tanous2c70f802020-09-28 14:29:23 -0700115 if (hostSocket == nullptr)
Ed Tanous2daf6722018-08-23 11:27:23 -0700116 {
117 const std::string consoleName("\0obmc-console", 13);
118 boost::asio::local::stream_protocol::endpoint ep(consoleName);
119
Ed Tanous2c70f802020-09-28 14:29:23 -0700120 hostSocket = std::make_unique<
Ed Tanous2daf6722018-08-23 11:27:23 -0700121 boost::asio::local::stream_protocol::socket>(
Ed Tanous2c70f802020-09-28 14:29:23 -0700122 conn.getIoContext());
123 hostSocket->async_connect(ep, connectHandler);
Ed Tanous2daf6722018-08-23 11:27:23 -0700124 }
125 })
Ed Tanouscb13a392020-07-25 19:02:03 +0000126 .onclose([](crow::websocket::Connection& conn,
127 [[maybe_unused]] const std::string& reason) {
128 sessions.erase(&conn);
129 if (sessions.empty())
130 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700131 hostSocket = nullptr;
Ed Tanouscb13a392020-07-25 19:02:03 +0000132 inputBuffer.clear();
133 inputBuffer.shrink_to_fit();
134 }
135 })
136 .onmessage([]([[maybe_unused]] crow::websocket::Connection& conn,
137 const std::string& data,
138 [[maybe_unused]] bool is_binary) {
Ed Tanous2daf6722018-08-23 11:27:23 -0700139 inputBuffer += data;
140 doWrite();
141 });
142}
143} // namespace obmc_console
144} // namespace crow