summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch163
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch448
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch471
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch677
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch326
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch133
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch85
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch267
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch141
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0012-Add-support-for-deleting-terminated-subscriptions.patch66
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0013-event-service-fix-added-Context-field-to-response.patch33
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README37
12 files changed, 2847 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch
new file mode 100644
index 000000000..5cb5c538c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch
@@ -0,0 +1,163 @@
+From d5ade2d2032d7bb0c17c92e957c2a4f6e77af2ee Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 6 Dec 2021 19:49:01 +0000
+Subject: [PATCH] Add unmerged changes for http retry support
+
+The http retry support added upstream as a single patch was slpit into
+3 patches, but only 2 of them was merged.
+This commit pulls in the differentail changes required to complete the
+entire http retry support. and also allow for other subsequent patches
+to be appplied easily.
+
+Change-Id: I43e68eeffb8d69c289dd306c1c7cafc87ad766a0
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_client.hpp | 32 ++++++++++++++++---
+ .../include/event_service_manager.hpp | 26 +++++++++------
+ redfish-core/lib/event_service.hpp | 1 +
+ 3 files changed, 45 insertions(+), 14 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index 5f352d3..f0152db 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -188,6 +188,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ BMCWEB_LOG_DEBUG << "recvMessage() data: "
+ << self->parser->get();
+
++ // Check if the response and header are received
++ if (!self->parser->is_done())
++ {
++ // The parser failed to receive the response
++ BMCWEB_LOG_ERROR
++ << "recvMessage() parser failed to receive response";
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
++
+ unsigned int respCode = self->parser->get().result_int();
+ BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
+ << respCode;
+@@ -379,15 +390,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ public:
+ explicit HttpClient(boost::asio::io_context& ioc, const std::string& id,
+ const std::string& destIP, const std::string& destPort,
+- const std::string& destUri,
+- const boost::beast::http::fields& httpHeader) :
++ const std::string& destUri) :
+ conn(ioc),
+- timer(ioc),
+- req(boost::beast::http::verb::post, destUri, 11, "", httpHeader),
+- subId(id), host(destIP), port(destPort)
++ timer(ioc), req(boost::beast::http::verb::post, destUri, 11), subId(id),
++ host(destIP), port(destPort)
+ {
++ // Set the request header
+ req.set(boost::beast::http::field::host, host);
++ req.set(boost::beast::http::field::content_type, "application/json");
+ req.keep_alive(true);
++
++ requestDataQueue.set_capacity(maxRequestQueueSize);
+ }
+
+ void sendData(const std::string& data)
+@@ -408,6 +421,15 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ }
+
++ void setHeaders(const boost::beast::http::fields& httpHeaders)
++ {
++ // Set custom headers
++ for (const auto& header : httpHeaders)
++ {
++ req.set(header.name(), header.value());
++ }
++ }
++
+ void setRetryConfig(const uint32_t retryAttempts,
+ const uint32_t retryTimeoutInterval)
+ {
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index e879f9e..75380dc 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -370,7 +370,10 @@ class Subscription : public persistent_data::UserSubscription
+ eventSeqNum(1),
+ host(inHost), port(inPort), path(inPath), uriProto(inUriProto)
+ {
+- // Subscription constructor
++ // create the HttpClient connection
++ conn = std::make_shared<crow::HttpClient>(
++ crow::connections::systemBus->get_io_context(), id, host, port,
++ path);
+ }
+
+ Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+@@ -391,17 +394,12 @@ class Subscription : public persistent_data::UserSubscription
+ return false;
+ }
+
+- if (conn == nullptr)
++ if (conn != nullptr)
+ {
+- // create the HttpClient connection
+- conn = std::make_shared<crow::HttpClient>(
+- crow::connections::systemBus->get_io_context(), id, host, port,
+- path, httpHeaders);
++ conn->sendData(msg);
++ eventSeqNum++;
+ }
+
+- conn->sendData(msg);
+- eventSeqNum++;
+-
+ if (sseConn != nullptr)
+ {
+ sseConn->sendData(eventSeqNum, msg);
+@@ -548,6 +546,14 @@ class Subscription : public persistent_data::UserSubscription
+ }
+ }
+
++ void updatehttpHeaders()
++ {
++ if (conn != nullptr)
++ {
++ conn->setHeaders(httpHeaders);
++ }
++ }
++
+ uint64_t getEventSeqNum() const
+ {
+ return eventSeqNum;
+@@ -661,6 +667,7 @@ class EventServiceManager
+ // Update retry configuration.
+ subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
+ subValue->updateRetryPolicy();
++ subValue->updatehttpHeaders();
+ }
+ }
+
+@@ -915,6 +922,7 @@ class EventServiceManager
+ // Update retry configuration.
+ subValue->updateRetryConfig(retryAttempts, retryTimeoutInterval);
+ subValue->updateRetryPolicy();
++ subValue->updatehttpHeaders();
+
+ return id;
+ }
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 9ce2f05..0903874 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -619,6 +619,7 @@ inline void requestRoutesEventDestination(App& app)
+ }
+ }
+ subValue->httpHeaders = fields;
++ subValue->updatehttpHeaders();
+ }
+
+ if (retryPolicy)
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch
new file mode 100644
index 000000000..9f51d23d3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch
@@ -0,0 +1,448 @@
+From 0dc82b56bae36aee8ebc1923e909e3ce74f6fdbc Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Mon, 6 Dec 2021 21:39:05 +0000
+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: I480085344ba7bed6ec0d94876eda1d252e51cb45
+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 | 309 ++++++++++++------
+ .../include/event_service_manager.hpp | 2 +-
+ 2 files changed, 204 insertions(+), 107 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index e69d397..7328eae 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -20,6 +20,7 @@
+ #include <boost/beast/core/flat_buffer.hpp>
+ #include <boost/beast/core/tcp_stream.hpp>
+ #include <boost/beast/http/message.hpp>
++#include <boost/beast/ssl/ssl_stream.hpp>
+ #include <boost/beast/version.hpp>
+ #include <boost/circular_buffer.hpp>
+ #include <include/async_resolve.hpp>
+@@ -44,6 +45,8 @@ enum class ConnState
+ resolveFailed,
+ connectInProgress,
+ connectFailed,
++ handshakeInProgress,
++ handshakeFailed,
+ connected,
+ sendInProgress,
+ sendFailed,
+@@ -62,7 +65,9 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ {
+ private:
+ crow::async_resolve::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_static_buffer<httpReadBodyLimit> buffer;
+ boost::beast::http::request<boost::beast::http::string_body> req;
+@@ -110,25 +115,52 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ const std::vector<boost::asio::ip::tcp::endpoint>& endpointList)
+ {
+ state = ConnState::connectInProgress;
++ sslConn.emplace(conn, ctx);
+
+ BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port;
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const boost::asio::ip::tcp::endpoint& endpoint) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Connect " << endpoint
++ << " failed: " << ec.message();
++ self->state = ConnState::connectFailed;
++ self->handleConnState();
++ return;
++ }
+
++ BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
++ if (self->sslConn)
++ {
++ self->performHandshake();
++ }
++ else
++ {
++ self->handleConnState();
++ }
++ };
+ conn.expires_after(std::chrono::seconds(30));
+- conn.async_connect(
+- endpointList, [self(shared_from_this())](
+- const boost::beast::error_code ec,
+- const boost::asio::ip::tcp::endpoint& endpoint) {
++ conn.async_connect(endpointList, std::move(respHandler));
++ }
++
++ void performHandshake()
++ {
++ state = ConnState::handshakeInProgress;
++
++ sslConn->async_handshake(
++ boost::asio::ssl::stream_base::client,
++ [self(shared_from_this())](const boost::beast::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "Connect "
+- << endpoint.address().to_string()
+- << " failed: " << ec.message();
+- self->state = ConnState::connectFailed;
++ BMCWEB_LOG_ERROR << "SSL handshake failed: "
++ << ec.message();
++ self->state = ConnState::handshakeFailed;
+ self->handleConnState();
+ return;
+ }
+- BMCWEB_LOG_DEBUG << "Connected to: "
+- << endpoint.address().to_string();
++
++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull";
+ self->state = ConnState::connected;
+ self->handleConnState();
+ });
+@@ -141,124 +173,182 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ 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->state = ConnState::sendFailed;
++ self->handleConnState();
++ return;
++ }
+
+- // 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->handleConnState();
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
+- << bytesTransferred;
+- boost::ignore_unused(bytesTransferred);
++ BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
++ << bytesTransferred;
++ boost::ignore_unused(bytesTransferred);
++ self->recvMessage();
++ };
+
+- self->recvMessage();
+- });
++ // Set a timeout on the operation
++ 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()
+ {
+ state = ConnState::recvInProgress;
+
+- parser.emplace(std::piecewise_construct, std::make_tuple());
+- parser->body_limit(httpReadBodyLimit);
++ auto respHandler = [self(shared_from_this())](
++ const boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ if (ec && ec != boost::asio::ssl::error::stream_truncated)
++ {
++ BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message();
+
+- // Receive the HTTP response
+- boost::beast::http::async_read(
+- conn, buffer, *parser,
+- [self(shared_from_this())](const boost::beast::error_code& ec,
+- const std::size_t& bytesTransferred) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "recvMessage() failed: "
+- << ec.message();
+- self->state = ConnState::recvFailed;
+- self->handleConnState();
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
+- << bytesTransferred;
+- BMCWEB_LOG_DEBUG << "recvMessage() data: "
+- << self->parser->get().body();
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
+
+- // Check if the response and header are received
+- if (!self->parser->is_done())
+- {
+- // The parser failed to receive the response
+- BMCWEB_LOG_ERROR
+- << "recvMessage() parser failed to receive response";
+- self->state = ConnState::recvFailed;
+- self->handleConnState();
+- return;
+- }
++ BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
++ << bytesTransferred;
++ boost::ignore_unused(bytesTransferred);
++
++ // Check if the response and header are received
++ if (!self->parser->is_done())
++ {
++ // The parser failed to receive the response
++ BMCWEB_LOG_ERROR
++ << "recvMessage() parser failed to receive response";
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
+
+- unsigned int respCode = self->parser->get().result_int();
+- BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
+- << respCode;
++ unsigned int respCode = self->parser->get().result_int();
++ BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
++ << respCode;
+
+- // 2XX response is considered to be successful
+- if ((respCode < 200) || (respCode >= 300))
+- {
+- // The listener failed to receive the Sent-Event
+- BMCWEB_LOG_ERROR
+- << "recvMessage() Listener Failed to "
+- "receive Sent-Event. Header Response Code: "
+- << respCode;
+- self->state = ConnState::recvFailed;
+- self->handleConnState();
+- return;
+- }
++ // 2XX response is considered to be successful
++ if ((respCode < 200) || (respCode >= 300))
++ {
++ // The listener failed to receive the Sent-Event
++ BMCWEB_LOG_ERROR << "recvMessage() Listener Failed to "
++ "receive Sent-Event";
++ self->state = ConnState::recvFailed;
++ self->handleConnState();
++ return;
++ }
+
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- if (!self->requestDataQueue.empty())
+- {
+- self->requestDataQueue.pop_front();
+- }
+- self->state = ConnState::idle;
++ // Send is successful, Lets remove data from queue
++ // check for next request data in queue.
++ if (!self->requestDataQueue.empty())
++ {
++ self->requestDataQueue.pop_front();
++ }
++ self->state = ConnState::idle;
++ // Keep the connection alive if server supports it
++ // Else close the connection
++ BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
++ << self->parser->keep_alive();
++ if (!self->parser->keep_alive())
++ {
++ // Abort the connection since server is not keep-alive enabled
++ self->state = ConnState::abortConnection;
++ }
+
+- // Keep the connection alive if server supports it
+- // Else close the connection
+- BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
+- << self->parser->keep_alive();
+- if (!self->parser->keep_alive())
+- {
+- // Abort the connection since server is not keep-alive
+- // enabled
+- self->state = ConnState::abortConnection;
+- }
++ // Returns ownership of the parsed message
++ self->parser->release();
+
+- self->handleConnState();
+- });
+- }
++ self->handleConnState();
++ };
++ parser.emplace(std::piecewise_construct, std::make_tuple());
++ parser->body_limit(httpReadBodyLimit);
+
++ // Check only for the response header
++ parser->skip(true);
++ 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 doClose()
+ {
+ state = ConnState::closeInProgress;
+- boost::beast::error_code ec;
+- conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
+- conn.close();
+
+- // not_connected happens sometimes so don't bother reporting it.
+- if (ec && ec != boost::beast::errc::not_connected)
++ // Set the timeout on the tcp stream socket for the async operation
++ conn.expires_after(std::chrono::seconds(30));
++ if (sslConn)
+ {
+- BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message();
+- return;
++ sslConn->async_shutdown([self = shared_from_this()](
++ const boost::system::error_code ec) {
++ if (ec)
++ {
++ // 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_INFO << "doClose(): Connection "
++ "closed by server. ";
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "doClose() failed: "
++ << ec.message();
++ }
++ }
++ else
++ {
++ BMCWEB_LOG_DEBUG << "Connection closed gracefully...";
++ }
++ self->conn.close();
++
++ if ((self->state != ConnState::suspended) &&
++ (self->state != ConnState::terminated))
++ {
++ self->state = ConnState::closed;
++ self->handleConnState();
++ }
++ });
+ }
+- BMCWEB_LOG_DEBUG << "Connection closed gracefully";
+- if ((state != ConnState::suspended) && (state != ConnState::terminated))
++ else
+ {
+- state = ConnState::closed;
+- handleConnState();
++ boost::beast::error_code ec;
++ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
++ ec);
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "doClose() failed: " << ec.message();
++ }
++ else
++ {
++ BMCWEB_LOG_DEBUG << "Connection closed gracefully...";
++ }
++ conn.close();
++
++ if ((state != ConnState::suspended) &&
++ (state != ConnState::terminated))
++ {
++ state = ConnState::closed;
++ handleConnState();
++ }
+ }
+ }
+
+@@ -330,6 +420,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ {
+ case ConnState::resolveInProgress:
+ case ConnState::connectInProgress:
++ case ConnState::handshakeInProgress:
+ case ConnState::sendInProgress:
+ case ConnState::recvInProgress:
+ case ConnState::closeInProgress:
+@@ -356,6 +447,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ case ConnState::resolveFailed:
+ case ConnState::connectFailed:
++ case ConnState::handshakeFailed:
+ case ConnState::sendFailed:
+ case ConnState::recvFailed:
+ case ConnState::retry:
+@@ -392,7 +484,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ public:
+ explicit HttpClient(boost::asio::io_context& ioc, const std::string& id,
+ const std::string& destIP, const std::string& destPort,
+- const std::string& destUri) :
++ const std::string& destUri,
++ const std::string& uriProto) :
+ conn(ioc),
+ timer(ioc), req(boost::beast::http::verb::post, destUri, 11), subId(id),
+ host(destIP), port(destPort)
+@@ -403,6 +496,10 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ req.keep_alive(true);
+
+ requestDataQueue.set_capacity(maxRequestQueueSize);
++ if (uriProto == "https")
++ {
++ sslConn.emplace(conn, ctx);
++ }
+ }
+
+ void sendData(const std::string& data)
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index bc97219..64cb43a 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -372,7 +372,7 @@ class Subscription : public persistent_data::UserSubscription
+ // create the HttpClient connection
+ conn = std::make_shared<crow::HttpClient>(
+ crow::connections::systemBus->get_io_context(), id, host, port,
+- path);
++ path, uriProto);
+ }
+
+ Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch
new file mode 100644
index 000000000..bce9fc939
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch
@@ -0,0 +1,471 @@
+From 6134487ccc46ace1943184f40c42184e3aa85881 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Fri, 12 Mar 2021 18:53:25 +0000
+Subject: [PATCH] Add Server-Sent-Events support
+
+Server-Sent Events is a standard describing how servers can
+initiate data transmission towards clients once an initial
+client connection has been established. Unlike websockets
+(which are bidirectional), Server-Sent Events are
+unidirectional and commonly used to send message updates or
+continuous data streams to a browser client.
+
+This is base patch for adding Server-Sent events support to
+bmcweb. Redfish eventservice SSE style subscription uses
+this and will be loaded on top of this commit.
+
+Tested:
+ - Tested using follow-up patch on top which adds
+ support for Redfish EventService SSE style subscription
+ and observed events are getting sent periodically.
+
+Change-Id: I36956565cbba30c2007852c9471f477f6d1736e9
+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_connection.hpp | 10 +-
+ http/http_response.hpp | 7 +-
+ http/routing.hpp | 71 ++++++++++
+ http/server_sent_event.hpp | 282 +++++++++++++++++++++++++++++++++++++
+ 4 files changed, 365 insertions(+), 5 deletions(-)
+ create mode 100644 http/server_sent_event.hpp
+
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index a27ec26..882a7a6 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -374,11 +374,13 @@ class Connection :
+ self->completeRequest(thisRes);
+ });
+
+- if (thisReq.isUpgrade() &&
+- boost::iequals(
+- thisReq.getHeaderValue(boost::beast::http::field::upgrade),
+- "websocket"))
++ if ((thisReq.isUpgrade() &&
++ boost::iequals(
++ thisReq.getHeaderValue(boost::beast::http::field::upgrade),
++ "websocket")) ||
++ (req->url == "/sse"))
+ {
++ BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded";
+ handler->handleUpgrade(thisReq, res, std::move(adaptor));
+ // delete lambda with self shared_ptr
+ // to enable connection destruction
+diff --git a/http/http_response.hpp b/http/http_response.hpp
+index 3c2a3f9..679dab2 100644
+--- a/http/http_response.hpp
++++ b/http/http_response.hpp
+@@ -15,10 +15,15 @@ namespace crow
+ template <typename Adaptor, typename Handler>
+ class Connection;
+
++template <typename Adaptor>
++class SseConnectionImpl;
++
+ struct Response
+ {
+ template <typename Adaptor, typename Handler>
+ friend class crow::Connection;
++ template <typename Adaptor>
++ friend class crow::SseConnectionImpl;
+ using response_type =
+ boost::beast::http::response<boost::beast::http::string_body>;
+
+@@ -173,8 +178,8 @@ struct Response
+
+ private:
+ bool completed = false;
+- std::function<void(Response&)> completeRequestHandler;
+ std::function<bool()> isAliveHelper;
++ std::function<void(Response&)> completeRequestHandler;
+
+ // In case of a JSON object, set the Content-Type header
+ void jsonMode()
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 250cd33..552e1cf 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -7,6 +7,7 @@
+ #include "http_response.hpp"
+ #include "logging.hpp"
+ #include "privileges.hpp"
++#include "server_sent_event.hpp"
+ #include "sessions.hpp"
+ #include "utility.hpp"
+ #include "websocket.hpp"
+@@ -407,6 +408,68 @@ class WebSocketRule : public BaseRule
+ std::function<void(crow::websocket::Connection&)> errorHandler;
+ };
+
++class SseSocketRule : public BaseRule
++{
++ using self_t = SseSocketRule;
++
++ public:
++ SseSocketRule(const std::string& ruleIn) : BaseRule(ruleIn)
++ {}
++
++ void validate() override
++ {}
++
++ void handle(const Request&,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const RoutingParams&) override
++ {
++ asyncResp->res.result(boost::beast::http::status::not_found);
++ }
++
++ void handleUpgrade(const Request& req, Response&,
++ boost::asio::ip::tcp::socket&& adaptor) override
++ {
++ std::shared_ptr<crow::SseConnectionImpl<boost::asio::ip::tcp::socket>>
++ myConnection = std::make_shared<
++ crow::SseConnectionImpl<boost::asio::ip::tcp::socket>>(
++ req, std::move(adaptor), openHandler, closeHandler);
++ myConnection->start();
++ }
++#ifdef BMCWEB_ENABLE_SSL
++ void handleUpgrade(const Request& req, Response&,
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
++ adaptor) override
++ {
++ std::shared_ptr<crow::SseConnectionImpl<
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>
++ myConnection = std::make_shared<crow::SseConnectionImpl<
++ boost::beast::ssl_stream<boost::asio::ip::tcp::socket>>>(
++ req, std::move(adaptor), openHandler, closeHandler);
++ myConnection->start();
++ }
++#endif
++
++ template <typename Func>
++ self_t& onopen(Func f)
++ {
++ openHandler = f;
++ return *this;
++ }
++
++ template <typename Func>
++ self_t& onclose(Func f)
++ {
++ closeHandler = f;
++ return *this;
++ }
++
++ private:
++ std::function<void(std::shared_ptr<crow::SseConnection>&,
++ const crow::Request&, crow::Response&)>
++ openHandler;
++ std::function<void(std::shared_ptr<crow::SseConnection>&)> closeHandler;
++};
++
+ template <typename T>
+ struct RuleParameterTraits
+ {
+@@ -419,6 +482,14 @@ struct RuleParameterTraits
+ return *p;
+ }
+
++ SseSocketRule& serverSentEvent()
++ {
++ self_t* self = static_cast<self_t*>(this);
++ SseSocketRule* p = new SseSocketRule(self->rule);
++ self->ruleToUpgrade.reset(p);
++ return *p;
++ }
++
+ self_t& name(const std::string_view name) noexcept
+ {
+ self_t* self = static_cast<self_t*>(this);
+diff --git a/http/server_sent_event.hpp b/http/server_sent_event.hpp
+new file mode 100644
+index 0000000..41d18ed
+--- /dev/null
++++ b/http/server_sent_event.hpp
+@@ -0,0 +1,282 @@
++#pragma once
++#include "http_request.hpp"
++
++#include <boost/algorithm/string/predicate.hpp>
++#include <boost/asio/buffer.hpp>
++#include <boost/beast/http/buffer_body.hpp>
++#include <boost/beast/websocket.hpp>
++
++#include <array>
++#include <functional>
++
++#ifdef BMCWEB_ENABLE_SSL
++#include <boost/beast/websocket/ssl.hpp>
++#endif
++
++namespace crow
++{
++
++struct SseConnection : std::enable_shared_from_this<SseConnection>
++{
++ public:
++ SseConnection(const crow::Request& reqIn) : req(reqIn)
++ {}
++ virtual ~SseConnection() = default;
++
++ virtual boost::asio::io_context& getIoContext() = 0;
++ virtual void sendSSEHeader() = 0;
++ virtual void completeRequest() = 0;
++ virtual void close(const std::string_view msg = "quit") = 0;
++ virtual void sendEvent(const std::string_view id,
++ const std::string_view msg) = 0;
++
++ crow::Request req;
++ crow::Response res;
++};
++
++template <typename Adaptor>
++class SseConnectionImpl : public SseConnection
++{
++ public:
++ SseConnectionImpl(
++ const crow::Request& reqIn, Adaptor adaptorIn,
++ std::function<void(std::shared_ptr<SseConnection>&,
++ const crow::Request&, crow::Response&)>
++ openHandler,
++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler) :
++ SseConnection(reqIn),
++ adaptor(std::move(adaptorIn)), openHandler(std::move(openHandler)),
++ closeHandler(std::move(closeHandler))
++ {
++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE constructor " << this;
++ }
++
++ ~SseConnectionImpl() override
++ {
++ res.setCompleteRequestHandler(nullptr);
++ BMCWEB_LOG_DEBUG << "SseConnectionImpl: SSE destructor " << this;
++ }
++
++ boost::asio::io_context& getIoContext() override
++ {
++ return static_cast<boost::asio::io_context&>(
++ adaptor.get_executor().context());
++ }
++
++ void start()
++ {
++ // Register for completion callback.
++ res.setCompleteRequestHandler([this, self(shared_from_this())](
++ crow::Response& thisRes) {
++ boost::ignore_unused(thisRes);
++ boost::asio::post(this->adaptor.get_executor(), [self] {
++ self->completeRequest();
++ });
++ });
++
++ if (openHandler)
++ {
++ std::shared_ptr<SseConnection> self = this->shared_from_this();
++ openHandler(self, req, res);
++ }
++ }
++
++ void close(const std::string_view msg) override
++ {
++ BMCWEB_LOG_DEBUG << "Closing SSE connection " << this << " - " << msg;
++ boost::beast::get_lowest_layer(adaptor).close();
++
++ // send notification to handler for cleanup
++ if (closeHandler)
++ {
++ std::shared_ptr<SseConnection> self = this->shared_from_this();
++ closeHandler(self);
++ }
++ }
++
++ void sendSSEHeader() override
++ {
++ BMCWEB_LOG_DEBUG << "Starting SSE connection";
++ using BodyType = boost::beast::http::buffer_body;
++ auto response =
++ std::make_shared<boost::beast::http::response<BodyType>>(
++ boost::beast::http::status::ok, 11);
++ auto serializer =
++ std::make_shared<boost::beast::http::response_serializer<BodyType>>(
++ *response);
++
++ response->set(boost::beast::http::field::server, "bmcweb");
++ response->set(boost::beast::http::field::content_type,
++ "text/event-stream");
++ response->body().data = nullptr;
++ response->body().size = 0;
++ response->body().more = true;
++
++ boost::beast::http::async_write_header(
++ adaptor, *serializer,
++ [this, self(shared_from_this()), response, serializer](
++ const boost::beast::error_code& ec, const std::size_t&) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Error sending header" << ec;
++ close("async_write_header failed");
++ return;
++ }
++ BMCWEB_LOG_DEBUG << "SSE header sent - Connection established";
++
++ // SSE stream header sent, So lets setup monitor.
++ // Any read data on this stream will be error in case of SSE.
++ setupRead();
++ });
++ }
++
++ void setupRead()
++ {
++ adaptor.async_read_some(
++ outputBuffer.prepare(outputBuffer.capacity() - outputBuffer.size()),
++ [this](const boost::system::error_code& ec, std::size_t bytesRead) {
++ BMCWEB_LOG_DEBUG << "async_read_some: Read " << bytesRead
++ << " bytes";
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "Read error: " << ec;
++ }
++ outputBuffer.commit(bytesRead);
++ outputBuffer.consume(bytesRead);
++
++ // After establishing SSE stream, Reading data on this
++ // stream means client is disobeys the SSE protocol.
++ // Read the data to avoid buffer attacks and close connection.
++ close("Close SSE connection");
++ return;
++ });
++ }
++
++ void doWrite()
++ {
++ if (doingWrite)
++ {
++ return;
++ }
++ if (inputBuffer.size() == 0)
++ {
++ BMCWEB_LOG_DEBUG << "inputBuffer is empty... Bailing out";
++ return;
++ }
++ doingWrite = true;
++
++ adaptor.async_write_some(
++ inputBuffer.data(), [this, self(shared_from_this())](
++ boost::beast::error_code ec,
++ const std::size_t& bytesTransferred) {
++ doingWrite = false;
++ inputBuffer.consume(bytesTransferred);
++
++ if (ec == boost::asio::error::eof)
++ {
++ BMCWEB_LOG_ERROR << "async_write_some() SSE stream closed";
++ close("SSE stream closed");
++ return;
++ }
++
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "async_write_some() failed: "
++ << ec.message();
++ close("async_write_some failed");
++ return;
++ }
++ BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: "
++ << bytesTransferred;
++
++ doWrite();
++ });
++ }
++
++ void completeRequest() override
++ {
++ BMCWEB_LOG_DEBUG << "SSE completeRequest() handler";
++ if (res.body().empty() && !res.jsonValue.empty())
++ {
++ res.addHeader("Content-Type", "application/json");
++ res.body() = res.jsonValue.dump(
++ 2, ' ', true, nlohmann::json::error_handler_t::replace);
++ }
++
++ res.preparePayload();
++ auto serializer =
++ std::make_shared<boost::beast::http::response_serializer<
++ boost::beast::http::string_body>>(*res.stringResponse);
++
++ boost::beast::http::async_write(
++ adaptor, *serializer,
++ [this, self(shared_from_this()),
++ serializer](const boost::system::error_code& ec,
++ std::size_t bytesTransferred) {
++ BMCWEB_LOG_DEBUG << this << " async_write " << bytesTransferred
++ << " bytes";
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << this << " from async_write failed";
++ return;
++ }
++ res.clear();
++
++ BMCWEB_LOG_DEBUG << this
++ << " Closing SSE connection - Request invalid";
++ close("Request invalid");
++ });
++
++ // delete lambda with self shared_ptr
++ // to enable connection destruction
++ res.setCompleteRequestHandler(nullptr);
++ }
++
++ void sendEvent(const std::string_view id,
++ const std::string_view msg) override
++ {
++ if (msg.empty())
++ {
++ BMCWEB_LOG_DEBUG << "Empty data, bailing out.";
++ return;
++ }
++
++ std::string rawData;
++ if (!id.empty())
++ {
++ rawData += "id: ";
++ rawData.append(id.begin(), id.end());
++ rawData += "\n";
++ }
++
++ rawData += "data: ";
++ for (char character : msg)
++ {
++ rawData += character;
++ if (character == '\n')
++ {
++ rawData += "data: ";
++ }
++ }
++ rawData += "\n\n";
++
++ boost::asio::buffer_copy(inputBuffer.prepare(rawData.size()),
++ boost::asio::buffer(rawData));
++ inputBuffer.commit(rawData.size());
++
++ doWrite();
++ }
++
++ private:
++ Adaptor adaptor;
++
++ boost::beast::flat_static_buffer<1024U * 8U> outputBuffer;
++ boost::beast::flat_static_buffer<1024U * 64U> inputBuffer;
++ bool doingWrite = false;
++
++ std::function<void(std::shared_ptr<SseConnection>&, const crow::Request&,
++ crow::Response&)>
++ openHandler;
++ std::function<void(std::shared_ptr<SseConnection>&)> closeHandler;
++};
++} // namespace crow
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch
new file mode 100644
index 000000000..40b46e74a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch
@@ -0,0 +1,677 @@
+From 30088cc01b8068419311b171dc51c8ff11fbc185 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Tue, 16 Mar 2021 15:37:24 +0000
+Subject: [PATCH] Add SSE style subscription support to eventservice
+
+This commit adds the SSE style eventservice subscription
+style event. Using this, end user can subscribe for
+Redfish event logs using GET on SSE usri from
+browser.
+URI: /redfish/v1/EventService/Subscriptions/SSE
+
+Tested:
+ - From Browser did GET on above SSE URI and
+ generated some Redfish event logs(power cycle)
+ and saw redfish event logs streaming on browser.
+ - After SSE registration, Check Subscription collections
+ and GET on individual subscription and saw desired
+ response.
+ - Ran RedfishValidation and its passed.
+
+Change-Id: I7f4b7a34974080739c4ba968ed570489af0474de
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_connection.hpp | 2 +-
+ include/eventservice_sse.hpp | 75 +++++
+ .../include/event_service_manager.hpp | 111 +++++--
+ redfish-core/include/server_sent_events.hpp | 286 ------------------
+ redfish-core/lib/event_service.hpp | 8 +-
+ src/webserver_main.cpp | 2 +
+ 6 files changed, 165 insertions(+), 319 deletions(-)
+ create mode 100644 include/eventservice_sse.hpp
+ delete mode 100644 redfish-core/include/server_sent_events.hpp
+
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index 9986e07..0b7b341 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -379,7 +379,7 @@ class Connection :
+ boost::iequals(
+ thisReq.getHeaderValue(boost::beast::http::field::upgrade),
+ "websocket")) ||
+- (req->url == "/sse"))
++ (req->url == "/redfish/v1/EventService/Subscriptions/SSE"))
+ {
+ BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded";
+ handler->handleUpgrade(thisReq, res, std::move(adaptor));
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+new file mode 100644
+index 0000000..14daf00
+--- /dev/null
++++ b/include/eventservice_sse.hpp
+@@ -0,0 +1,75 @@
++#pragma once
++
++#include <app.hpp>
++#include <event_service_manager.hpp>
++
++namespace redfish
++{
++namespace eventservice_sse
++{
++
++static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn,
++ const crow::Request& req, crow::Response& res)
++{
++ if ((EventServiceManager::getInstance().getNumberOfSubscriptions() >=
++ maxNoOfSubscriptions) ||
++ EventServiceManager::getInstance().getNumberOfSSESubscriptions() >=
++ maxNoOfSSESubscriptions)
++ {
++ BMCWEB_LOG_ERROR << "Max SSE subscriptions reached";
++ messages::eventSubscriptionLimitExceeded(res);
++ res.end();
++ return false;
++ }
++ BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size();
++
++ std::shared_ptr<redfish::Subscription> subValue =
++ std::make_shared<redfish::Subscription>(std::move(conn));
++
++ // GET on this URI means, Its SSE subscriptionType.
++ subValue->subscriptionType = redfish::subscriptionTypeSSE;
++
++ // TODO: parse $filter query params and fill config.
++ subValue->protocol = "Redfish";
++ subValue->retryPolicy = "TerminateAfterRetries";
++ subValue->eventFormatType = "Event";
++
++ std::string id =
++ redfish::EventServiceManager::getInstance().addSubscription(subValue,
++ false);
++ if (id.empty())
++ {
++ messages::internalError(res);
++ res.end();
++ return false;
++ }
++
++ return true;
++}
++
++static void deleteSubscription(std::shared_ptr<crow::SseConnection>& conn)
++{
++ redfish::EventServiceManager::getInstance().deleteSubscription(conn);
++}
++
++inline void requestRoutes(App& app)
++{
++ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/SSE")
++ .privileges({{"ConfigureComponents", "ConfigureManager"}})
++ .serverSentEvent()
++ .onopen([](std::shared_ptr<crow::SseConnection>& conn,
++ const crow::Request& req, crow::Response& res) {
++ BMCWEB_LOG_DEBUG << "Connection " << conn << " opened.";
++ if (createSubscription(conn, req, res))
++ {
++ // All success, lets send SSE haader
++ conn->sendSSEHeader();
++ }
++ })
++ .onclose([](std::shared_ptr<crow::SseConnection>& conn) {
++ BMCWEB_LOG_DEBUG << "Connection " << conn << " closed";
++ deleteSubscription(conn);
++ });
++}
++} // namespace eventservice_sse
++} // namespace redfish
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 64cb43a..c64bb59 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -23,6 +23,7 @@
+ #include <sys/inotify.h>
+
+ #include <boost/asio/io_context.hpp>
++#include <boost/beast/core/span.hpp>
+ #include <boost/container/flat_map.hpp>
+ #include <dbus_utility.hpp>
+ #include <error_messages.hpp>
+@@ -30,9 +31,10 @@
+ #include <http_client.hpp>
+ #include <persistent_data.hpp>
+ #include <random.hpp>
+-#include <server_sent_events.hpp>
++#include <server_sent_event.hpp>
+ #include <utils/json_utils.hpp>
+
++#include <algorithm>
+ #include <cstdlib>
+ #include <ctime>
+ #include <fstream>
+@@ -48,9 +50,27 @@ using ReadingsObjType =
+ static constexpr const char* eventFormatType = "Event";
+ static constexpr const char* metricReportFormatType = "MetricReport";
+
++static constexpr const char* subscriptionTypeSSE = "SSE";
+ static constexpr const char* eventServiceFile =
+ "/var/lib/bmcweb/eventservice_config.json";
+
++static constexpr const uint8_t maxNoOfSubscriptions = 20;
++static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
++
++#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
++static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
++static constexpr const char* redfishEventLogDir = "/var/log";
++static constexpr const char* redfishEventLogFile = "/var/log/redfish";
++static constexpr const size_t iEventSize = sizeof(inotify_event);
++static int inotifyFd = -1;
++static int dirWatchDesc = -1;
++static int fileWatchDesc = -1;
++
++// <ID, timestamp, RedfishLogId, registryPrefix, MessageId, MessageArgs>
++using EventLogObjectsType =
++ std::tuple<std::string, std::string, std::string, std::string, std::string,
++ std::vector<std::string>>;
++
+ namespace registries
+ {
+ inline std::span<const MessageEntry>
+@@ -70,24 +90,6 @@ inline std::span<const MessageEntry>
+ }
+ return {openbmc::registry};
+ }
+-} // namespace registries
+-
+-#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+-static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
+-static constexpr const char* redfishEventLogDir = "/var/log";
+-static constexpr const char* redfishEventLogFile = "/var/log/redfish";
+-static constexpr const size_t iEventSize = sizeof(inotify_event);
+-static int inotifyFd = -1;
+-static int dirWatchDesc = -1;
+-static int fileWatchDesc = -1;
+-
+-// <ID, timestamp, RedfishLogId, registryPrefix, MessageId, MessageArgs>
+-using EventLogObjectsType =
+- std::tuple<std::string, std::string, std::string, std::string, std::string,
+- std::vector<std::string>>;
+-
+-namespace registries
+-{
+ static const Message*
+ getMsgFromRegistry(const std::string& messageKey,
+ const std::span<const MessageEntry>& registry)
+@@ -375,11 +377,9 @@ class Subscription : public persistent_data::UserSubscription
+ path, uriProto);
+ }
+
+- Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+- eventSeqNum(1)
+- {
+- sseConn = std::make_shared<crow::ServerSentEvents>(adaptor);
+- }
++ Subscription(const std::shared_ptr<crow::SseConnection>& adaptor) :
++ sseConn(adaptor), eventSeqNum(1)
++ {}
+
+ ~Subscription() = default;
+
+@@ -396,13 +396,14 @@ class Subscription : public persistent_data::UserSubscription
+ if (conn != nullptr)
+ {
+ conn->sendData(msg);
+- eventSeqNum++;
+ }
+
+ if (sseConn != nullptr)
+ {
+- sseConn->sendData(eventSeqNum, msg);
++ sseConn->sendEvent(std::to_string(eventSeqNum), msg);
+ }
++
++ eventSeqNum++;
+ return true;
+ }
+
+@@ -558,14 +559,39 @@ class Subscription : public persistent_data::UserSubscription
+ return eventSeqNum;
+ }
+
++ void setSubscriptionId(const std::string& id)
++ {
++ BMCWEB_LOG_DEBUG << "Subscription ID: " << id;
++ subId = id;
++ }
++
++ std::string getSubscriptionId()
++ {
++ return subId;
++ }
++
++ std::optional<std::string>
++ getSubscriptionId(const std::shared_ptr<crow::SseConnection>& connPtr)
++ {
++ if (sseConn != nullptr && connPtr == sseConn)
++ {
++ BMCWEB_LOG_DEBUG << __FUNCTION__
++ << " conn matched, subId: " << subId;
++ return subId;
++ }
++
++ return std::nullopt;
++ }
++
+ private:
++ std::shared_ptr<crow::SseConnection> sseConn = nullptr;
+ uint64_t eventSeqNum;
+ std::string host;
+ std::string port;
+ std::string path;
+ std::string uriProto;
+ std::shared_ptr<crow::HttpClient> conn = nullptr;
+- std::shared_ptr<crow::ServerSentEvents> sseConn = nullptr;
++ std::string subId;
+ };
+
+ class EventServiceManager
+@@ -923,6 +949,8 @@ class EventServiceManager
+ subValue->updateRetryPolicy();
+ subValue->updatehttpHeaders();
+
++ // Set Subscription ID for back trace
++ subValue->setSubscriptionId(id);
+ return id;
+ }
+
+@@ -947,11 +975,40 @@ class EventServiceManager
+ }
+ }
+
++ void deleteSubscription(const std::shared_ptr<crow::SseConnection>& connPtr)
++ {
++ for (const auto& it : this->subscriptionsMap)
++ {
++ std::shared_ptr<Subscription> entry = it.second;
++ if (entry->subscriptionType == subscriptionTypeSSE)
++ {
++ std::optional<std::string> id =
++ entry->getSubscriptionId(connPtr);
++ if (id)
++ {
++ deleteSubscription(*id);
++ return;
++ }
++ }
++ }
++ }
++
+ size_t getNumberOfSubscriptions()
+ {
+ return subscriptionsMap.size();
+ }
+
++ size_t getNumberOfSSESubscriptions() const
++ {
++ auto count = std::count_if(
++ subscriptionsMap.begin(), subscriptionsMap.end(),
++ [this](const std::pair<std::string, std::shared_ptr<Subscription>>&
++ entry) {
++ return (entry.second->subscriptionType == subscriptionTypeSSE);
++ });
++ return static_cast<size_t>(count);
++ }
++
+ std::vector<std::string> getAllIDs()
+ {
+ std::vector<std::string> idList;
+diff --git a/redfish-core/include/server_sent_events.hpp b/redfish-core/include/server_sent_events.hpp
+deleted file mode 100644
+index 13840d3..0000000
+--- a/redfish-core/include/server_sent_events.hpp
++++ /dev/null
+@@ -1,286 +0,0 @@
+-
+-/*
+-// Copyright (c) 2020 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 <boost/asio/strand.hpp>
+-#include <boost/beast/http/buffer_body.hpp>
+-#include <boost/beast/http/message.hpp>
+-#include <boost/beast/version.hpp>
+-
+-#include <cstdlib>
+-#include <functional>
+-#include <iostream>
+-#include <memory>
+-#include <queue>
+-#include <string>
+-
+-namespace crow
+-{
+-
+-static constexpr uint8_t maxReqQueueSize = 50;
+-
+-enum class SseConnState
+-{
+- startInit,
+- initInProgress,
+- initialized,
+- initFailed,
+- sendInProgress,
+- sendFailed,
+- idle,
+- suspended,
+- closed
+-};
+-
+-class ServerSentEvents : public std::enable_shared_from_this<ServerSentEvents>
+-{
+- private:
+- std::shared_ptr<boost::beast::tcp_stream> sseConn;
+- std::queue<std::pair<uint64_t, std::string>> requestDataQueue;
+- std::string outBuffer;
+- SseConnState state{SseConnState::startInit};
+- int retryCount{0};
+- int maxRetryAttempts{5};
+-
+- void sendEvent(const std::string& id, const std::string& msg)
+- {
+- if (msg.empty())
+- {
+- BMCWEB_LOG_DEBUG << "Empty data, bailing out.";
+- return;
+- }
+-
+- if (state == SseConnState::sendInProgress)
+- {
+- return;
+- }
+- state = SseConnState::sendInProgress;
+-
+- if (!id.empty())
+- {
+- outBuffer += "id: ";
+- outBuffer.append(id.begin(), id.end());
+- outBuffer += "\n";
+- }
+-
+- outBuffer += "data: ";
+- for (char character : msg)
+- {
+- outBuffer += character;
+- if (character == '\n')
+- {
+- outBuffer += "data: ";
+- }
+- }
+- outBuffer += "\n\n";
+-
+- doWrite();
+- }
+-
+- void doWrite()
+- {
+- if (outBuffer.empty())
+- {
+- BMCWEB_LOG_DEBUG << "All data sent successfully.";
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- requestDataQueue.pop();
+- state = SseConnState::idle;
+- checkQueue();
+- return;
+- }
+-
+- sseConn->async_write_some(
+- boost::asio::buffer(outBuffer.data(), outBuffer.size()),
+- [self(shared_from_this())](
+- boost::beast::error_code ec,
+- [[maybe_unused]] const std::size_t& bytesTransferred) {
+- self->outBuffer.erase(0, bytesTransferred);
+-
+- if (ec == boost::asio::error::eof)
+- {
+- // Send is successful, Lets remove data from queue
+- // check for next request data in queue.
+- self->requestDataQueue.pop();
+- self->state = SseConnState::idle;
+- self->checkQueue();
+- return;
+- }
+-
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "async_write_some() failed: "
+- << ec.message();
+- self->state = SseConnState::sendFailed;
+- self->checkQueue();
+- return;
+- }
+- BMCWEB_LOG_DEBUG << "async_write_some() bytes transferred: "
+- << bytesTransferred;
+-
+- self->doWrite();
+- });
+- }
+-
+- void startSSE()
+- {
+- if (state == SseConnState::initInProgress)
+- {
+- return;
+- }
+- state = SseConnState::initInProgress;
+-
+- BMCWEB_LOG_DEBUG << "starting SSE connection ";
+- using BodyType = boost::beast::http::buffer_body;
+- auto response =
+- std::make_shared<boost::beast::http::response<BodyType>>(
+- boost::beast::http::status::ok, 11);
+- auto serializer =
+- std::make_shared<boost::beast::http::response_serializer<BodyType>>(
+- *response);
+-
+- // TODO: Add hostname in http header.
+- response->set(boost::beast::http::field::server, "iBMC");
+- response->set(boost::beast::http::field::content_type,
+- "text/event-stream");
+- response->body().data = nullptr;
+- response->body().size = 0;
+- response->body().more = true;
+-
+- boost::beast::http::async_write_header(
+- *sseConn, *serializer,
+- [this, response,
+- serializer](const boost::beast::error_code& ec,
+- [[maybe_unused]] const std::size_t& bytesTransferred) {
+- if (ec)
+- {
+- BMCWEB_LOG_ERROR << "Error sending header" << ec;
+- state = SseConnState::initFailed;
+- checkQueue();
+- return;
+- }
+-
+- BMCWEB_LOG_DEBUG << "startSSE Header sent.";
+- state = SseConnState::initialized;
+- checkQueue();
+- });
+- }
+-
+- void checkQueue(const bool newRecord = false)
+- {
+- if (requestDataQueue.empty())
+- {
+- BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n";
+- return;
+- }
+-
+- if (retryCount >= maxRetryAttempts)
+- {
+- BMCWEB_LOG_ERROR << "Maximum number of retries is reached.";
+-
+- // Clear queue.
+- while (!requestDataQueue.empty())
+- {
+- requestDataQueue.pop();
+- }
+-
+- // TODO: Take 'DeliveryRetryPolicy' action.
+- // For now, doing 'SuspendRetries' action.
+- state = SseConnState::suspended;
+- return;
+- }
+-
+- if ((state == SseConnState::initFailed) ||
+- (state == SseConnState::sendFailed))
+- {
+- if (newRecord)
+- {
+- // We are already running async wait and retry.
+- // Since record is added to queue, it gets the
+- // turn in FIFO.
+- return;
+- }
+-
+- retryCount++;
+- // TODO: Perform async wait for retryTimeoutInterval before proceed.
+- }
+- else
+- {
+- // reset retry count.
+- retryCount = 0;
+- }
+-
+- switch (state)
+- {
+- case SseConnState::initInProgress:
+- case SseConnState::sendInProgress:
+- case SseConnState::suspended:
+- case SseConnState::startInit:
+- case SseConnState::closed:
+- // do nothing
+- break;
+- case SseConnState::initFailed:
+- {
+- startSSE();
+- break;
+- }
+- case SseConnState::initialized:
+- case SseConnState::idle:
+- case SseConnState::sendFailed:
+- {
+- std::pair<uint64_t, std::string> reqData =
+- requestDataQueue.front();
+- sendEvent(std::to_string(reqData.first), reqData.second);
+- break;
+- }
+- }
+- }
+-
+- public:
+- ServerSentEvents(const ServerSentEvents&) = delete;
+- ServerSentEvents& operator=(const ServerSentEvents&) = delete;
+- ServerSentEvents(ServerSentEvents&&) = delete;
+- ServerSentEvents& operator=(ServerSentEvents&&) = delete;
+-
+- ServerSentEvents(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) :
+- sseConn(adaptor)
+- {
+- startSSE();
+- }
+-
+- ~ServerSentEvents() = default;
+-
+- void sendData(const uint64_t& id, const std::string& data)
+- {
+- if (state == SseConnState::suspended)
+- {
+- return;
+- }
+-
+- if (requestDataQueue.size() <= maxReqQueueSize)
+- {
+- requestDataQueue.push(std::pair(id, data));
+- checkQueue(true);
+- }
+- else
+- {
+- BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data.";
+- }
+- }
+-};
+-
+-} // namespace crow
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index c7392bd..2181346 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -40,8 +40,6 @@ static constexpr const std::array<const char*, 1> supportedResourceTypes = {
+ "Task"};
+ #endif
+
+-static constexpr const uint8_t maxNoOfSubscriptions = 20;
+-
+ inline void requestRoutesEventService(App& app)
+ {
+ BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
+@@ -54,6 +52,8 @@ inline void requestRoutesEventService(App& app)
+ {"@odata.type", "#EventService.v1_5_0.EventService"},
+ {"Id", "EventService"},
+ {"Name", "Event Service"},
++ {"ServerSentEventUri",
++ "/redfish/v1/EventService/Subscriptions/SSE"},
+ {"Subscriptions",
+ {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
+ {"Actions",
+@@ -92,9 +92,7 @@ inline void requestRoutesEventService(App& app)
+ .privileges(redfish::privileges::patchEventService)
+ .methods(boost::beast::http::verb::patch)(
+ [](const crow::Request& req,
+- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+-
+- {
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
+ std::optional<bool> serviceEnabled;
+ std::optional<uint32_t> retryAttemps;
+ std::optional<uint32_t> retryInterval;
+diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
+index 6bdce98..d8b4f4e 100644
+--- a/src/webserver_main.cpp
++++ b/src/webserver_main.cpp
+@@ -6,6 +6,7 @@
+ #include <cors_preflight.hpp>
+ #include <dbus_monitor.hpp>
+ #include <dbus_singleton.hpp>
++#include <eventservice_sse.hpp>
+ #include <google/google_service_root.hpp>
+ #include <hostname_monitor.hpp>
+ #include <ibm/management_console_rest.hpp>
+@@ -83,6 +84,7 @@ static int run()
+ #endif
+
+ #ifdef BMCWEB_ENABLE_REDFISH
++ redfish::eventservice_sse::requestRoutes(app);
+ redfish::requestRoutes(app);
+ redfish::RedfishService redfish(app);
+
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch
new file mode 100644
index 000000000..816456cec
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch
@@ -0,0 +1,326 @@
+From e207fca58bf0d05b160ea6735f4f576737d7a9cb Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Wed, 17 Mar 2021 01:16:50 +0000
+Subject: [PATCH] Add EventService SSE filter support
+
+This commit implements the Event Service SSE stream
+filters support. As per redfish specification:
+The SSE streams have these formats:
+ - Metric report SSE stream
+ - Event message SSE stream
+
+To reduce the amount of data, service supports $filter
+query parameter in SSE URI.
+Below properties support as filter criteria:
+ - EventFormatType( Event & MetricReport)
+ - MessageId
+ - RegistryPrefix
+ - MetricReportDefinition
+
+For more details, refer Redfish specification section 13.5.2
+
+Tested:
+ Created SSE stream with different filters and observed
+ desired events on SSE stream client(browser), some examples
+ - To get all Redfish events,
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event)
+ - To get Redfish events with RegistryPrefix "OpenBMC"
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(RegistryPrefix%20eq%20OpenBMC)
+ - To get only DC power of Events,
+ URI: /redfish/v1/EventService/Subscriptions/SSE?$filter=(EventFormatType%20eq%20Event)%20and%20(MessageId%20eq%20DCPowerOff)
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Change-Id: I55c6f53bb5e57aa1f2d1601f1a16525a33b13bd2
+---
+ include/eventservice_sse.hpp | 172 +++++++++++++++++-
+ redfish-core/include/error_messages.hpp | 9 +
+ .../include/event_service_manager.hpp | 5 +
+ redfish-core/lib/event_service.hpp | 5 -
+ redfish-core/src/error_messages.cpp | 27 +++
+ 5 files changed, 209 insertions(+), 9 deletions(-)
+
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+index 14daf00..5847766 100644
+--- a/include/eventservice_sse.hpp
++++ b/include/eventservice_sse.hpp
+@@ -21,18 +21,182 @@ static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn,
+ res.end();
+ return false;
+ }
++#ifdef NEW_BOOST_URL
++ BMCWEB_LOG_DEBUG << "Request query param size: "
++ << req.urlView.params().size();
++
++ // EventService SSE supports only "$filter" query param.
++ if (req.urlView.params().size() > 1)
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ std::string eventFormatType;
++ std::string queryFilters;
++ if (req.urlView.params().size())
++ {
++ boost::urls::params_view::iterator it =
++ req.urlView.params().find("$filter");
++ if (it == req.urlView.params().end())
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ queryFilters = std::string((*it).value);
++ }
++ else
++ {
++ eventFormatType = "Event";
++ }
++#else
+ BMCWEB_LOG_DEBUG << "Request query param size: " << req.urlParams.size();
+
++ // EventService SSE supports only "$filter" query param.
++ if (req.urlParams.size() > 1)
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ std::string eventFormatType;
++ std::string queryFilters;
++ if (req.urlParams.size())
++ {
++ boost::urls::query_params_view::iterator it =
++ req.urlParams.find("$filter");
++ if (it == req.urlParams.end())
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++ queryFilters = it->value();
++ }
++ else
++ {
++ eventFormatType = "Event";
++ }
++#endif
++
++ std::vector<std::string> msgIds;
++ std::vector<std::string> regPrefixes;
++ std::vector<std::string> mrdsArray;
++ if (!queryFilters.empty())
++ {
++ // Reading from query params.
++ bool status = readSSEQueryParams(queryFilters, eventFormatType, msgIds,
++ regPrefixes, mrdsArray);
++ if (!status)
++ {
++ messages::invalidQueryFilter(res);
++ res.end();
++ return false;
++ }
++
++ // RegsitryPrefix and messageIds are mutuly exclusive as per redfish
++ // specification.
++ if (!regPrefixes.empty() && !msgIds.empty())
++ {
++ messages::propertyValueConflict(res, "RegistryPrefix", "MessageId");
++ res.end();
++ return false;
++ }
++
++ if (!eventFormatType.empty())
++ {
++ if (std::find(supportedEvtFormatTypes.begin(),
++ supportedEvtFormatTypes.end(),
++ eventFormatType) == supportedEvtFormatTypes.end())
++ {
++ messages::propertyValueNotInList(res, eventFormatType,
++ "EventFormatType");
++ res.end();
++ return false;
++ }
++ }
++ else
++ {
++ // If nothing specified, using default "Event"
++ eventFormatType = "Event";
++ }
++
++ if (!regPrefixes.empty())
++ {
++ for (const std::string& it : regPrefixes)
++ {
++ if (std::find(supportedRegPrefixes.begin(),
++ supportedRegPrefixes.end(),
++ it) == supportedRegPrefixes.end())
++ {
++ messages::propertyValueNotInList(res, it, "RegistryPrefix");
++ res.end();
++ return false;
++ }
++ }
++ }
++
++ if (!msgIds.empty())
++ {
++ std::vector<std::string> registryPrefix;
++
++ // If no registry prefixes are mentioned, consider all supported
++ // prefixes to validate message ID
++ if (regPrefixes.empty())
++ {
++ registryPrefix.assign(supportedRegPrefixes.begin(),
++ supportedRegPrefixes.end());
++ }
++ else
++ {
++ registryPrefix = regPrefixes;
++ }
++
++ for (const std::string& id : msgIds)
++ {
++ bool validId = false;
++
++ // Check for Message ID in each of the selected Registry
++ for (const std::string& it : registryPrefix)
++ {
++ const std::span<const redfish::registries::MessageEntry>
++ registry =
++ redfish::registries::getRegistryFromPrefix(it);
++
++ if (std::any_of(
++ registry.begin(), registry.end(),
++ [&id](const redfish::registries::MessageEntry&
++ messageEntry) {
++ return !id.compare(messageEntry.first);
++ }))
++ {
++ validId = true;
++ break;
++ }
++ }
++
++ if (!validId)
++ {
++ messages::propertyValueNotInList(res, id, "MessageIds");
++ res.end();
++ return false;
++ }
++ }
++ }
++ }
++
+ std::shared_ptr<redfish::Subscription> subValue =
+ std::make_shared<redfish::Subscription>(std::move(conn));
+
+ // GET on this URI means, Its SSE subscriptionType.
+- subValue->subscriptionType = redfish::subscriptionTypeSSE;
+-
+- // TODO: parse $filter query params and fill config.
++ subValue->subscriptionType = subscriptionTypeSSE;
+ subValue->protocol = "Redfish";
+ subValue->retryPolicy = "TerminateAfterRetries";
+- subValue->eventFormatType = "Event";
++ subValue->eventFormatType = eventFormatType;
++ subValue->registryMsgIds = msgIds;
++ subValue->registryPrefixes = regPrefixes;
++ subValue->metricReportDefinitions = mrdsArray;
+
+ std::string id =
+ redfish::EventServiceManager::getInstance().addSubscription(subValue,
+diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
+index b3b2305..9b3ee49 100644
+--- a/redfish-core/include/error_messages.hpp
++++ b/redfish-core/include/error_messages.hpp
+@@ -980,6 +980,15 @@ nlohmann::json invalidUpload(std::string_view arg1, std::string_view arg2);
+ void invalidUpload(crow::Response& res, std::string_view arg1,
+ std::string_view arg2);
+
++/**
++ * @brief Formats InvalidQueryFilter message into JSON
++ * Message body: "The requested URL contains the invalid query filters"
++ *
++ * @returns Message InvalidQueryFilter formatted to JSON */
++nlohmann::json invalidQueryFilter();
++
++void invalidQueryFilter(crow::Response& res);
++
+ } // namespace messages
+
+ } // namespace redfish
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index c64bb59..e03dd9b 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -57,6 +57,11 @@ static constexpr const char* eventServiceFile =
+ static constexpr const uint8_t maxNoOfSubscriptions = 20;
+ static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
+
++static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
++ eventFormatType, metricReportFormatType};
++static constexpr const std::array<const char*, 2> supportedRegPrefixes = {
++ "OpenBMC", "TaskEvent"};
++
+ #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+ static std::optional<boost::asio::posix::stream_descriptor> inotifyConn;
+ static constexpr const char* redfishEventLogDir = "/var/log";
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 2181346..e9ee78f 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -24,11 +24,6 @@
+
+ namespace redfish
+ {
+-
+-static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
+- eventFormatType, metricReportFormatType};
+-static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
+- "Base", "OpenBMC", "TaskEvent"};
+ static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
+ "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
+
+diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
+index 381b8a9..cad145a 100644
+--- a/redfish-core/src/error_messages.cpp
++++ b/redfish-core/src/error_messages.cpp
+@@ -1668,6 +1668,33 @@ nlohmann::json invalidUpload(std::string_view arg1, std::string_view arg2)
+ {"MessageSeverity", "Warning"},
+ {"Resolution", "None."}};
+ }
++
++/**
++ * @internal
++ * @brief Formats InvalidQueryFilter into JSON
++ *
++ * See header file for more information
++ * @endinternal
++ */
++nlohmann::json invalidQueryFilter()
++{
++ return nlohmann::json{
++ {"@odata.type", "#Message.v1_0_0.Message"},
++ {"MessageId", "Base.1.5.0.InvalidQueryFilter"},
++ {"Message", "The requested url contains the invalid query filter."},
++ {"MessageArgs", nlohmann::json::array()},
++ {"Severity", "Warning"},
++ {"Resolution",
++ "Ensure the correct query filter is specified in requested url "
++ "and resubmit the request."}};
++}
++
++void invalidQueryFilter(crow::Response& res)
++{
++ res.result(boost::beast::http::status::bad_request);
++ addMessageToErrorJson(res.jsonValue, invalidQueryFilter());
++}
++
+ } // namespace messages
+
+ } // namespace redfish
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch
new file mode 100644
index 000000000..3818b99ee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0007-EventService-Log-events-for-subscription-actions.patch
@@ -0,0 +1,133 @@
+From ec3349511d66a7136a054c1a4e7a6f24ea3b6722 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Fri, 27 Aug 2021 16:02:01 +0000
+Subject: [PATCH] EventService: Log events for subscription actions
+
+Log redfish event for below 3 actions
+ - Add new subscription
+ - Update existing subscription properties
+ - Delete existing subscription
+in order to notify the subscribed clients on the subscription related
+information.
+
+Modified method name accordingly to indicate the clear purpose and
+added updateSubscription method with subscription id param
+to log event for subscription update.
+
+Tested:
+ - Performed all the above actions and verified the redfish event
+ messages are logged.
+
+Change-Id: I3745fa6357bd215379781a9818d9acc02a853d79
+Signed-off-by: AppaRao Puli <apparao.puli@intel.com>
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ .../include/event_service_manager.hpp | 35 ++++++++++++++++---
+ redfish-core/lib/event_service.hpp | 2 +-
+ 2 files changed, 32 insertions(+), 5 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index f2b7803..5483a74 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -21,6 +21,7 @@
+ #include "registries/task_event_message_registry.hpp"
+
+ #include <sys/inotify.h>
++#include <systemd/sd-journal.h>
+
+ #include <boost/asio/io_context.hpp>
+ #include <boost/beast/core/span.hpp>
+@@ -782,7 +783,7 @@ class EventServiceManager
+ }
+ }
+
+- void updateSubscriptionData() const
++ void persistSubscriptionData()
+ {
+ persistent_data::EventServiceStore::getInstance()
+ .eventServiceConfig.enabled = serviceEnabled;
+@@ -829,7 +830,7 @@ class EventServiceManager
+
+ if (updateConfig)
+ {
+- updateSubscriptionData();
++ persistSubscriptionData();
+ }
+
+ if (updateRetryCfg)
+@@ -941,7 +942,7 @@ class EventServiceManager
+
+ if (updateFile)
+ {
+- updateSubscriptionData();
++ persistSubscriptionData();
+ }
+
+ #ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
+@@ -957,6 +958,13 @@ class EventServiceManager
+
+ // Set Subscription ID for back trace
+ subValue->setSubscriptionId(id);
++
++ /* Log event for subscription addition */
++ sd_journal_send("MESSAGE=Event subscription added(Id: %s)", id.c_str(),
++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionAdded",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++
+ return id;
+ }
+
+@@ -981,7 +989,14 @@ class EventServiceManager
+ persistent_data::EventServiceStore::getInstance()
+ .subscriptionsConfigMap.erase(obj2);
+ updateNoOfSubscribersCount();
+- updateSubscriptionData();
++
++ persistSubscriptionData();
++ /* Log event for subscription delete. */
++ sd_journal_send("MESSAGE=Event subscription removed.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionRemoved",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
+ }
+ }
+
+@@ -1003,6 +1018,18 @@ class EventServiceManager
+ }
+ }
+
++ void updateSubscription(const std::string& id)
++ {
++ persistSubscriptionData();
++
++ /* Log event for subscription update. */
++ sd_journal_send("MESSAGE=Event subscription updated.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionUpdated",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++ }
++
+ size_t getNumberOfSubscriptions()
+ {
+ return subscriptionsMap.size();
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index ab85796..91ce22c 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -630,7 +630,7 @@ inline void requestRoutesEventDestination(App& app)
+ subValue->updateRetryPolicy();
+ }
+
+- EventServiceManager::getInstance().updateSubscriptionData();
++ EventServiceManager::getInstance().updateSubscription(param);
+ });
+ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
+ // The below privilege is wrong, it should be ConfigureManager OR
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch
new file mode 100644
index 000000000..65bfafdcc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch
@@ -0,0 +1,85 @@
+From a22fcc269c475b0ff8a80a6aa2c837b247eca907 Mon Sep 17 00:00:00 2001
+From: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+Date: Mon, 28 Jun 2021 19:59:57 +0000
+Subject: [PATCH] Add checks on Event Subscription input parameters
+
+There is no check on the size of input parameters(Context,
+Destination and Header) during Event Subscription.This
+creates out of memory situation.
+This commit checks for the size of input parameters and
+rejects if it is exceeding the input size limits.
+
+Tested
+ - Validated using POST on Event Subscription.
+ - When Context, Destination and Headers were too long,
+ received a error message denoting the same.
+
+Change-Id: Iec2cd766c0e137b72706fc2da468d4fefd8fbaae
+Signed-off-by: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com>
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ redfish-core/lib/event_service.hpp | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
+index 88ebd01..373c873 100644
+--- a/redfish-core/lib/event_service.hpp
++++ b/redfish-core/lib/event_service.hpp
+@@ -22,6 +22,10 @@
+
+ #include <span>
+
++#define MAX_CONTEXT_SIZE 256
++#define MAX_DESTINATION_SIZE 1024
++#define MAX_HEADER_SIZE 8096
++
+ namespace redfish
+ {
+ static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
+@@ -229,6 +233,12 @@ inline void requestRoutesEventDestinationCollection(App& app)
+ return;
+ }
+
++ if (destUrl.size() > MAX_DESTINATION_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res, "Destination");
++ return;
++ }
++
+ if (regPrefixes && msgIds)
+ {
+ if (!regPrefixes->empty() && !msgIds->empty())
+@@ -336,13 +346,30 @@ inline void requestRoutesEventDestinationCollection(App& app)
+
+ if (context)
+ {
++ if (context->size() > MAX_CONTEXT_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res, "Context");
++ return;
++ }
+ subValue->customText = *context;
+ }
+
+ if (headers)
+ {
++ size_t cumulativeLen = 0;
++
+ for (const nlohmann::json& headerChunk : *headers)
+ {
++ std::string hdr{headerChunk.dump(
++ -1, ' ', true,
++ nlohmann::json::error_handler_t::replace)};
++ cumulativeLen += hdr.length();
++ if (cumulativeLen > MAX_HEADER_SIZE)
++ {
++ messages::propertySizeExceeded(asyncResp->res,
++ "HttpHeaders");
++ return;
++ }
+ for (const auto& item : headerChunk.items())
+ {
+ const std::string* value =
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch
new file mode 100644
index 000000000..ede279868
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch
@@ -0,0 +1,267 @@
+From fc4b7e964f5f26e7af2eb19f120b1762b70b8179 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Tue, 12 Oct 2021 08:19:51 +0000
+Subject: [PATCH] Delete/Remove Terminated Event Subscription(s)
+
+Added functionality to delete/remove event subscription(s) which are
+configured to Terminate after retries.
+
+Currently, when an Event is subscribed with Retry Policy as
+"TerminateAfterRetries", the state of the connection is set to
+"Terminated" after retrying, but the Subscription is not removed.
+This commit adds the functionality to detect terminated connection and
+remove the respective subscription.
+
+Tested:
+ - Created a Subscription with
+ DeliveryRetryPolicy: "TerminateAfterRetries"
+ - Received Events successfully on Event listener
+ - Once the Event listener was stopped, the Subscription was
+ removed/deleted after retries.
+
+Change-Id: If447acb2db74fb29a5d1cfe6194b77cda82bc8a1
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_client.hpp | 48 +++++++++++++++----
+ .../include/event_service_manager.hpp | 36 ++++++++++++++
+ 2 files changed, 75 insertions(+), 9 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index 7328eae..db99faa 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -56,6 +56,8 @@ enum class ConnState
+ closeInProgress,
+ closed,
+ suspended,
++ terminate,
++ terminateInProgress,
+ terminated,
+ abortConnection,
+ retry
+@@ -290,7 +292,14 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ void doClose()
+ {
+- state = ConnState::closeInProgress;
++ if (state == ConnState::terminate)
++ {
++ state = ConnState::terminateInProgress;
++ }
++ else if (state != ConnState::suspended)
++ {
++ state = ConnState::closeInProgress;
++ }
+
+ // Set the timeout on the tcp stream socket for the async operation
+ conn.expires_after(std::chrono::seconds(30));
+@@ -320,8 +329,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ self->conn.close();
+
+- if ((self->state != ConnState::suspended) &&
+- (self->state != ConnState::terminated))
++ if (self->state == ConnState::terminateInProgress)
++ {
++ self->state = ConnState::terminated;
++ }
++ else if (self->state == ConnState::closeInProgress)
+ {
+ self->state = ConnState::closed;
+ self->handleConnState();
+@@ -343,8 +355,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ conn.close();
+
+- if ((state != ConnState::suspended) &&
+- (state != ConnState::terminated))
++ if (state == ConnState::terminateInProgress)
++ {
++ state = ConnState::terminated;
++ }
++ else if (state == ConnState::closeInProgress)
+ {
+ state = ConnState::closed;
+ handleConnState();
+@@ -367,8 +382,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction;
+ if (retryPolicyAction == "TerminateAfterRetries")
+ {
+- // TODO: delete subscription
+- state = ConnState::terminated;
++ state = ConnState::terminate;
+ }
+ if (retryPolicyAction == "SuspendRetries")
+ {
+@@ -424,6 +438,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ case ConnState::sendInProgress:
+ case ConnState::recvInProgress:
+ case ConnState::closeInProgress:
++ case ConnState::terminateInProgress:
+ {
+ BMCWEB_LOG_DEBUG << "Async operation is already in progress";
+ break;
+@@ -440,11 +455,16 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ break;
+ }
+ case ConnState::suspended:
+- case ConnState::terminated:
++ case ConnState::terminate:
+ {
+ doClose();
+ break;
+ }
++ case ConnState::terminated:
++ {
++ BMCWEB_LOG_DEBUG << "Connection Terminated";
++ break;
++ }
+ case ConnState::resolveFailed:
+ case ConnState::connectFailed:
+ case ConnState::handshakeFailed:
+@@ -504,7 +524,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ void sendData(const std::string& data)
+ {
+- if ((state == ConnState::suspended) || (state == ConnState::terminated))
++ if ((state == ConnState::terminate) ||
++ (state == ConnState::terminated) || (state == ConnState::suspended))
+ {
+ return;
+ }
+@@ -520,6 +541,15 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ }
+ }
+
++ bool isTerminated()
++ {
++ if (state == ConnState::terminated)
++ {
++ return true;
++ }
++ return false;
++ }
++
+ void setHeaders(const boost::beast::http::fields& httpHeaders)
+ {
+ // Set custom headers
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 5483a74..92abaa5 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -590,6 +590,14 @@ class Subscription : public persistent_data::UserSubscription
+ return std::nullopt;
+ }
+
++ bool isTerminated()
++ {
++ if (conn != nullptr)
++ return conn->isTerminated();
++
++ return false;
++ }
++
+ private:
+ std::shared_ptr<crow::SseConnection> sseConn = nullptr;
+ uint64_t eventSeqNum;
+@@ -845,6 +853,22 @@ class EventServiceManager
+ }
+ }
+
++ void deleteTerminatedSubcriptions()
++ {
++ boost::container::flat_map<std::string,
++ std::shared_ptr<Subscription>>::iterator it =
++ subscriptionsMap.begin();
++ while (it != subscriptionsMap.end())
++ {
++ std::shared_ptr<Subscription> entry = it->second;
++ if (entry->isTerminated())
++ {
++ subscriptionsMap.erase(it);
++ }
++ it++;
++ }
++ }
++
+ void updateNoOfSubscribersCount()
+ {
+ size_t eventLogSubCount = 0;
+@@ -879,6 +903,7 @@ class EventServiceManager
+
+ std::shared_ptr<Subscription> getSubscription(const std::string& id)
+ {
++ deleteTerminatedSubcriptions();
+ auto obj = subscriptionsMap.find(id);
+ if (obj == subscriptionsMap.end())
+ {
+@@ -970,6 +995,7 @@ class EventServiceManager
+
+ bool isSubscriptionExist(const std::string& id)
+ {
++ deleteTerminatedSubcriptions();
+ auto obj = subscriptionsMap.find(id);
+ if (obj == subscriptionsMap.end())
+ {
+@@ -1032,6 +1058,7 @@ class EventServiceManager
+
+ size_t getNumberOfSubscriptions()
+ {
++ deleteTerminatedSubcriptions();
+ return subscriptionsMap.size();
+ }
+
+@@ -1048,6 +1075,7 @@ class EventServiceManager
+
+ std::vector<std::string> getAllIDs()
+ {
++ deleteTerminatedSubcriptions();
+ std::vector<std::string> idList;
+ for (const auto& it : subscriptionsMap)
+ {
+@@ -1058,6 +1086,7 @@ class EventServiceManager
+
+ bool isDestinationExist(const std::string& destUrl)
+ {
++ deleteTerminatedSubcriptions();
+ for (const auto& it : subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1072,6 +1101,7 @@ class EventServiceManager
+
+ bool sendTestEventLog()
+ {
++ deleteTerminatedSubcriptions();
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1108,6 +1138,8 @@ class EventServiceManager
+ }
+ eventRecord.push_back(eventMessage);
+
++ deleteTerminatedSubcriptions();
++
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1151,6 +1183,8 @@ class EventServiceManager
+ }
+ void sendBroadcastMsg(const std::string& broadcastMsg)
+ {
++ deleteTerminatedSubcriptions();
++
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+@@ -1263,6 +1297,8 @@ class EventServiceManager
+ return;
+ }
+
++ deleteTerminatedSubcriptions();
++
+ for (const auto& it : this->subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch
new file mode 100644
index 000000000..87f0a4fd9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch
@@ -0,0 +1,141 @@
+From ff562320d23e1c1e075689a636505f22eb4890d4 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Thu, 14 Oct 2021 02:56:11 +0530
+Subject: [PATCH] Fix bmcweb crash while deleting terminated subscriptions
+
+This commit fixes bmcweb crash while deleting the terminated
+subscriptions. In the earlier implementation, detection of subscription
+to be deleted and the deletion(erase) was happening in the same loop.
+Due to this, if the Subscription to be deleted is the last one in the
+list, the loop will enter into infinite loop. The fix is to keep the
+detection and deletion loop separate.
+Also, this commit adds code to :
+ - Delete from persistent storage
+ - Add journal entry for deleted entry
+ - update number of subcribers and update persistent storage.
+
+Apart from this, this commit also moves the retry timer check to the top
+to avoid multiple calls to close when the retry count is 3 and timer is
+running.
+
+Tested:
+ - Checked journal logs to confirm each retry is actually spanned to be
+ 30 secs
+ - Verified Journal entry for deleted subscription after retires.
+ - Verified Event service functionality by making three subscriptions:
+ retry for ever, terminate after retires and suspend after retries.
+
+Change-Id: I425a6c749923ce86c457a36394deb0fbbee232db
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/http_client.hpp | 11 ++--
+ .../include/event_service_manager.hpp | 59 ++++++++++++++++---
+ 2 files changed, 58 insertions(+), 12 deletions(-)
+
+diff --git a/http/http_client.hpp b/http/http_client.hpp
+index 745eeb6..5575765 100644
+--- a/http/http_client.hpp
++++ b/http/http_client.hpp
+@@ -369,6 +369,12 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+
+ void waitAndRetry()
+ {
++ if (runningTimer)
++ {
++ BMCWEB_LOG_DEBUG << "Retry timer is already running.";
++ return;
++ }
++
+ if (retryCount >= maxRetryAttempts)
+ {
+ BMCWEB_LOG_ERROR << "Maximum number of retries reached.";
+@@ -395,11 +401,6 @@ class HttpClient : public std::enable_shared_from_this<HttpClient>
+ return;
+ }
+
+- if (runningTimer)
+- {
+- BMCWEB_LOG_DEBUG << "Retry timer is already running.";
+- return;
+- }
+ runningTimer = true;
+
+ retryCount++;
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 5d71c63..f97909c 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -853,18 +853,63 @@ class EventServiceManager
+
+ void deleteTerminatedSubcriptions()
+ {
+- boost::container::flat_map<std::string,
+- std::shared_ptr<Subscription>>::iterator it =
+- subscriptionsMap.begin();
+- while (it != subscriptionsMap.end())
++ BMCWEB_LOG_ERROR << "Map size Before Delete : "
++ << subscriptionsMap.size();
++
++ std::vector<std::string> deleteIds;
++
++ // Determine Subscription ID's to be deleted.
++ for (const auto& it : subscriptionsMap)
+ {
+- std::shared_ptr<Subscription> entry = it->second;
++ std::shared_ptr<Subscription> entry = it.second;
+ if (entry->isTerminated())
+ {
+- subscriptionsMap.erase(it);
++ deleteIds.emplace_back(it.first);
++ }
++ }
++
++ // Delete the Terminated Subcriptions
++ for (std::string& id : deleteIds)
++ {
++ auto map1 = subscriptionsMap.find(id);
++ if (map1 != subscriptionsMap.end())
++ {
++ subscriptionsMap.erase(map1);
++ auto map2 = persistent_data::EventServiceStore::getInstance()
++ .subscriptionsConfigMap.find(id);
++ if (map2 != persistent_data::EventServiceStore::getInstance()
++ .subscriptionsConfigMap.end())
++ {
++ persistent_data::EventServiceStore::getInstance()
++ .subscriptionsConfigMap.erase(map2);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Couldn't find ID: " << id
++ << " in subscriptionsConfigMap";
++ }
++
++ /* Log event for subscription delete. */
++ sd_journal_send("MESSAGE=Event subscription removed.(Id = %s)",
++ id.c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.EventSubscriptionRemoved",
++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR << "Couldn't find ID: " << id
++ << " in subscriptionsMap";
+ }
+- it++;
+ }
++ if (deleteIds.size())
++ {
++ updateNoOfSubscribersCount();
++ persistSubscriptionData();
++ }
++
++ BMCWEB_LOG_ERROR << "Map size After Delete : "
++ << subscriptionsMap.size();
+ }
+
+ void updateNoOfSubscribersCount()
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0012-Add-support-for-deleting-terminated-subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0012-Add-support-for-deleting-terminated-subscriptions.patch
new file mode 100644
index 000000000..61503904c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0012-Add-support-for-deleting-terminated-subscriptions.patch
@@ -0,0 +1,66 @@
+From b132263ef2f3bb3fd2766154c00b7b00c1e49fb6 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Tue, 7 Dec 2021 09:48:07 +0100
+Subject: [PATCH] Add support for deleting terminated subscriptions
+
+Added functionality to delete/remove event subscription(s) which are
+configured to Terminate after retries.
+
+Currently, when an Event is subscribed with Retry Policy as
+"TerminateAfterRetries", the state of the connection is set to
+"Terminated" after retrying, but the Subscription is not removed.
+This commit adds the functionality to detect terminated connection and
+remove the respective subscription.
+
+This commit adds this check for metric reports.
+
+Tested:
+ - Created a Subscription with
+ DeliveryRetryPolicy: "TerminateAfterRetries"
+ - Received Events successfully on Event listener
+ - Once the Event listener was stopped, the Subscription was
+ removed/deleted after retries.
+
+Change-Id: I3cb0af5bc24411cddcdb3d1d9de25e8e9144106c
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ redfish-core/include/event_service_manager.hpp | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index c68b707..6a93fc0 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -1486,7 +1486,7 @@ class EventServiceManager
+ }
+
+ #endif
+- static void getReadingsForReport(sdbusplus::message::message& msg)
++ void getReadingsForReport(sdbusplus::message::message& msg)
+ {
+ if (msg.is_method_error())
+ {
+@@ -1525,6 +1525,8 @@ class EventServiceManager
+ return;
+ }
+
++ deleteTerminatedSubcriptions();
++
+ for (const auto& it :
+ EventServiceManager::getInstance().subscriptionsMap)
+ {
+@@ -1560,7 +1562,10 @@ class EventServiceManager
+ "arg0=xyz.openbmc_project.Telemetry.Report";
+
+ matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>(
+- *crow::connections::systemBus, matchStr, getReadingsForReport);
++ *crow::connections::systemBus, matchStr,
++ [this](sdbusplus::message::message& msg) {
++ getReadingsForReport(msg);
++ });
+ }
+ };
+
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0013-event-service-fix-added-Context-field-to-response.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0013-event-service-fix-added-Context-field-to-response.patch
new file mode 100644
index 000000000..019ccbe64
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0013-event-service-fix-added-Context-field-to-response.patch
@@ -0,0 +1,33 @@
+From ce9b52791e76d73050f053f8fc607c6e1eb5d8c4 Mon Sep 17 00:00:00 2001
+From: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Date: Thu, 16 Dec 2021 10:46:55 +0100
+Subject: [PATCH] event service fix, added Context field to response
+
+Tested:
+ - Context field is present
+ - No regression detected
+
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+---
+ redfish-core/include/event_service_manager.hpp | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 881d2db..1ba9f21 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -530,6 +530,11 @@ class Subscription : public persistent_data::UserSubscription
+ return;
+ }
+
++ if (!customText.empty())
++ {
++ msg["Context"] = customText;
++ }
++
+ this->sendEvent(
+ msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace));
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README
new file mode 100644
index 000000000..617d6f3e8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README
@@ -0,0 +1,37 @@
+Eventservice specific patches: Temporary pulling down
+the upstream patches. These will be remove as soon as
+thee gets merged upstream.
+
+Upstream revision information:
+ - EventService : Add unmerged changes for http retry support (Downstream patch)
+ file://eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch
+
+ - EventService: https client support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31735/40 (Rebased on latest bmcweb)
+
+ - Add Server-Sent-Events support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41258/9
+
+ - Add SSE style subscription support to eventservice
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41319/10
+
+ - Add EventService SSE filter support
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41349/7 (Modified boost::urls::query_params_view to boost::urls::url_view::params_type)
+
+ - EventService Log events for subscription actions (Downstream patch)
+ file://eventservice/0007-EventService-Log-events-for-subscription-actions.patch
+
+ - Add checks on Event-Subscription input parameters (Downstream patch)
+ file://eventservice/0008-Add-checks-on-Event-Subscription-input-parameters.patch
+
+ - Remove Terminated Event Subscriptions (Downstream patch)
+ file://eventservice/0010-Remove-Terminated-Event-Subscriptions.patch
+
+ - Fix bmcweb crash while deleting terminated subscriptions (Downstream patch)
+ file://eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch
+
+ - Add support for deleting terminated subscriptions
+ file://eventservice/0012-Add-support-for-deleting-terminated-subscriptions.patch
+
+ - event service fix added Context field to response
+ file://eventservice/0013-event-service-fix-added-Context-field-to-response.patch