summaryrefslogtreecommitdiff
path: root/include/nbd_proxy.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/nbd_proxy.hpp')
-rw-r--r--include/nbd_proxy.hpp387
1 files changed, 0 insertions, 387 deletions
diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp
deleted file mode 100644
index adc51a85ef..0000000000
--- a/include/nbd_proxy.hpp
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
-// Copyright (c) 2019 Intel Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-*/
-#pragma once
-#include "app.hpp"
-#include "dbus_utility.hpp"
-#include "privileges.hpp"
-#include "websocket.hpp"
-
-#include <boost/asio/local/stream_protocol.hpp>
-#include <boost/beast/core/buffers_to_string.hpp>
-#include <boost/container/flat_map.hpp>
-
-#include <string_view>
-
-namespace crow
-{
-
-namespace nbd_proxy
-{
-
-using boost::asio::local::stream_protocol;
-
-static constexpr size_t nbdBufferSize = 131088;
-constexpr const char* requiredPrivilegeString = "ConfigureManager";
-
-struct NbdProxyServer : std::enable_shared_from_this<NbdProxyServer>
-{
- NbdProxyServer(crow::websocket::Connection& connIn,
- const std::string& socketIdIn,
- const std::string& endpointIdIn, const std::string& pathIn) :
- socketId(socketIdIn),
- endpointId(endpointIdIn), path(pathIn),
-
- peerSocket(connIn.getIoContext()),
- acceptor(connIn.getIoContext(), stream_protocol::endpoint(socketId)),
- connection(connIn)
- {}
-
- NbdProxyServer(const NbdProxyServer&) = delete;
- NbdProxyServer(NbdProxyServer&&) = delete;
- NbdProxyServer& operator=(const NbdProxyServer&) = delete;
- NbdProxyServer& operator=(NbdProxyServer&&) = delete;
-
- ~NbdProxyServer()
- {
- BMCWEB_LOG_DEBUG("NbdProxyServer destructor");
-
- BMCWEB_LOG_DEBUG("peerSocket->close()");
- boost::system::error_code ec;
- peerSocket.close(ec);
-
- BMCWEB_LOG_DEBUG("std::filesystem::remove({})", socketId);
- std::error_code ec2;
- std::filesystem::remove(socketId.c_str(), ec2);
- if (ec2)
- {
- BMCWEB_LOG_DEBUG("Failed to remove file, ignoring");
- }
-
- crow::connections::systemBus->async_method_call(
- dbus::utility::logError, "xyz.openbmc_project.VirtualMedia", path,
- "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
- }
-
- std::string getEndpointId() const
- {
- return endpointId;
- }
-
- void run()
- {
- acceptor.async_accept(
- [weak(weak_from_this())](const boost::system::error_code& ec,
- stream_protocol::socket socket) {
- if (ec)
- {
- BMCWEB_LOG_ERROR("UNIX socket: async_accept error = {}",
- ec.message());
- return;
- }
-
- BMCWEB_LOG_DEBUG("Connection opened");
- std::shared_ptr<NbdProxyServer> self = weak.lock();
- if (self == nullptr)
- {
- return;
- }
-
- self->connection.resumeRead();
- self->peerSocket = std::move(socket);
- // Start reading from socket
- self->doRead();
- });
-
- auto mountHandler = [weak(weak_from_this())](
- const boost::system::error_code& ec, bool) {
- std::shared_ptr<NbdProxyServer> self = weak.lock();
- if (self == nullptr)
- {
- return;
- }
- if (ec)
- {
- BMCWEB_LOG_ERROR("DBus error: cannot call mount method = {}",
- ec.message());
-
- self->connection.close("Failed to mount media");
- return;
- }
- };
-
- crow::connections::systemBus->async_method_call(
- std::move(mountHandler), "xyz.openbmc_project.VirtualMedia", path,
- "xyz.openbmc_project.VirtualMedia.Proxy", "Mount");
- }
-
- void send(std::string_view buffer, std::function<void()>&& onDone)
- {
- size_t copied = boost::asio::buffer_copy(
- ws2uxBuf.prepare(buffer.size()), boost::asio::buffer(buffer));
- ws2uxBuf.commit(copied);
-
- doWrite(std::move(onDone));
- }
-
- private:
- void doRead()
- {
- // Trigger async read
- peerSocket.async_read_some(
- ux2wsBuf.prepare(nbdBufferSize),
- [weak(weak_from_this())](const boost::system::error_code& ec,
- size_t bytesRead) {
- if (ec)
- {
- BMCWEB_LOG_ERROR("UNIX socket: async_read_some error = {}",
- ec.message());
- return;
- }
- std::shared_ptr<NbdProxyServer> self = weak.lock();
- if (self == nullptr)
- {
- return;
- }
-
- // Send to websocket
- self->ux2wsBuf.commit(bytesRead);
- self->connection.sendEx(
- crow::websocket::MessageType::Binary,
- boost::beast::buffers_to_string(self->ux2wsBuf.data()),
- [weak(self->weak_from_this())]() {
- std::shared_ptr<NbdProxyServer> self2 = weak.lock();
- if (self2 != nullptr)
- {
- self2->ux2wsBuf.consume(self2->ux2wsBuf.size());
- self2->doRead();
- }
- });
- });
- }
-
- void doWrite(std::function<void()>&& onDone)
- {
- if (uxWriteInProgress)
- {
- BMCWEB_LOG_ERROR("Write in progress");
- return;
- }
-
- if (ws2uxBuf.size() == 0)
- {
- BMCWEB_LOG_ERROR("No data to write to UNIX socket");
- return;
- }
-
- uxWriteInProgress = true;
- peerSocket.async_write_some(
- ws2uxBuf.data(),
- [weak(weak_from_this()),
- onDone(std::move(onDone))](const boost::system::error_code& ec,
- size_t bytesWritten) mutable {
- std::shared_ptr<NbdProxyServer> self = weak.lock();
- if (self == nullptr)
- {
- return;
- }
-
- self->ws2uxBuf.consume(bytesWritten);
- self->uxWriteInProgress = false;
-
- if (ec)
- {
- BMCWEB_LOG_ERROR("UNIX: async_write error = {}", ec.message());
- self->connection.close("Internal error");
- return;
- }
-
- // Retrigger doWrite if there is something in buffer
- if (self->ws2uxBuf.size() > 0)
- {
- self->doWrite(std::move(onDone));
- return;
- }
- onDone();
- });
- }
-
- // Keeps UNIX socket endpoint file path
- const std::string socketId;
- const std::string endpointId;
- const std::string path;
-
- bool uxWriteInProgress = false;
-
- // UNIX => WebSocket buffer
- boost::beast::flat_static_buffer<nbdBufferSize> ux2wsBuf;
-
- // WebSocket => UNIX buffer
- boost::beast::flat_static_buffer<nbdBufferSize> ws2uxBuf;
-
- // The socket used to communicate with the client.
- stream_protocol::socket peerSocket;
-
- // Default acceptor for UNIX socket
- stream_protocol::acceptor acceptor;
-
- crow::websocket::Connection& connection;
-};
-
-using SessionMap = boost::container::flat_map<crow::websocket::Connection*,
- std::shared_ptr<NbdProxyServer>>;
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-static SessionMap sessions;
-
-inline void
- afterGetManagedObjects(crow::websocket::Connection& conn,
- const boost::system::error_code& ec,
- const dbus::utility::ManagedObjectType& objects)
-{
- const std::string* socketValue = nullptr;
- const std::string* endpointValue = nullptr;
- const std::string* endpointObjectPath = nullptr;
-
- if (ec)
- {
- BMCWEB_LOG_ERROR("DBus error: {}", ec.message());
- conn.close("Failed to create mount point");
- return;
- }
-
- for (const auto& [objectPath, interfaces] : objects)
- {
- for (const auto& [interface, properties] : interfaces)
- {
- if (interface != "xyz.openbmc_project.VirtualMedia.MountPoint")
- {
- continue;
- }
-
- for (const auto& [name, value] : properties)
- {
- if (name == "EndpointId")
- {
- endpointValue = std::get_if<std::string>(&value);
-
- if (endpointValue == nullptr)
- {
- BMCWEB_LOG_ERROR("EndpointId property value is null");
- }
- }
- if (name == "Socket")
- {
- socketValue = std::get_if<std::string>(&value);
- if (socketValue == nullptr)
- {
- BMCWEB_LOG_ERROR("Socket property value is null");
- }
- }
- }
- }
-
- if ((endpointValue != nullptr) && (socketValue != nullptr) &&
- *endpointValue == conn.url().path())
- {
- endpointObjectPath = &objectPath.str;
- break;
- }
- }
-
- if (objects.empty() || endpointObjectPath == nullptr)
- {
- BMCWEB_LOG_ERROR("Cannot find requested EndpointId");
- conn.close("Failed to match EndpointId");
- return;
- }
-
- for (const auto& session : sessions)
- {
- if (session.second->getEndpointId() == conn.url().path())
- {
- BMCWEB_LOG_ERROR("Cannot open new connection - socket is in use");
- conn.close("Slot is in use");
- return;
- }
- }
-
- // If the socket file exists (i.e. after bmcweb crash),
- // we cannot reuse it.
- std::remove((*socketValue).c_str());
-
- sessions[&conn] = std::make_shared<NbdProxyServer>(
- conn, *socketValue, *endpointValue, *endpointObjectPath);
-
- sessions[&conn]->run();
-};
-inline void onOpen(crow::websocket::Connection& conn)
-{
- BMCWEB_LOG_DEBUG("nbd-proxy.onopen({})", logPtr(&conn));
-
- sdbusplus::message::object_path path("/xyz/openbmc_project/VirtualMedia");
- dbus::utility::getManagedObjects(
- "xyz.openbmc_project.VirtualMedia", path,
- [&conn](const boost::system::error_code& ec,
- const dbus::utility::ManagedObjectType& objects) {
- afterGetManagedObjects(conn, ec, objects);
- });
-
- // We need to wait for dbus and the websockets to hook up before data is
- // sent/received. Tell the core to hold off messages until the sockets are
- // up
- conn.deferRead();
-}
-
-inline void onClose(crow::websocket::Connection& conn,
- const std::string& reason)
-{
- BMCWEB_LOG_DEBUG("nbd-proxy.onclose(reason = '{}')", reason);
- auto session = sessions.find(&conn);
- if (session == sessions.end())
- {
- BMCWEB_LOG_DEBUG("No session to close");
- return;
- }
- // Remove reference to session in global map
- sessions.erase(session);
-}
-
-inline void onMessage(crow::websocket::Connection& conn, std::string_view data,
- crow::websocket::MessageType /*type*/,
- std::function<void()>&& whenComplete)
-{
- BMCWEB_LOG_DEBUG("nbd-proxy.onMessage(len = {})", data.size());
-
- // Acquire proxy from sessions
- auto session = sessions.find(&conn);
- if (session == sessions.end() || session->second == nullptr)
- {
- whenComplete();
- return;
- }
-
- session->second->send(data, std::move(whenComplete));
-}
-
-inline void requestRoutes(App& app)
-{
- BMCWEB_ROUTE(app, "/nbd/<str>")
- .websocket()
- .onopen(onOpen)
- .onclose(onClose)
- .onmessageex(onMessage);
-}
-} // namespace nbd_proxy
-} // namespace crow