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 <boost/callable_traits.hpp>
18 #include <ipmid/api-types.hpp>
19 #include <ipmid/message.hpp>
20
21 #include <algorithm>
22 #include <cstdint>
23 #include <memory>
24 #include <tuple>
25 #include <utility>
26
27 namespace ipmi
28 {
29
30 using FilterFunction = ipmi::Cc(ipmi::message::Request::ptr);
31
32 /**
33 * @brief Filter base class for dealing with IPMI request/response
34 *
35 * The subclasses are all templated so they can provide access to any type of
36 * command callback functions.
37 */
38 class FilterBase
39 {
40 public:
41 using ptr = std::shared_ptr<FilterBase>;
42
43 virtual ~FilterBase() = default;
44
45 virtual ipmi::Cc call(message::Request::ptr request) = 0;
46 };
47
48 /**
49 * @brief filter concrete class
50 *
51 * This is the base template that ipmi filters will resolve into. This is
52 * essentially just a wrapper to hold the filter callback so it can be stored in
53 * the filter list.
54 *
55 * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
56 * commands in priority order and each filter has the opportunity to reject the
57 * command (by returning an IPMI error competion code.) If all the filters
58 * return success, the actual IPMI command will be executed. Filters can reject
59 * the command for any reason, based on system state, the context, the command
60 * payload, etc.
61 */
62 template <typename Filter>
63 class IpmiFilter : public FilterBase
64 {
65 public:
IpmiFilter(Filter && filter)66 IpmiFilter(Filter&& filter) : filter_(std::move(filter)) {}
67
call(message::Request::ptr request)68 ipmi::Cc call(message::Request::ptr request) override
69 {
70 return filter_(request);
71 }
72
73 private:
74 Filter filter_;
75 };
76
77 /**
78 * @brief helper function to construct a filter object
79 *
80 * This is called internally by the ipmi::registerFilter function.
81 */
82 template <typename Filter>
makeFilter(Filter && filter)83 static inline auto makeFilter(Filter&& filter)
84 {
85 FilterBase::ptr ptr(new IpmiFilter<Filter>(std::forward<Filter>(filter)));
86 return ptr;
87 }
88 template <typename Filter>
makeFilter(const Filter & filter)89 static inline auto makeFilter(const Filter& filter)
90 {
91 Filter lFilter = filter;
92 return makeFilter(std::forward<Filter>(lFilter));
93 }
94
95 namespace impl
96 {
97
98 // IPMI command filter registration implementation
99 void registerFilter(int prio, ::ipmi::FilterBase::ptr filter);
100
101 } // namespace impl
102
103 /**
104 * @brief IPMI command filter registration function
105 *
106 * This function should be used to register IPMI command filter functions.
107 * This function just passes the callback to makeFilter, which creates a
108 * wrapper functor object that ultimately calls the callback.
109 *
110 * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
111 * commands in priority order and each filter has the opportunity to reject the
112 * command (by returning an IPMI error competion code.) If all the filters
113 * return success, the actual IPMI command will be executed. Filters can reject
114 * the command for any reason, based on system state, the context, the command
115 * payload, etc.
116 *
117 * @param prio - priority at which to register; see api.hpp
118 * @param filter - the callback function that will handle this request
119 *
120 * @return bool - success of registering the handler
121 */
122 template <typename Filter>
registerFilter(int prio,Filter && filter)123 void registerFilter(int prio, Filter&& filter)
124 {
125 auto f = ipmi::makeFilter(std::forward<Filter>(filter));
126 impl::registerFilter(prio, f);
127 }
128
129 template <typename Filter>
registerFilter(int prio,const Filter & filter)130 void registerFilter(int prio, const Filter& filter)
131 {
132 auto f = ipmi::makeFilter(filter);
133 impl::registerFilter(prio, f);
134 }
135
136 } // namespace ipmi
137