xref: /openbmc/bmcweb/features/redfish/src/subscription.cpp (revision fb54610544f97b989b549d8fc94518e2d38c9467)
102c1e29fSAlexander Hansen /*
202c1e29fSAlexander Hansen Copyright (c) 2020 Intel Corporation
302c1e29fSAlexander Hansen 
402c1e29fSAlexander Hansen Licensed under the Apache License, Version 2.0 (the "License");
502c1e29fSAlexander Hansen you may not use this file except in compliance with the License.
602c1e29fSAlexander Hansen You may obtain a copy of the License at
702c1e29fSAlexander Hansen 
802c1e29fSAlexander Hansen       http://www.apache.org/licenses/LICENSE-2.0
902c1e29fSAlexander Hansen 
1002c1e29fSAlexander Hansen Unless required by applicable law or agreed to in writing, software
1102c1e29fSAlexander Hansen distributed under the License is distributed on an "AS IS" BASIS,
1202c1e29fSAlexander Hansen WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1302c1e29fSAlexander Hansen See the License for the specific language governing permissions and
1402c1e29fSAlexander Hansen limitations under the License.
1502c1e29fSAlexander Hansen */
1602c1e29fSAlexander Hansen #include "subscription.hpp"
1702c1e29fSAlexander Hansen 
18*fb546105SMyung Bae #include "dbus_singleton.hpp"
19b80ba2e4SAlexander Hansen #include "event_log.hpp"
2002c1e29fSAlexander Hansen #include "event_logs_object_type.hpp"
2102c1e29fSAlexander Hansen #include "event_matches_filter.hpp"
2202c1e29fSAlexander Hansen #include "event_service_store.hpp"
2302c1e29fSAlexander Hansen #include "filter_expr_executor.hpp"
2402c1e29fSAlexander Hansen #include "generated/enums/log_entry.hpp"
25*fb546105SMyung Bae #include "heartbeat_messages.hpp"
2602c1e29fSAlexander Hansen #include "http_client.hpp"
2702c1e29fSAlexander Hansen #include "http_response.hpp"
2802c1e29fSAlexander Hansen #include "logging.hpp"
2902c1e29fSAlexander Hansen #include "metric_report.hpp"
3002c1e29fSAlexander Hansen #include "server_sent_event.hpp"
3102c1e29fSAlexander Hansen #include "ssl_key_handler.hpp"
3202c1e29fSAlexander Hansen #include "utils/time_utils.hpp"
3302c1e29fSAlexander Hansen 
34*fb546105SMyung Bae #include <boost/asio/error.hpp>
3502c1e29fSAlexander Hansen #include <boost/asio/io_context.hpp>
36*fb546105SMyung Bae #include <boost/asio/steady_timer.hpp>
3702c1e29fSAlexander Hansen #include <boost/beast/http/verb.hpp>
3802c1e29fSAlexander Hansen #include <boost/system/errc.hpp>
3902c1e29fSAlexander Hansen #include <boost/url/format.hpp>
4002c1e29fSAlexander Hansen #include <boost/url/url_view_base.hpp>
4102c1e29fSAlexander Hansen #include <nlohmann/json.hpp>
4202c1e29fSAlexander Hansen 
4302c1e29fSAlexander Hansen #include <algorithm>
44*fb546105SMyung Bae #include <chrono>
4502c1e29fSAlexander Hansen #include <cstdint>
4602c1e29fSAlexander Hansen #include <cstdlib>
4702c1e29fSAlexander Hansen #include <ctime>
4802c1e29fSAlexander Hansen #include <format>
4902c1e29fSAlexander Hansen #include <functional>
5002c1e29fSAlexander Hansen #include <memory>
5102c1e29fSAlexander Hansen #include <span>
5202c1e29fSAlexander Hansen #include <string>
5302c1e29fSAlexander Hansen #include <string_view>
5402c1e29fSAlexander Hansen #include <utility>
5502c1e29fSAlexander Hansen #include <vector>
5602c1e29fSAlexander Hansen 
5702c1e29fSAlexander Hansen namespace redfish
5802c1e29fSAlexander Hansen {
5902c1e29fSAlexander Hansen 
6002c1e29fSAlexander Hansen Subscription::Subscription(
6102c1e29fSAlexander Hansen     std::shared_ptr<persistent_data::UserSubscription> userSubIn,
6202c1e29fSAlexander Hansen     const boost::urls::url_view_base& url, boost::asio::io_context& ioc) :
6302c1e29fSAlexander Hansen     userSub{std::move(userSubIn)},
64*fb546105SMyung Bae     policy(std::make_shared<crow::ConnectionPolicy>()), hbTimer(ioc)
6502c1e29fSAlexander Hansen {
6602c1e29fSAlexander Hansen     userSub->destinationUrl = url;
6702c1e29fSAlexander Hansen     client.emplace(ioc, policy);
6802c1e29fSAlexander Hansen     // Subscription constructor
6902c1e29fSAlexander Hansen     policy->invalidResp = retryRespHandler;
7002c1e29fSAlexander Hansen }
7102c1e29fSAlexander Hansen 
7202c1e29fSAlexander Hansen Subscription::Subscription(crow::sse_socket::Connection& connIn) :
7302c1e29fSAlexander Hansen     userSub{std::make_shared<persistent_data::UserSubscription>()},
74*fb546105SMyung Bae     sseConn(&connIn), hbTimer(crow::connections::systemBus->get_io_context())
7502c1e29fSAlexander Hansen {}
7602c1e29fSAlexander Hansen 
7702c1e29fSAlexander Hansen // callback for subscription sendData
7802c1e29fSAlexander Hansen void Subscription::resHandler(const std::shared_ptr<Subscription>& /*unused*/,
7902c1e29fSAlexander Hansen                               const crow::Response& res)
8002c1e29fSAlexander Hansen {
8102c1e29fSAlexander Hansen     BMCWEB_LOG_DEBUG("Response handled with return code: {}", res.resultInt());
8202c1e29fSAlexander Hansen 
8302c1e29fSAlexander Hansen     if (!client)
8402c1e29fSAlexander Hansen     {
8502c1e29fSAlexander Hansen         BMCWEB_LOG_ERROR(
8602c1e29fSAlexander Hansen             "Http client wasn't filled but http client callback was called.");
8702c1e29fSAlexander Hansen         return;
8802c1e29fSAlexander Hansen     }
8902c1e29fSAlexander Hansen 
9002c1e29fSAlexander Hansen     if (userSub->retryPolicy != "TerminateAfterRetries")
9102c1e29fSAlexander Hansen     {
9202c1e29fSAlexander Hansen         return;
9302c1e29fSAlexander Hansen     }
9402c1e29fSAlexander Hansen     if (client->isTerminated())
9502c1e29fSAlexander Hansen     {
96*fb546105SMyung Bae         hbTimer.cancel();
9702c1e29fSAlexander Hansen         if (deleter)
9802c1e29fSAlexander Hansen         {
9902c1e29fSAlexander Hansen             BMCWEB_LOG_INFO("Subscription {} is deleted after MaxRetryAttempts",
10002c1e29fSAlexander Hansen                             userSub->id);
10102c1e29fSAlexander Hansen             deleter();
10202c1e29fSAlexander Hansen         }
10302c1e29fSAlexander Hansen     }
10402c1e29fSAlexander Hansen }
10502c1e29fSAlexander Hansen 
106*fb546105SMyung Bae void Subscription::sendHeartbeatEvent()
107*fb546105SMyung Bae {
108*fb546105SMyung Bae     // send the heartbeat message
109*fb546105SMyung Bae     nlohmann::json eventMessage = messages::redfishServiceFunctional();
110*fb546105SMyung Bae 
111*fb546105SMyung Bae     std::string heartEventId = std::to_string(eventSeqNum);
112*fb546105SMyung Bae     eventMessage["EventId"] = heartEventId;
113*fb546105SMyung Bae     eventMessage["EventTimestamp"] = time_utils::getDateTimeOffsetNow().first;
114*fb546105SMyung Bae     eventMessage["OriginOfCondition"] =
115*fb546105SMyung Bae         std::format("/redfish/v1/EventService/Subscriptions/{}", userSub->id);
116*fb546105SMyung Bae     eventMessage["MemberId"] = "0";
117*fb546105SMyung Bae 
118*fb546105SMyung Bae     nlohmann::json::array_t eventRecord;
119*fb546105SMyung Bae     eventRecord.emplace_back(std::move(eventMessage));
120*fb546105SMyung Bae 
121*fb546105SMyung Bae     nlohmann::json msgJson;
122*fb546105SMyung Bae     msgJson["@odata.type"] = "#Event.v1_4_0.Event";
123*fb546105SMyung Bae     msgJson["Name"] = "Heartbeat";
124*fb546105SMyung Bae     msgJson["Id"] = heartEventId;
125*fb546105SMyung Bae     msgJson["Events"] = std::move(eventRecord);
126*fb546105SMyung Bae 
127*fb546105SMyung Bae     std::string strMsg =
128*fb546105SMyung Bae         msgJson.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
129*fb546105SMyung Bae     sendEventToSubscriber(std::move(strMsg));
130*fb546105SMyung Bae     eventSeqNum++;
131*fb546105SMyung Bae }
132*fb546105SMyung Bae 
133*fb546105SMyung Bae void Subscription::scheduleNextHeartbeatEvent()
134*fb546105SMyung Bae {
135*fb546105SMyung Bae     hbTimer.expires_after(std::chrono::minutes(userSub->hbIntervalMinutes));
136*fb546105SMyung Bae     hbTimer.async_wait(
137*fb546105SMyung Bae         std::bind_front(&Subscription::onHbTimeout, this, weak_from_this()));
138*fb546105SMyung Bae }
139*fb546105SMyung Bae 
140*fb546105SMyung Bae void Subscription::heartbeatParametersChanged()
141*fb546105SMyung Bae {
142*fb546105SMyung Bae     hbTimer.cancel();
143*fb546105SMyung Bae 
144*fb546105SMyung Bae     if (userSub->sendHeartbeat)
145*fb546105SMyung Bae     {
146*fb546105SMyung Bae         scheduleNextHeartbeatEvent();
147*fb546105SMyung Bae     }
148*fb546105SMyung Bae }
149*fb546105SMyung Bae 
150*fb546105SMyung Bae void Subscription::onHbTimeout(const std::weak_ptr<Subscription>& weakSelf,
151*fb546105SMyung Bae                                const boost::system::error_code& ec)
152*fb546105SMyung Bae {
153*fb546105SMyung Bae     if (ec == boost::asio::error::operation_aborted)
154*fb546105SMyung Bae     {
155*fb546105SMyung Bae         BMCWEB_LOG_DEBUG("heartbeat timer async_wait is aborted");
156*fb546105SMyung Bae         return;
157*fb546105SMyung Bae     }
158*fb546105SMyung Bae     if (ec == boost::system::errc::operation_canceled)
159*fb546105SMyung Bae     {
160*fb546105SMyung Bae         BMCWEB_LOG_DEBUG("heartbeat timer async_wait canceled");
161*fb546105SMyung Bae         return;
162*fb546105SMyung Bae     }
163*fb546105SMyung Bae     if (ec)
164*fb546105SMyung Bae     {
165*fb546105SMyung Bae         BMCWEB_LOG_CRITICAL("heartbeat timer async_wait failed: {}", ec);
166*fb546105SMyung Bae         return;
167*fb546105SMyung Bae     }
168*fb546105SMyung Bae 
169*fb546105SMyung Bae     std::shared_ptr<Subscription> self = weakSelf.lock();
170*fb546105SMyung Bae     if (!self)
171*fb546105SMyung Bae     {
172*fb546105SMyung Bae         BMCWEB_LOG_CRITICAL("onHbTimeout failed on Subscription");
173*fb546105SMyung Bae         return;
174*fb546105SMyung Bae     }
175*fb546105SMyung Bae 
176*fb546105SMyung Bae     // Timer expired.
177*fb546105SMyung Bae     sendHeartbeatEvent();
178*fb546105SMyung Bae 
179*fb546105SMyung Bae     // reschedule heartbeat timer
180*fb546105SMyung Bae     scheduleNextHeartbeatEvent();
181*fb546105SMyung Bae }
182*fb546105SMyung Bae 
18302c1e29fSAlexander Hansen bool Subscription::sendEventToSubscriber(std::string&& msg)
18402c1e29fSAlexander Hansen {
18502c1e29fSAlexander Hansen     persistent_data::EventServiceConfig eventServiceConfig =
18602c1e29fSAlexander Hansen         persistent_data::EventServiceStore::getInstance()
18702c1e29fSAlexander Hansen             .getEventServiceConfig();
18802c1e29fSAlexander Hansen     if (!eventServiceConfig.enabled)
18902c1e29fSAlexander Hansen     {
19002c1e29fSAlexander Hansen         return false;
19102c1e29fSAlexander Hansen     }
19202c1e29fSAlexander Hansen 
19302c1e29fSAlexander Hansen     if (client)
19402c1e29fSAlexander Hansen     {
19502c1e29fSAlexander Hansen         client->sendDataWithCallback(
19602c1e29fSAlexander Hansen             std::move(msg), userSub->destinationUrl,
19702c1e29fSAlexander Hansen             static_cast<ensuressl::VerifyCertificate>(
19802c1e29fSAlexander Hansen                 userSub->verifyCertificate),
19902c1e29fSAlexander Hansen             userSub->httpHeaders, boost::beast::http::verb::post,
20002c1e29fSAlexander Hansen             std::bind_front(&Subscription::resHandler, this,
20102c1e29fSAlexander Hansen                             shared_from_this()));
20202c1e29fSAlexander Hansen         return true;
20302c1e29fSAlexander Hansen     }
20402c1e29fSAlexander Hansen 
20502c1e29fSAlexander Hansen     if (sseConn != nullptr)
20602c1e29fSAlexander Hansen     {
20702c1e29fSAlexander Hansen         eventSeqNum++;
20802c1e29fSAlexander Hansen         sseConn->sendSseEvent(std::to_string(eventSeqNum), msg);
20902c1e29fSAlexander Hansen     }
21002c1e29fSAlexander Hansen     return true;
21102c1e29fSAlexander Hansen }
21202c1e29fSAlexander Hansen 
21302c1e29fSAlexander Hansen bool Subscription::sendTestEventLog()
21402c1e29fSAlexander Hansen {
21502c1e29fSAlexander Hansen     nlohmann::json::array_t logEntryArray;
21602c1e29fSAlexander Hansen     nlohmann::json& logEntryJson = logEntryArray.emplace_back();
21702c1e29fSAlexander Hansen 
21802c1e29fSAlexander Hansen     logEntryJson["EventId"] = "TestID";
21902c1e29fSAlexander Hansen     logEntryJson["Severity"] = log_entry::EventSeverity::OK;
22002c1e29fSAlexander Hansen     logEntryJson["Message"] = "Generated test event";
22102c1e29fSAlexander Hansen     logEntryJson["MessageId"] = "OpenBMC.0.2.TestEventLog";
22202c1e29fSAlexander Hansen     // MemberId is 0 : since we are sending one event record.
22302c1e29fSAlexander Hansen     logEntryJson["MemberId"] = "0";
22402c1e29fSAlexander Hansen     logEntryJson["MessageArgs"] = nlohmann::json::array();
22502c1e29fSAlexander Hansen     logEntryJson["EventTimestamp"] =
22602c1e29fSAlexander Hansen         redfish::time_utils::getDateTimeOffsetNow().first;
22702c1e29fSAlexander Hansen     logEntryJson["Context"] = userSub->customText;
22802c1e29fSAlexander Hansen 
22902c1e29fSAlexander Hansen     nlohmann::json msg;
23002c1e29fSAlexander Hansen     msg["@odata.type"] = "#Event.v1_4_0.Event";
23102c1e29fSAlexander Hansen     msg["Id"] = std::to_string(eventSeqNum);
23202c1e29fSAlexander Hansen     msg["Name"] = "Event Log";
23302c1e29fSAlexander Hansen     msg["Events"] = logEntryArray;
23402c1e29fSAlexander Hansen 
23502c1e29fSAlexander Hansen     std::string strMsg =
23602c1e29fSAlexander Hansen         msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
23702c1e29fSAlexander Hansen     return sendEventToSubscriber(std::move(strMsg));
23802c1e29fSAlexander Hansen }
23902c1e29fSAlexander Hansen 
24002c1e29fSAlexander Hansen void Subscription::filterAndSendEventLogs(
24102c1e29fSAlexander Hansen     const std::vector<EventLogObjectsType>& eventRecords)
24202c1e29fSAlexander Hansen {
24302c1e29fSAlexander Hansen     nlohmann::json::array_t logEntryArray;
24402c1e29fSAlexander Hansen     for (const EventLogObjectsType& logEntry : eventRecords)
24502c1e29fSAlexander Hansen     {
24602c1e29fSAlexander Hansen         std::vector<std::string_view> messageArgsView(
24702c1e29fSAlexander Hansen             logEntry.messageArgs.begin(), logEntry.messageArgs.end());
24802c1e29fSAlexander Hansen 
24902c1e29fSAlexander Hansen         nlohmann::json::object_t bmcLogEntry;
25002c1e29fSAlexander Hansen         if (event_log::formatEventLogEntry(
25102c1e29fSAlexander Hansen                 logEntry.id, logEntry.messageId, messageArgsView,
25202c1e29fSAlexander Hansen                 logEntry.timestamp, userSub->customText, bmcLogEntry) != 0)
25302c1e29fSAlexander Hansen         {
25402c1e29fSAlexander Hansen             BMCWEB_LOG_DEBUG("Read eventLog entry failed");
25502c1e29fSAlexander Hansen             continue;
25602c1e29fSAlexander Hansen         }
25702c1e29fSAlexander Hansen 
25802c1e29fSAlexander Hansen         if (!eventMatchesFilter(*userSub, bmcLogEntry, ""))
25902c1e29fSAlexander Hansen         {
26002c1e29fSAlexander Hansen             BMCWEB_LOG_DEBUG("Event {} did not match the filter",
26102c1e29fSAlexander Hansen                              nlohmann::json(bmcLogEntry).dump());
26202c1e29fSAlexander Hansen             continue;
26302c1e29fSAlexander Hansen         }
26402c1e29fSAlexander Hansen 
26502c1e29fSAlexander Hansen         if (filter)
26602c1e29fSAlexander Hansen         {
26702c1e29fSAlexander Hansen             if (!memberMatches(bmcLogEntry, *filter))
26802c1e29fSAlexander Hansen             {
26902c1e29fSAlexander Hansen                 BMCWEB_LOG_DEBUG("Filter didn't match");
27002c1e29fSAlexander Hansen                 continue;
27102c1e29fSAlexander Hansen             }
27202c1e29fSAlexander Hansen         }
27302c1e29fSAlexander Hansen 
27402c1e29fSAlexander Hansen         logEntryArray.emplace_back(std::move(bmcLogEntry));
27502c1e29fSAlexander Hansen     }
27602c1e29fSAlexander Hansen 
27702c1e29fSAlexander Hansen     if (logEntryArray.empty())
27802c1e29fSAlexander Hansen     {
27902c1e29fSAlexander Hansen         BMCWEB_LOG_DEBUG("No log entries available to be transferred.");
28002c1e29fSAlexander Hansen         return;
28102c1e29fSAlexander Hansen     }
28202c1e29fSAlexander Hansen 
28302c1e29fSAlexander Hansen     nlohmann::json msg;
28402c1e29fSAlexander Hansen     msg["@odata.type"] = "#Event.v1_4_0.Event";
28502c1e29fSAlexander Hansen     msg["Id"] = std::to_string(eventSeqNum);
28602c1e29fSAlexander Hansen     msg["Name"] = "Event Log";
28702c1e29fSAlexander Hansen     msg["Events"] = std::move(logEntryArray);
28802c1e29fSAlexander Hansen     std::string strMsg =
28902c1e29fSAlexander Hansen         msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
29002c1e29fSAlexander Hansen     sendEventToSubscriber(std::move(strMsg));
29102c1e29fSAlexander Hansen     eventSeqNum++;
29202c1e29fSAlexander Hansen }
29302c1e29fSAlexander Hansen 
29402c1e29fSAlexander Hansen void Subscription::filterAndSendReports(const std::string& reportId,
29502c1e29fSAlexander Hansen                                         const telemetry::TimestampReadings& var)
29602c1e29fSAlexander Hansen {
29702c1e29fSAlexander Hansen     boost::urls::url mrdUri = boost::urls::format(
29802c1e29fSAlexander Hansen         "/redfish/v1/TelemetryService/MetricReportDefinitions/{}", reportId);
29902c1e29fSAlexander Hansen 
30002c1e29fSAlexander Hansen     // Empty list means no filter. Send everything.
30102c1e29fSAlexander Hansen     if (!userSub->metricReportDefinitions.empty())
30202c1e29fSAlexander Hansen     {
30302c1e29fSAlexander Hansen         if (std::ranges::find(userSub->metricReportDefinitions,
30402c1e29fSAlexander Hansen                               mrdUri.buffer()) ==
30502c1e29fSAlexander Hansen             userSub->metricReportDefinitions.end())
30602c1e29fSAlexander Hansen         {
30702c1e29fSAlexander Hansen             return;
30802c1e29fSAlexander Hansen         }
30902c1e29fSAlexander Hansen     }
31002c1e29fSAlexander Hansen 
31102c1e29fSAlexander Hansen     nlohmann::json msg;
31202c1e29fSAlexander Hansen     if (!telemetry::fillReport(msg, reportId, var))
31302c1e29fSAlexander Hansen     {
31402c1e29fSAlexander Hansen         BMCWEB_LOG_ERROR("Failed to fill the MetricReport for DBus "
31502c1e29fSAlexander Hansen                          "Report with id {}",
31602c1e29fSAlexander Hansen                          reportId);
31702c1e29fSAlexander Hansen         return;
31802c1e29fSAlexander Hansen     }
31902c1e29fSAlexander Hansen 
32002c1e29fSAlexander Hansen     // Context is set by user during Event subscription and it must be
32102c1e29fSAlexander Hansen     // set for MetricReport response.
32202c1e29fSAlexander Hansen     if (!userSub->customText.empty())
32302c1e29fSAlexander Hansen     {
32402c1e29fSAlexander Hansen         msg["Context"] = userSub->customText;
32502c1e29fSAlexander Hansen     }
32602c1e29fSAlexander Hansen 
32702c1e29fSAlexander Hansen     std::string strMsg =
32802c1e29fSAlexander Hansen         msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace);
32902c1e29fSAlexander Hansen     sendEventToSubscriber(std::move(strMsg));
33002c1e29fSAlexander Hansen }
33102c1e29fSAlexander Hansen 
33202c1e29fSAlexander Hansen void Subscription::updateRetryConfig(uint32_t retryAttempts,
33302c1e29fSAlexander Hansen                                      uint32_t retryTimeoutInterval)
33402c1e29fSAlexander Hansen {
33502c1e29fSAlexander Hansen     if (policy == nullptr)
33602c1e29fSAlexander Hansen     {
33702c1e29fSAlexander Hansen         BMCWEB_LOG_DEBUG("Retry policy was nullptr, ignoring set");
33802c1e29fSAlexander Hansen         return;
33902c1e29fSAlexander Hansen     }
34002c1e29fSAlexander Hansen     policy->maxRetryAttempts = retryAttempts;
34102c1e29fSAlexander Hansen     policy->retryIntervalSecs = std::chrono::seconds(retryTimeoutInterval);
34202c1e29fSAlexander Hansen }
34302c1e29fSAlexander Hansen 
34402c1e29fSAlexander Hansen uint64_t Subscription::getEventSeqNum() const
34502c1e29fSAlexander Hansen {
34602c1e29fSAlexander Hansen     return eventSeqNum;
34702c1e29fSAlexander Hansen }
34802c1e29fSAlexander Hansen 
34902c1e29fSAlexander Hansen bool Subscription::matchSseId(const crow::sse_socket::Connection& thisConn)
35002c1e29fSAlexander Hansen {
35102c1e29fSAlexander Hansen     return &thisConn == sseConn;
35202c1e29fSAlexander Hansen }
35302c1e29fSAlexander Hansen 
35402c1e29fSAlexander Hansen // Check used to indicate what response codes are valid as part of our retry
35502c1e29fSAlexander Hansen // policy.  2XX is considered acceptable
35602c1e29fSAlexander Hansen boost::system::error_code Subscription::retryRespHandler(unsigned int respCode)
35702c1e29fSAlexander Hansen {
35802c1e29fSAlexander Hansen     BMCWEB_LOG_DEBUG("Checking response code validity for SubscriptionEvent");
35902c1e29fSAlexander Hansen     if ((respCode < 200) || (respCode >= 300))
36002c1e29fSAlexander Hansen     {
36102c1e29fSAlexander Hansen         return boost::system::errc::make_error_code(
36202c1e29fSAlexander Hansen             boost::system::errc::result_out_of_range);
36302c1e29fSAlexander Hansen     }
36402c1e29fSAlexander Hansen 
36502c1e29fSAlexander Hansen     // Return 0 if the response code is valid
36602c1e29fSAlexander Hansen     return boost::system::errc::make_error_code(boost::system::errc::success);
36702c1e29fSAlexander Hansen }
36802c1e29fSAlexander Hansen 
36902c1e29fSAlexander Hansen } // namespace redfish
370