diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch | 547 |
1 files changed, 0 insertions, 547 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch deleted file mode 100644 index 54f00aa39..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch +++ /dev/null @@ -1,547 +0,0 @@ -From d340953bc925ff8535c5a8fac54db24b243ba8ad Mon Sep 17 00:00:00 2001 -From: AppaRao Puli <apparao.puli@linux.intel.com> -Date: Mon, 19 Oct 2020 13:21:42 +0530 -Subject: [PATCH] EventService: https client support - -Add https client support for push style -eventing. Using this BMC can push the event -logs/telemetry data to event listener over -secure http channel. - -Tested: - - Created subscription with https destination - url. Using SubmitTestEvent action set the - event and can see event on event listener. - - Validator passed. - -Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a -Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> -Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> ---- - http/http_client.hpp | 370 +++++++++++++----- - .../include/event_service_manager.hpp | 2 +- - 2 files changed, 267 insertions(+), 105 deletions(-) - -diff --git a/http/http_client.hpp b/http/http_client.hpp -index 5c7b13f..d782dee 100644 ---- a/http/http_client.hpp -+++ b/http/http_client.hpp -@@ -31,12 +31,17 @@ namespace crow - { - - static constexpr uint8_t maxRequestQueueSize = 50; -+static constexpr unsigned int httpReadBodyLimit = 1024; - - enum class ConnState - { - initialized, -+ resolveInProgress, -+ resolveFailed, -+ resolved, - connectInProgress, - connectFailed, -+ sslHandshakeInProgress, - connected, - sendInProgress, - sendFailed, -@@ -50,53 +55,124 @@ enum class ConnState - class HttpClient : public std::enable_shared_from_this<HttpClient> - { - private: -+ boost::asio::ip::tcp::resolver resolver; -+ boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client}; - boost::beast::tcp_stream conn; -+ std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream&>> sslConn; - boost::asio::steady_timer timer; -- boost::beast::flat_buffer buffer; -+ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; -+ std::optional< -+ boost::beast::http::response_parser<boost::beast::http::string_body>> -+ parser; - boost::beast::http::request<boost::beast::http::string_body> req; -- boost::beast::http::response<boost::beast::http::string_body> res; - boost::asio::ip::tcp::resolver::results_type endpoint; -- std::vector<std::pair<std::string, std::string>> headers; -+ boost::beast::http::fields fields; - std::queue<std::string> requestDataQueue; -- ConnState state; - std::string subId; - std::string host; - std::string port; - std::string uri; -+ bool useSsl; - uint32_t retryCount; - uint32_t maxRetryAttempts; - uint32_t retryIntervalSecs; - std::string retryPolicyAction; - bool runningTimer; -+ ConnState state; -+ -+ void doResolve() -+ { -+ BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port; -+ if (state == ConnState::resolveInProgress) -+ { -+ return; -+ } -+ state = ConnState::resolveInProgress; -+ // TODO: Use async_resolver. boost asio example -+ // code as is crashing with async_resolve(). -+ try -+ { -+ endpoint = resolver.resolve(host, port); -+ } -+ catch (const std::exception& e) -+ { -+ BMCWEB_LOG_ERROR << "Failed to resolve hostname: " << host << " - " -+ << e.what(); -+ state = ConnState::resolveFailed; -+ checkQueue(); -+ return; -+ } -+ state = ConnState::resolved; -+ checkQueue(); -+ } - - void doConnect() - { -- if (state == ConnState::connectInProgress) -+ if (useSsl) -+ { -+ sslConn.emplace(conn, ctx); -+ } -+ -+ if ((state == ConnState::connectInProgress) || -+ (state == ConnState::sslHandshakeInProgress)) - { - return; - } - state = ConnState::connectInProgress; - - BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; -- // Set a timeout on the operation -+ -+ auto respHandler = -+ [self(shared_from_this())](const boost::beast::error_code ec, -+ const boost::asio::ip::tcp::resolver:: -+ results_type::endpoint_type& ep) { -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "Connect " << ep -+ << " failed: " << ec.message(); -+ self->state = ConnState::connectFailed; -+ self->checkQueue(); -+ return; -+ } -+ BMCWEB_LOG_DEBUG << "Connected to: " << ep; -+ if (self->sslConn) -+ { -+ self->performHandshake(); -+ } -+ else -+ { -+ self->state = ConnState::connected; -+ self->checkQueue(); -+ } -+ }; -+ - conn.expires_after(std::chrono::seconds(30)); -- conn.async_connect(endpoint, [self(shared_from_this())]( -- const boost::beast::error_code& ec, -- const boost::asio::ip::tcp::resolver:: -- results_type::endpoint_type& ep) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "Connect " << ep -- << " failed: " << ec.message(); -- self->state = ConnState::connectFailed; -- self->checkQueue(); -- return; -- } -- self->state = ConnState::connected; -- BMCWEB_LOG_DEBUG << "Connected to: " << ep; -+ conn.async_connect(endpoint, std::move(respHandler)); -+ } -+ -+ void performHandshake() -+ { -+ if (state == ConnState::sslHandshakeInProgress) -+ { -+ return; -+ } -+ state = ConnState::sslHandshakeInProgress; -+ -+ sslConn->async_handshake( -+ boost::asio::ssl::stream_base::client, -+ [self(shared_from_this())](const boost::beast::error_code ec) { -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "SSL handshake failed: " -+ << ec.message(); -+ self->doCloseAndCheckQueue(ConnState::connectFailed); -+ return; -+ } -+ self->state = ConnState::connected; -+ BMCWEB_LOG_DEBUG << "SSL Handshake successfull"; - -- self->checkQueue(); -- }); -+ self->checkQueue(); -+ }); - } - - void sendMessage(const std::string& data) -@@ -107,100 +183,170 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - } - state = ConnState::sendInProgress; - -- BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; -+ BMCWEB_LOG_DEBUG << host << ":" << port; - -- req.version(static_cast<int>(11)); // HTTP 1.1 -- req.target(uri); -- req.method(boost::beast::http::verb::post); -- -- // Set headers -- for (const auto& [key, value] : headers) -+ req = {}; -+ for (const auto& field : fields) - { -- req.set(key, value); -+ req.set(field.name_string(), field.value()); - } - req.set(boost::beast::http::field::host, host); -+ req.set(boost::beast::http::field::content_type, "text/plain"); -+ -+ req.version(static_cast<int>(11)); // HTTP 1.1 -+ req.target(uri); -+ req.method(boost::beast::http::verb::post); - req.keep_alive(true); - - req.body() = data; - req.prepare_payload(); - -- // Set a timeout on the operation -- conn.expires_after(std::chrono::seconds(30)); -+ auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code ec, -+ const std::size_t& bytesTransferred) { -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); -+ self->doCloseAndCheckQueue(ConnState::sendFailed); -+ return; -+ } -+ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " -+ << bytesTransferred; -+ boost::ignore_unused(bytesTransferred); - -- // Send the HTTP request to the remote host -- boost::beast::http::async_write( -- conn, req, -- [self(shared_from_this())](const boost::beast::error_code& ec, -- const std::size_t& bytesTransferred) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "sendMessage() failed: " -- << ec.message(); -- self->state = ConnState::sendFailed; -- self->checkQueue(); -- return; -- } -- BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " -- << bytesTransferred; -- boost::ignore_unused(bytesTransferred); -+ self->recvMessage(); -+ }; - -- self->recvMessage(); -- }); -+ conn.expires_after(std::chrono::seconds(30)); -+ if (sslConn) -+ { -+ boost::beast::http::async_write(*sslConn, req, -+ std::move(respHandler)); -+ } -+ else -+ { -+ boost::beast::http::async_write(conn, req, std::move(respHandler)); -+ } - } - - void recvMessage() - { -- // Receive the HTTP response -- boost::beast::http::async_read( -- conn, buffer, res, -- [self(shared_from_this())](const boost::beast::error_code& ec, -- const std::size_t& bytesTransferred) { -+ auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code ec, -+ const std::size_t& bytesTransferred) { -+ if (ec && ec != boost::beast::http::error::partial_message) -+ { -+ BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message(); -+ self->doCloseAndCheckQueue(ConnState::recvFailed); -+ return; -+ } -+ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " -+ << bytesTransferred; -+ boost::ignore_unused(bytesTransferred); -+ -+ // TODO: check for return status code and perform -+ // retry if fails(Ex: 40x). Take action depending on -+ // retry policy. -+ BMCWEB_LOG_DEBUG << "recvMessage() data: " -+ << self->parser->get().body(); -+ -+ // Send is successful, Lets remove data from queue -+ // check for next request data in queue. -+ self->requestDataQueue.pop(); -+ -+ // Transfer ownership of the response -+ self->parser->release(); -+ -+ // TODO: Implement the keep-alive connections. -+ // Most of the web servers close connection abruptly -+ // and might be reason due to which its observed that -+ // stream_truncated(Next read) or partial_message -+ // errors. So for now, closing connection and re-open -+ // for all cases. -+ self->doCloseAndCheckQueue(ConnState::closed); -+ }; -+ -+ parser.emplace(std::piecewise_construct, std::make_tuple()); -+ parser->body_limit(httpReadBodyLimit); -+ // Since these are all push style eventing, we are not -+ // bothered about response parsing. -+ parser->skip(true); -+ buffer.consume(buffer.size()); -+ -+ conn.expires_after(std::chrono::seconds(30)); -+ if (sslConn) -+ { -+ boost::beast::http::async_read(*sslConn, buffer, *parser, -+ std::move(respHandler)); -+ } -+ else -+ { -+ boost::beast::http::async_read(conn, buffer, *parser, -+ std::move(respHandler)); -+ } -+ } -+ -+ void doCloseAndCheckQueue(const ConnState setState = ConnState::closed) -+ { -+ if (sslConn) -+ { -+ conn.expires_after(std::chrono::seconds(30)); -+ sslConn->async_shutdown([self = shared_from_this(), -+ setState{std::move(setState)}]( -+ const boost::system::error_code ec) { - if (ec) - { -- BMCWEB_LOG_ERROR << "recvMessage() failed: " -- << ec.message(); -- self->state = ConnState::recvFailed; -- self->checkQueue(); -- return; -+ // Many https server closes connection abruptly -+ // i.e witnout close_notify. More details are at -+ // https://github.com/boostorg/beast/issues/824 -+ if (ec == boost::asio::ssl::error::stream_truncated) -+ { -+ BMCWEB_LOG_ERROR -+ << "doCloseAndCheckQueue(): Connection " -+ "closed by server. "; -+ } -+ else -+ { -+ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " -+ << ec.message(); -+ } - } -- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " -- << bytesTransferred; -- boost::ignore_unused(bytesTransferred); -- -- // Discard received data. We are not interested. -- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; -- -- // Send is successful, Lets remove data from queue -- // check for next request data in queue. -- self->requestDataQueue.pop(); -- self->state = ConnState::idle; -+ else -+ { -+ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; -+ } -+ self->conn.cancel(); -+ self->state = setState; - self->checkQueue(); - }); -- } -- -- void doClose() -- { -- boost::beast::error_code ec; -- conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); -- -- state = ConnState::closed; -- // not_connected happens sometimes so don't bother reporting it. -- if (ec && ec != boost::beast::errc::not_connected) -+ } -+ else - { -- BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message(); -- return; -+ boost::beast::error_code ec; -+ conn.expires_after(std::chrono::seconds(30)); -+ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, -+ ec); -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " -+ << ec.message(); -+ } -+ else -+ { -+ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; -+ } -+ -+ conn.close(); -+ state = setState; -+ checkQueue(); - } -- BMCWEB_LOG_DEBUG << "Connection closed gracefully"; -+ return; - } - - void checkQueue(const bool newRecord = false) - { - if (requestDataQueue.empty()) - { -- // TODO: Having issue in keeping connection alive. So lets close if -- // nothing to be transferred. -- doClose(); -- - BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; - return; - } -@@ -232,6 +378,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - } - - if ((state == ConnState::connectFailed) || -+ (state == ConnState::resolveFailed) || - (state == ConnState::sendFailed) || - (state == ConnState::recvFailed)) - { -@@ -256,14 +403,18 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - << " seconds. RetryCount = " << retryCount; - timer.expires_after(std::chrono::seconds(retryIntervalSecs)); - timer.async_wait( -- [self = shared_from_this()](const boost::system::error_code&) { -+ [self = shared_from_this()](boost::system::error_code) { - self->runningTimer = false; - self->connStateCheck(); - }); - return; - } -- // reset retry count. -- retryCount = 0; -+ -+ if (state == ConnState::idle) -+ { -+ // State idle means, previous attempt is successful. -+ retryCount = 0; -+ } - connStateCheck(); - - return; -@@ -273,15 +424,21 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - { - switch (state) - { -+ case ConnState::initialized: -+ case ConnState::resolveFailed: -+ case ConnState::connectFailed: -+ doResolve(); -+ break; - case ConnState::connectInProgress: -+ case ConnState::resolveInProgress: -+ case ConnState::sslHandshakeInProgress: - case ConnState::sendInProgress: - case ConnState::suspended: - case ConnState::terminated: - // do nothing - break; -- case ConnState::initialized: - case ConnState::closed: -- case ConnState::connectFailed: -+ case ConnState::resolved: - case ConnState::sendFailed: - case ConnState::recvFailed: - { -@@ -297,22 +454,22 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - sendMessage(data); - break; - } -+ default: -+ break; - } - } - - public: - explicit HttpClient(boost::asio::io_context& ioc, const std::string& id, - const std::string& destIP, const std::string& destPort, -- const std::string& destUri) : -- conn(ioc), -- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), -- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), -- retryPolicyAction("TerminateAfterRetries"), runningTimer(false) -- { -- boost::asio::ip::tcp::resolver resolver(ioc); -- endpoint = resolver.resolve(host, port); -- state = ConnState::initialized; -- } -+ const std::string& destUri, -+ const bool inUseSsl = true) : -+ resolver(ioc), -+ conn(ioc), timer(ioc), subId(id), host(destIP), port(destPort), -+ uri(destUri), useSsl(inUseSsl), retryCount(0), maxRetryAttempts(5), -+ retryPolicyAction("TerminateAfterRetries"), runningTimer(false), -+ state(ConnState::initialized) -+ {} - - void sendData(const std::string& data) - { -@@ -337,7 +494,12 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - void setHeaders( - const std::vector<std::pair<std::string, std::string>>& httpHeaders) - { -- headers = httpHeaders; -+ // Set headers -+ for (const auto& [key, value] : httpHeaders) -+ { -+ // TODO: Validate the header fileds before assign. -+ fields.set(key, value); -+ } - } - - void setRetryConfig(const uint32_t retryAttempts, -diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 54dafb4..f68ae1d 100644 ---- a/redfish-core/include/event_service_manager.hpp -+++ b/redfish-core/include/event_service_manager.hpp -@@ -387,7 +387,7 @@ class Subscription - { - conn = std::make_shared<crow::HttpClient>( - crow::connections::systemBus->get_io_context(), id, host, port, -- path); -+ path, (uriProto == "https" ? true : false)); - } - - Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) : --- -2.17.1 - |