1 /** 2 * Copyright © 2018 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 #include <algorithm> 18 #include <boost/callable_traits.hpp> 19 #include <cstdint> 20 #include <ipmid/api-types.hpp> 21 #include <ipmid/message.hpp> 22 #include <memory> 23 #include <tuple> 24 #include <utility> 25 26 namespace ipmi 27 { 28 29 using FilterFunction = ipmi::Cc(ipmi::message::Request::ptr); 30 31 /** 32 * @brief Filter base class for dealing with IPMI request/response 33 * 34 * The subclasses are all templated so they can provide access to any type of 35 * command callback functions. 36 */ 37 class FilterBase 38 { 39 public: 40 using ptr = std::shared_ptr<FilterBase>; 41 42 virtual ~FilterBase() = default; 43 44 virtual ipmi::Cc call(message::Request::ptr request) = 0; 45 }; 46 47 /** 48 * @brief filter concrete class 49 * 50 * This is the base template that ipmi filters will resolve into. This is 51 * essentially just a wrapper to hold the filter callback so it can be stored in 52 * the filter list. 53 * 54 * Filters are called with a ipmi::message::Request shared_ptr on all IPMI 55 * commands in priority order and each filter has the opportunity to reject the 56 * command (by returning an IPMI error competion code.) If all the filters 57 * return success, the actual IPMI command will be executed. Filters can reject 58 * the command for any reason, based on system state, the context, the command 59 * payload, etc. 60 */ 61 template <typename Filter> 62 class IpmiFilter : public FilterBase 63 { 64 public: 65 IpmiFilter(Filter&& filter) : filter_(std::move(filter)) 66 { 67 } 68 69 ipmi::Cc call(message::Request::ptr request) override 70 { 71 return filter_(request); 72 } 73 74 private: 75 Filter filter_; 76 }; 77 78 /** 79 * @brief helper function to construct a filter object 80 * 81 * This is called internally by the ipmi::registerFilter function. 82 */ 83 template <typename Filter> 84 static inline auto makeFilter(Filter&& filter) 85 { 86 FilterBase::ptr ptr(new IpmiFilter<Filter>(std::forward<Filter>(filter))); 87 return ptr; 88 } 89 template <typename Filter> 90 static inline auto makeFilter(const Filter& filter) 91 { 92 Filter lFilter = filter; 93 return makeFilter(std::forward<Filter>(lFilter)); 94 } 95 96 namespace impl 97 { 98 99 // IPMI command filter registration implementation 100 void registerFilter(int prio, ::ipmi::FilterBase::ptr filter); 101 102 } // namespace impl 103 104 /** 105 * @brief IPMI command filter registration function 106 * 107 * This function should be used to register IPMI command filter functions. 108 * This function just passes the callback to makeFilter, which creates a 109 * wrapper functor object that ultimately calls the callback. 110 * 111 * Filters are called with a ipmi::message::Request shared_ptr on all IPMI 112 * commands in priority order and each filter has the opportunity to reject the 113 * command (by returning an IPMI error competion code.) If all the filters 114 * return success, the actual IPMI command will be executed. Filters can reject 115 * the command for any reason, based on system state, the context, the command 116 * payload, etc. 117 * 118 * @param prio - priority at which to register; see api.hpp 119 * @param filter - the callback function that will handle this request 120 * 121 * @return bool - success of registering the handler 122 */ 123 template <typename Filter> 124 void registerFilter(int prio, Filter&& filter) 125 { 126 auto f = ipmi::makeFilter(std::forward<Filter>(filter)); 127 impl::registerFilter(prio, f); 128 } 129 130 template <typename Filter> 131 void registerFilter(int prio, const Filter& filter) 132 { 133 auto f = ipmi::makeFilter(filter); 134 impl::registerFilter(prio, f); 135 } 136 137 } // namespace ipmi 138