108a70aa5SVernon Mauery /**
208a70aa5SVernon Mauery  * Copyright © 2018 Intel Corporation
308a70aa5SVernon Mauery  *
408a70aa5SVernon Mauery  * Licensed under the Apache License, Version 2.0 (the "License");
508a70aa5SVernon Mauery  * you may not use this file except in compliance with the License.
608a70aa5SVernon Mauery  * You may obtain a copy of the License at
708a70aa5SVernon Mauery  *
808a70aa5SVernon Mauery  *     http://www.apache.org/licenses/LICENSE-2.0
908a70aa5SVernon Mauery  *
1008a70aa5SVernon Mauery  * Unless required by applicable law or agreed to in writing, software
1108a70aa5SVernon Mauery  * distributed under the License is distributed on an "AS IS" BASIS,
1208a70aa5SVernon Mauery  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308a70aa5SVernon Mauery  * See the License for the specific language governing permissions and
1408a70aa5SVernon Mauery  * limitations under the License.
1508a70aa5SVernon Mauery  */
1608a70aa5SVernon Mauery #pragma once
1708a70aa5SVernon Mauery #include <boost/callable_traits.hpp>
18e08fbffcSVernon Mauery #include <ipmid/api-types.hpp>
1908a70aa5SVernon Mauery #include <ipmid/message.hpp>
20*fbc6c9d7SPatrick Williams 
21*fbc6c9d7SPatrick Williams #include <algorithm>
22*fbc6c9d7SPatrick Williams #include <cstdint>
2308a70aa5SVernon Mauery #include <memory>
2408a70aa5SVernon Mauery #include <tuple>
2508a70aa5SVernon Mauery #include <utility>
2608a70aa5SVernon Mauery 
2708a70aa5SVernon Mauery namespace ipmi
2808a70aa5SVernon Mauery {
2908a70aa5SVernon Mauery 
3008a70aa5SVernon Mauery using FilterFunction = ipmi::Cc(ipmi::message::Request::ptr);
3108a70aa5SVernon Mauery 
3208a70aa5SVernon Mauery /**
3308a70aa5SVernon Mauery  * @brief Filter base class for dealing with IPMI request/response
3408a70aa5SVernon Mauery  *
3508a70aa5SVernon Mauery  * The subclasses are all templated so they can provide access to any type of
3608a70aa5SVernon Mauery  * command callback functions.
3708a70aa5SVernon Mauery  */
3808a70aa5SVernon Mauery class FilterBase
3908a70aa5SVernon Mauery {
4008a70aa5SVernon Mauery   public:
4108a70aa5SVernon Mauery     using ptr = std::shared_ptr<FilterBase>;
4208a70aa5SVernon Mauery 
437d7a6858SPatrick Williams     virtual ~FilterBase() = default;
447d7a6858SPatrick Williams 
4508a70aa5SVernon Mauery     virtual ipmi::Cc call(message::Request::ptr request) = 0;
4608a70aa5SVernon Mauery };
4708a70aa5SVernon Mauery 
4808a70aa5SVernon Mauery /**
4908a70aa5SVernon Mauery  * @brief filter concrete class
5008a70aa5SVernon Mauery  *
5108a70aa5SVernon Mauery  * This is the base template that ipmi filters will resolve into. This is
5208a70aa5SVernon Mauery  * essentially just a wrapper to hold the filter callback so it can be stored in
5308a70aa5SVernon Mauery  * the filter list.
5408a70aa5SVernon Mauery  *
5508a70aa5SVernon Mauery  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
5608a70aa5SVernon Mauery  * commands in priority order and each filter has the opportunity to reject the
5708a70aa5SVernon Mauery  * command (by returning an IPMI error competion code.) If all the filters
5808a70aa5SVernon Mauery  * return success, the actual IPMI command will be executed. Filters can reject
5908a70aa5SVernon Mauery  * the command for any reason, based on system state, the context, the command
6008a70aa5SVernon Mauery  * payload, etc.
6108a70aa5SVernon Mauery  */
6208a70aa5SVernon Mauery template <typename Filter>
6308a70aa5SVernon Mauery class IpmiFilter : public FilterBase
6408a70aa5SVernon Mauery {
6508a70aa5SVernon Mauery   public:
IpmiFilter(Filter && filter)66*fbc6c9d7SPatrick Williams     IpmiFilter(Filter&& filter) : filter_(std::move(filter)) {}
6708a70aa5SVernon Mauery 
call(message::Request::ptr request)6808a70aa5SVernon Mauery     ipmi::Cc call(message::Request::ptr request) override
6908a70aa5SVernon Mauery     {
7008a70aa5SVernon Mauery         return filter_(request);
7108a70aa5SVernon Mauery     }
7208a70aa5SVernon Mauery 
7308a70aa5SVernon Mauery   private:
7408a70aa5SVernon Mauery     Filter filter_;
7508a70aa5SVernon Mauery };
7608a70aa5SVernon Mauery 
7708a70aa5SVernon Mauery /**
7808a70aa5SVernon Mauery  * @brief helper function to construct a filter object
7908a70aa5SVernon Mauery  *
8008a70aa5SVernon Mauery  * This is called internally by the ipmi::registerFilter function.
8108a70aa5SVernon Mauery  */
8208a70aa5SVernon Mauery template <typename Filter>
makeFilter(Filter && filter)8308a70aa5SVernon Mauery static inline auto makeFilter(Filter&& filter)
8408a70aa5SVernon Mauery {
8508a70aa5SVernon Mauery     FilterBase::ptr ptr(new IpmiFilter<Filter>(std::forward<Filter>(filter)));
8608a70aa5SVernon Mauery     return ptr;
8708a70aa5SVernon Mauery }
8808a70aa5SVernon Mauery template <typename Filter>
makeFilter(const Filter & filter)8908a70aa5SVernon Mauery static inline auto makeFilter(const Filter& filter)
9008a70aa5SVernon Mauery {
9108a70aa5SVernon Mauery     Filter lFilter = filter;
9208a70aa5SVernon Mauery     return makeFilter(std::forward<Filter>(lFilter));
9308a70aa5SVernon Mauery }
9408a70aa5SVernon Mauery 
95e08fbffcSVernon Mauery namespace impl
96e08fbffcSVernon Mauery {
97e08fbffcSVernon Mauery 
98e08fbffcSVernon Mauery // IPMI command filter registration implementation
99e08fbffcSVernon Mauery void registerFilter(int prio, ::ipmi::FilterBase::ptr filter);
100e08fbffcSVernon Mauery 
101e08fbffcSVernon Mauery } // namespace impl
102e08fbffcSVernon Mauery 
103e08fbffcSVernon Mauery /**
104e08fbffcSVernon Mauery  * @brief IPMI command filter registration function
105e08fbffcSVernon Mauery  *
106e08fbffcSVernon Mauery  * This function should be used to register IPMI command filter functions.
107e08fbffcSVernon Mauery  * This function just passes the callback to makeFilter, which creates a
108e08fbffcSVernon Mauery  * wrapper functor object that ultimately calls the callback.
109e08fbffcSVernon Mauery  *
110e08fbffcSVernon Mauery  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
111e08fbffcSVernon Mauery  * commands in priority order and each filter has the opportunity to reject the
112e08fbffcSVernon Mauery  * command (by returning an IPMI error competion code.) If all the filters
113e08fbffcSVernon Mauery  * return success, the actual IPMI command will be executed. Filters can reject
114e08fbffcSVernon Mauery  * the command for any reason, based on system state, the context, the command
115e08fbffcSVernon Mauery  * payload, etc.
116e08fbffcSVernon Mauery  *
117e08fbffcSVernon Mauery  * @param prio - priority at which to register; see api.hpp
118e08fbffcSVernon Mauery  * @param filter - the callback function that will handle this request
119e08fbffcSVernon Mauery  *
120e08fbffcSVernon Mauery  * @return bool - success of registering the handler
121e08fbffcSVernon Mauery  */
122e08fbffcSVernon Mauery template <typename Filter>
registerFilter(int prio,Filter && filter)123e08fbffcSVernon Mauery void registerFilter(int prio, Filter&& filter)
124e08fbffcSVernon Mauery {
125e08fbffcSVernon Mauery     auto f = ipmi::makeFilter(std::forward<Filter>(filter));
126e08fbffcSVernon Mauery     impl::registerFilter(prio, f);
127e08fbffcSVernon Mauery }
128e08fbffcSVernon Mauery 
129e08fbffcSVernon Mauery template <typename Filter>
registerFilter(int prio,const Filter & filter)130e08fbffcSVernon Mauery void registerFilter(int prio, const Filter& filter)
131e08fbffcSVernon Mauery {
132e08fbffcSVernon Mauery     auto f = ipmi::makeFilter(filter);
133e08fbffcSVernon Mauery     impl::registerFilter(prio, f);
134e08fbffcSVernon Mauery }
135e08fbffcSVernon Mauery 
13608a70aa5SVernon Mauery } // namespace ipmi
137