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