blob: 23560a40f3ec9f017f39aa6ac9becb3857b1d389 [file] [log] [blame]
Vishwanatha81ee91f2016-08-30 17:17:13 +05301#include <systemd/sd-bus.h>
2#include <fstream>
3#include <string>
4#include <chrono>
5#include "time-config.hpp"
6
7/** @class Time
8 * @brief Base class catering to common data needed by implementations
9 */
10class Time
11{
12public:
13 /** @brief Takes time in microseconds and uses systemd/timedated
14 * to set the system time
15 *
16 * @param[in] timeOfDayUsec - Time value in microseconds
Vishwanatha Subbannaeaee4552017-07-06 15:01:45 +053017 * @param[out] retError - Error message on failure
Vishwanatha81ee91f2016-08-30 17:17:13 +053018 * @return - Status of time set operation
Vishwanatha Subbannaeaee4552017-07-06 15:01:45 +053019 * @error - Error message populated
Vishwanatha81ee91f2016-08-30 17:17:13 +053020 */
Vishwanatha Subbannaeaee4552017-07-06 15:01:45 +053021 int setTimeOfDay(const std::chrono::microseconds& timeOfDayUsec,
22 sd_bus_error *retError);
Vishwanatha81ee91f2016-08-30 17:17:13 +053023
24 /** @brief Reads BMC time
25 *
26 * @param[in] - None
27 * @return - time read in microseconds
28 */
29 std::chrono::microseconds getBaseTime();
30
31 /** @brief Converts microseconds to human readable time value
32 *
33 * @param[in] timeInUsec - Time value in microseconds
34 * @return - Time converted to human readable format
35 */
36 std::string convertToStr(const std::chrono::microseconds& timeInUsec);
37
38 /** @brief Reference to config information due to need of policy data */
39 const TimeConfig& config;
40
41 /** Needed to access configuration variables */
42 Time(const TimeConfig&);
43
44private:
45 Time();
46};
47
48/** @class BmcTime
49 * @brief Provides time Set and time Get operations for BMC target
50 */
51class BmcTime: public Time
52{
53public:
54 /** @brief Called when the time is to be read on BMC
55 *
56 * @param[in] m - sd_bus message.
57 * @param[out] retError - Error reporting structure
58 * @return - On no error, time read which is specified in
59 * microseonds and also in human readable format.
60 *
61 * - On error, retError populated
62 */
63 int getTime(sd_bus_message* m, sd_bus_error* retError);
64
65 /** @brief Called when the time is to be set on BMC
66 *
67 * @param[in] m - sd_bus message encapsulating time string
68 * @param[out] retError - Error reporting structure
69 * @return - On no error, 0, -1 otherwise or retError thrown
70 */
71 int setTime(sd_bus_message* m, sd_bus_error* retError);
72
73 /** @brief constructor */
74 BmcTime(const TimeConfig&);
75
76private:
77 BmcTime();
78};
79
80/** @class HostTime
81 * @brief Provides time Set and time Get operations for BMC target
82 */
83class HostTime: public Time
84{
85public:
86 /** @brief Called when IPMI_GET_SEL_TIME is called
87 *
88 * @param[in] m - sd_bus message.
89 * @param[out] retError - Error reporting structure
90 * @return - On no error, time read which is specified in
91 * microseonds and also in human readable format.
92 *
93 * - On error, retError populated
94 */
95 int getTime(sd_bus_message*, sd_bus_error*);
96
97 /** @brief Called when the IPMI_SET_SEL_TIME is called
98 *
99 * @param[in] m - sd_bus message encapsulating time in seconds
100 * @param[out] retError - Error reporting structure
101 * @return - On no error, 0, -1 otherwise or retError thrown
102 */
103 int setTime(sd_bus_message*, sd_bus_error*);
104
105 /** @brief constructor */
106 HostTime(const TimeConfig&, const std::chrono::microseconds&);
107
108 /** @brief When the owner is SPLIT, the delta between HOST's time and BMC's
109 * time needs to be saved and this function returns current delta.
110 *
111 * @param[in] - None
112 * @return - offset in microseconds
113 */
114 inline std::chrono::microseconds getChangedOffset() const
115 {
116 return changedOffset;
117 }
118
119 /** @brief Reference to host's offset in case of SPLIT owner */
120 const std::chrono::microseconds& iv_Offset;
121
122private:
123 HostTime();
124
125 /** @brief The delta offset of Host and BMC time */
126 std::chrono::microseconds changedOffset;
127};
128
129/** @class TimeManager
130 * @brief Caters to client requests with Set and Get time and configuration
131 * changes
132 */
133class TimeManager
134{
135public:
136 // Do not have a usecase of copying this object so disable
137 TimeManager();
138 ~TimeManager() = default;
139 TimeManager(const TimeManager&) = delete;
140 TimeManager& operator=(const TimeManager&) = delete;
141 TimeManager(TimeManager&&) = delete;
142 TimeManager& operator=(TimeManager&&) = delete;
143
144 // Maintains *all* the config that is needed for TimeManager.
145 TimeConfig config;
146
147 /** @brief Callback handlers invoked by dbus on GetTime client requests
148 *
149 * @param[in] m - sd_bus message encapsulating the time target
150 * @param[in] userdata - context that is filled while registering this
151 * @param[out] retError - Error reporting mechanism
152 *
153 * @return - On no error, time in microseconds and human
154 * readable string. retError otherwise.
155 */
156 int getTime(sd_bus_message* m, void* userdata, sd_bus_error* retError);
157
158 /** @brief Callback handlers invoked by dbus on SetTime client requests
159 *
160 * @param[in] m - sd_bus message encapsulating the time target and
161 * time value either in string or in seconds.
162 * @param[in] userdata - client context that is filled while registering
163 * @param[out] retError - Error reporting mechanism
164 *
165 * @return - On no error, time in microseconds and human
166 * readable string. retError otherwise.
167 */
168 int setTime(sd_bus_message* m, void* userdata, sd_bus_error* retError);
169
170 /** @brief sd_event callback handlers on the requests coming in dbus
171 * These are actually GetTime and SetTime requests
172 *
173 * @param[in] es - Event Structure
174 * @param[in] fd - file descriptor that had 'read' activity
175 * @param[in] revents - generic linux style return event
176 * @param[in] userdata - Client context filled while registering
177 *
178 * @return - 0 for success, failure otherwise.
179 */
180 static int processSdBusMessage(sd_event_source* es, int fd,
181 uint32_t revents, void* userdata);
182
183 /** @brief sd_event callback handler called whenever there is a
184 * time change event indicated by timerfd expiring. This happens
185 * whenever the time is set on BMC by any source.
186 *
187 * @param[in] es - Event Structure
188 * @param[in] fd - file descriptor that had 'read' activity
189 * @param[in] revents - generic linux style return event
190 * @param[in] userdata - Client context filled while registering
191 *
192 * @return - 0 for success, failure otherwise.
193 */
194 static int processTimeChange(sd_event_source* es, int fd,
195 uint32_t revents, void* userdata);
196
197 /** @brief sd_event callback handler called whenever a settings
198 * property is changed.
199 * This gets called into whenever "time_mode", "time_owner",
200 * "use_dhcp_ntp" properties are changed
201 *
202 * @param[in] es - Event Structure
203 * @param[in] fd - file descriptor that had 'read' activity
204 * @param[in] revents - generic linux style return event
205 * @param[in] userdata - Client context filled while registering
206 *
207 * @return - 0 for success, failure otherwise.
208 */
209 static int processPropertyChange(sd_bus_message*,
210 void*,sd_bus_error*);
211
212 /** @brief sd_event callback handler called whenever Pgood property is
213 * changed
214 *
215 * @param[in] es - Event Structure
216 * @param[in] fd - file descriptor that had 'read' activity
217 * @param[in] revents - generic linux style return event
218 * @param[in] userdata - Client context filled while registering
219 *
220 * @return - 0 for success, failure otherwise.
221 */
222 static int processPgoodChange(sd_bus_message*,
223 void*,sd_bus_error*);
224
225 /** @brief registers callsback handlers for sd_event loop
226 *
227 * @param[in] - None
228 * @return - 0 if everything goes well, -1 otherwise
229 */
230 int registerCallbackHandlers();
231
232 /** @brief Makes the Delta between Host and BMC time as 'ZERO'. This
233 * essentially only means that time owner was SPLIT before
234 * and now changed to something else.
235 *
236 * @param[in] - None
237 * @return - 0 if everything goes well, -1 otherwise.
238 */
239 int resetHostOffset();
240
241 /** @brief Reads what was the last delta offset stored in file
242 *
243 * @param[in] - None
244 * @return - 0 if everything goes well, -1 otherwise.
245 */
246 int readPersistentData();
247
248 /** @brief waits on sd_events loop for client requests
249 *
250 * @param[in] - None
251 * @return - 0 if everything goes well, -1 otherwise.
252 */
253 int waitForClientRequest();
254
255 inline auto getHostOffset() const
256 {
257 return iv_HostOffset;
258 }
259
260 inline auto updateHostOffset(const std::chrono::microseconds& newOffset)
261 {
262 iv_HostOffset = newOffset;
263 }
264
265 inline auto getUptimeUsec() const
266 {
267 return iv_UptimeUsec;
268 }
269
270 inline auto updateUptimeUsec(const std::chrono::microseconds& newUpTime)
271 {
272 iv_UptimeUsec = newUpTime;
273 }
274
275 inline sd_bus* getTimeBus() const
276 {
277 return iv_TimeBus;
278 }
279
280private:
281 // What was the last known host offset.
282 std::chrono::microseconds iv_HostOffset;
283
284 // How long was the BMC up for prior to this boot
285 std::chrono::microseconds iv_UptimeUsec;
286
287 // Used for registering sd_bus callback handlers.
288 sd_event_source* iv_EventSource;
289 sd_event* iv_Event;
290 sd_bus* iv_TimeBus;
291
292 // Dbus communication enablers.
293 static constexpr auto cv_BusName = "org.openbmc.TimeManager";
294 static constexpr auto cv_ObjPath = "/org/openbmc/TimeManager";
295 static constexpr auto cv_IntfName = "org.openbmc.TimeManager";
296
297 // Store the offset in File System. Read back when TimeManager starts.
298 static constexpr auto cv_HostOffsetFile = "/var/lib/obmc/saved_host_offset";
299
300 /** @brief Sets up internal data structures and callback handler at startup
301 *
302 * @param[in] - None
303 * @return - 0 if everything goes well, -1 otherwise
304 */
305 int setupTimeManager(void);
306};