source: trunk/FACT++/src/timecheck.cc@ 20115

Last change on this file since 20115 was 14679, checked in by tbretz, 12 years ago
The service name was incorrect. It should be TIME_CHECK/OFFSET
File size: 6.0 KB
Line 
1#include "StateMachineDim.h"
2
3#include "tools.h"
4#include "Time.h"
5#include "Configuration.h"
6#include "LocalControl.h"
7
8using namespace std;
9
10// ------------------------------------------------------------------------
11
12#include "DimDescriptionService.h"
13
14// ========================================================================
15// ========================================================================
16// ========================================================================
17
18class StateMachineTimeCheck : public StateMachineDim
19{
20private:
21 Time fLastUpdate;
22
23 string fServer;
24 uint16_t fInterval;
25
26 DimDescribedService fService;
27
28 enum
29 {
30 kStateOutOfRange = 1,
31 kStateRunning = 2,
32 };
33
34 // ------------- Initialize variables before the Dim stuff ------------
35
36 int Execute()
37 {
38 Time now;
39 if (now-fLastUpdate<boost::posix_time::minutes(fInterval))
40 return kStateRunning;
41
42 fLastUpdate=now;
43
44 const string cmd = "ntpdate -q "+fServer;
45
46 Info("Calling '"+cmd+"'");
47
48 // !!!!! Warning: this is a blocking operation !!!!!
49 FILE *pipe = popen(cmd.c_str(), "r");
50 if (!pipe)
51 {
52 const string err = strerror(errno);
53 Error("Could not create pipe '"+cmd+"': "+err);
54 return 0x100;
55 }
56
57 vector<string> args;
58
59 string line;
60 while (1)
61 {
62 const int rc = fgetc(pipe);
63 if (rc==EOF || rc=='\n')
64 {
65 args.push_back(Tools::Trim(line));
66 break;
67 }
68
69 if (rc==',')
70 {
71 args.push_back(Tools::Trim(line));
72 line = "";
73 continue;
74 }
75
76 line += static_cast<unsigned char>(rc);
77 }
78 pclose(pipe);
79
80 if (args.size()!=4)
81 {
82 Error("First returned line contains other than four arguments (separated by commas)");
83 return 0x100;
84 }
85
86 if (args[2].substr(0, 7)!="offset ")
87 {
88 Error("Argument 3 '"+args[2]+"' is not what it ought to be.");
89 return 0x100;
90 }
91
92 try
93 {
94 const float offset = stof(args[2].substr(7));
95 fService.Update(offset);
96
97 const string msg = "NTP: "+fServer+" returned: "+args[2]+" ms";
98
99 if (offset>=1000)
100 {
101 Warn(msg);
102 return kStateOutOfRange;
103 }
104
105 Message(msg);
106
107 }
108 catch (const exception &e)
109 {
110 Error("Converting offset '"+args[2]+"' to float failed: "+e.what());
111 return 0x100;
112 }
113
114 return kStateRunning;
115 }
116
117 int Trigger()
118 {
119 fLastUpdate = Time()-boost::posix_time::minutes(fInterval);
120 return GetCurrentState();
121 }
122
123public:
124 StateMachineTimeCheck(ostream &out=cout) : StateMachineDim(out, "TIME_CHECK"),
125 fService("TIME_CHECK/OFFSET", "F:1", "Time offset measured with ntp|offset[ms]:Time offset in milliseconds")
126 {
127 // State names
128 AddStateName(kStateRunning, "Valid", "Last check was valid.");
129 AddStateName(kStateOutOfRange, "OutOfRange", "Last time check exceeded 1s.");
130
131 AddEvent("TRIGGER");
132 (bind(&StateMachineTimeCheck::Trigger, this))
133 ("Trigger update");
134
135 }
136 int EvalOptions(Configuration &conf)
137 {
138 fServer = conf.Get<string>("ntp-server");
139 fInterval = conf.Get<uint16_t>("interval");
140 if (fInterval==0)
141 fInterval=1;
142
143 Trigger();
144
145 return -1;
146 }
147};
148
149// ------------------------------------------------------------------------
150
151#include "Main.h"
152
153template<class T>
154int RunShell(Configuration &conf)
155{
156 return Main::execute<T, StateMachineTimeCheck>(conf);
157}
158
159void SetupConfiguration(Configuration &conf)
160{
161 po::options_description control("Time check");
162 control.add_options()
163 ("ntp-server", var<string>("hora.roa.es"), "The ntp server to be queried")
164 ("interval", var<uint16_t>(15), "Interval in minutes the ntp server should be queried")
165 ;
166
167 conf.AddOptions(control);
168}
169
170/*
171 Extract usage clause(s) [if any] for SYNOPSIS.
172 Translators: "Usage" and "or" here are patterns (regular expressions) which
173 are used to match the usage synopsis in program output. An example from cp
174 (GNU coreutils) which contains both strings:
175 Usage: cp [OPTION]... [-T] SOURCE DEST
176 or: cp [OPTION]... SOURCE... DIRECTORY
177 or: cp [OPTION]... -t DIRECTORY SOURCE...
178 */
179void PrintUsage()
180{
181 /*
182 cout <<
183 "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
184 "\n"
185 "The default is that the program is started without user intercation. "
186 "All actions are supposed to arrive as DimCommands. Using the -c "
187 "option, a local shell can be initialized. With h or help a short "
188 "help message about the usuage can be brought to the screen.\n"
189 "\n"
190 "Usage: smartfact [-c type] [OPTIONS]\n"
191 " or: smartfact [OPTIONS]\n";
192 cout << endl;*/
193}
194
195void PrintHelp()
196{
197 Main::PrintHelp<StateMachineTimeCheck>();
198
199 /* Additional help text which is printed after the configuration
200 options goes here */
201
202 /*
203 cout << "bla bla bla" << endl << endl;
204 cout << endl;
205 cout << "Environment:" << endl;
206 cout << "environment" << endl;
207 cout << endl;
208 cout << "Examples:" << endl;
209 cout << "test exam" << endl;
210 cout << endl;
211 cout << "Files:" << endl;
212 cout << "files" << endl;
213 cout << endl;
214 */
215}
216
217int main(int argc, const char* argv[])
218{
219 Configuration conf(argv[0]);
220 conf.SetPrintUsage(PrintUsage);
221 Main::SetupConfiguration(conf);
222 SetupConfiguration(conf);
223
224 if (!conf.DoParse(argc, argv, PrintHelp))
225 return 127;
226
227 if (!conf.Has("console"))
228 return RunShell<LocalStream>(conf);
229
230 if (conf.Get<int>("console")==0)
231 return RunShell<LocalShell>(conf);
232 else
233 return RunShell<LocalConsole>(conf);
234
235 return 0;
236}
Note: See TracBrowser for help on using the repository browser.