1 #include <sys/select.h>
4 #include <curl/types.h>
11 #include <boost/bind.hpp>
13 #include "snmp_pp/snmp_pp.h"
18 #include "subscriber.h"
19 #include "datatypes.h"
25 using GTS::Subscriber;
28 Timer::Timer(boost::function<void ()> callback, time_t interval)
29 : _interval(interval),
39 int Timer::getTimeout() const
41 double delta = difftime(time(NULL), _lastFire);
42 return _interval - delta;
51 Syncer::Syncer(SettingsParser & sp,
53 : _settingsParser(sp),
57 _timers.push_back(Timer(boost::bind(&Syncer::syncInfo, this),
58 _settingsParser.settings().infoSyncInterval()));
65 void Syncer::run(const bool & running, bool & reload)
67 logger << "Syncer::run()" << std::endl;
70 logger << "Syncer::run() - wait stopped by signal" << std::endl;
74 logger << "Syncer::run() - reload" << std::endl;
76 _settingsParser.reloadConfig();
78 catch (std::exception & ex) {
79 logger << "Syncer::run() - exception: " << ex.what() << std::endl;
89 Timer & timer(getNextTimer());
91 if (timer.getTimeout() > 0) {
97 tv.tv_sec = timer.getTimeout();
100 int retval = select(1, &rfds, NULL, NULL, &tv);
112 Timer & Syncer::getNextTimer()
114 assert(_timers.size() && "Timer list must not be empty!");
115 int timeout = _timers.begin()->getTimeout();
116 std::list<Timer>::iterator it(_timers.begin());
117 std::list<Timer>::iterator pos(_timers.begin());
119 while (it != _timers.end()) {
120 if (it->getTimeout() < timeout) {
122 timeout = pos->getTimeout();
129 void Syncer::syncInfo()
131 std::map<std::string, Switch> switches;
132 if (!getSwitchesState(switches)) {
133 logger << "Syncer::syncInfo() - failed to get new switch states" << std::endl;
136 std::list<TimedSwitch>::iterator it(_switches.begin());
137 while (it != _switches.end()) {
138 _timers.erase(it->second);
139 _switches.erase(it++);
141 std::map<std::string, Switch>::const_iterator sit;
142 for (sit = switches.begin(); sit != switches.end(); ++sit) {
143 // Insert switch with no timer
144 _switches.push_back(std::make_pair(sit->second, _timers.end()));
145 // Insert timer for this switch
146 TimerIterator tit = _timers.insert(
148 Timer(boost::bind(&Switch::sync, &_switches.back().first),
149 _settingsParser.settings().switchSyncInterval()));
150 // Set timer iterator for this switch
151 _switches.back().second = tit;
153 logger << "Syncer::syncInfo() - data synchronization successfull, switches: " << _switches.size() << std::endl;
156 size_t curlWriteFunction(void * ptr, size_t size, size_t nmemb, void * userdata)
158 char * data = static_cast<char *>(ptr);
159 std::string * dest = static_cast<std::string *>(userdata);
160 dest->append(data, size * nmemb);
164 bool Syncer::getDBData(std::string & data) const
166 CURL * handle = curl_easy_init();
168 char errorBuffer[CURL_ERROR_SIZE];
169 curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); // Accept self-signed certs
170 curl_easy_setopt(handle, CURLOPT_LOW_SPEED_LIMIT, 1); // Less than 1 bps
171 curl_easy_setopt(handle, CURLOPT_LOW_SPEED_TIME, 60); // During 60 secs
172 curl_easy_setopt(handle, CURLOPT_URL, _settingsParser.settings().dataURL().c_str()); // Our URL
173 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curlWriteFunction); // Our write callback
174 curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data); // Our callback data
175 curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errorBuffer); // Buffer for an error messages
176 CURLcode res = curl_easy_perform(handle);
178 logger << "Syncer::getDBData() - DB communication error: '" << errorBuffer << "'" << std::endl;
179 curl_easy_cleanup(handle);
182 curl_easy_cleanup(handle);
185 logger << "Syncer::getDBData() - failed to init CURL library" << std::endl;
189 bool Syncer::getSwitchesState(std::map<std::string, Switch> & switches)
191 if (_settingsParser.settings().dataURL().empty()) {
192 logger << "Switch::getSwitchesState() - data URL is empty" << std::endl;
196 if (!getDBData(data)) {
197 logger << "Syncer::getSwitchesState() - failed to fetch data from the URL: '" << _settingsParser.settings().dataURL() << "'" << std::endl;
201 if (!parseData(data, lines)) {
202 logger << "Syncer::getSwitchesState() - failed to parse data:\n" << data << std::endl;
205 Lines::const_iterator it;
206 for (it = lines.begin(); it != lines.end(); ++it) {
207 std::pair<std::map<std::string, Switch>::iterator, bool> res(
212 _settingsParser.settings(),
222 res.first->second.addSubscriber(