IBR-DTNSuite  0.10
Clock.cpp
Go to the documentation of this file.
1 /*
2  * Clock.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "ibrdtn/utils/Clock.h"
23 #include "ibrdtn/data/AgeBlock.h"
24 
25 #include <ibrcommon/Logger.h>
26 #include <iomanip>
27 
28 namespace dtn
29 {
30  namespace utils
31  {
32  int Clock::_timezone = 0;
33  double Clock::_rating = 0;
34  bool Clock::_badclock = false;
35 
36  struct timeval Clock::_offset;
37  bool Clock::_offset_init = false;
38 
39  bool Clock::_modify_clock = false;
40 
41  // store the timestamp at start-up
42  const dtn::data::Timestamp Clock::_boot_timestamp = Clock::getUnixTimestamp();
43 
48 
49  Clock::Clock()
50  {
51  }
52 
53  Clock::~Clock()
54  {
55  }
56 
57  bool Clock::isBad()
58  {
59  return _badclock;
60  }
61 
62  void Clock::setBad(bool val)
63  {
64  _badclock = val;
65  }
66 
68  {
69  return _timezone;
70  }
71 
72  void Clock::setTimezone(int val)
73  {
74  _timezone = val;
75  }
76 
78  {
79  return _rating;
80  }
81 
82  void Clock::setRating(double val)
83  {
84  _rating = val;
85 
86  // debug quality of time
87  IBRCOMMON_LOGGER_DEBUG_TAG("Clock", 25) << "new clock rating is " << std::setprecision(16) << val << IBRCOMMON_LOGGER_ENDL;
88  }
89 
91  {
92  return _modify_clock;
93  }
94 
95  void Clock::setModifyClock(bool val)
96  {
97  _modify_clock = val;
98  }
99 
101  {
102  if ((b.timestamp == 0) || dtn::utils::Clock::isBad())
103  {
104  // use the AgeBlock to verify the age
105  try {
106  const dtn::data::AgeBlock &agebl = b.find<const dtn::data::AgeBlock>();
107  dtn::data::Number seconds_left = 0;
108  if (b.lifetime > agebl.getSeconds()) {
109  seconds_left = b.lifetime - agebl.getSeconds();
110  }
111  return getTime() + seconds_left;
113  }
114 
115  return __getExpireTime(b.timestamp, b.lifetime);
116  }
117 
119  {
120  return __getExpireTime(timestamp, lifetime);
121  }
122 
124  {
125  return __getExpireTime(getTime(), lifetime);
126  }
127 
129  {
130  // if the timestamp of the bundle is larger than the expiretime
131  // the bundle is invalid
132  if (id.timestamp > expiretime) return 0;
133 
134  // else the lifetime is the difference between the timestamp and the expiretime
135  return id.timestamp - expiretime;
136  }
137 
138  dtn::data::Number Clock::__getExpireTime(const dtn::data::Timestamp &timestamp, const dtn::data::Number &lifetime)
139  {
140  // if the quality of time is zero, return standard expire time
141  if (Clock::getRating() == 0) return timestamp + lifetime;
142 
143  // calculate sigma based on the quality of time and the original lifetime
144  double sigma_error = lifetime.get<double>() * (1 - Clock::getRating());
145 
146  // expiration adjusted by quality of time
147  return timestamp + lifetime + dtn::data::Number(static_cast<dtn::data::Size>(sigma_error));
148  }
149 
151  {
152  // use the AgeBlock to verify the age
153  try {
154  const dtn::data::AgeBlock &agebl = b.find<const dtn::data::AgeBlock>();
155  return (b.lifetime < agebl.getSeconds());
157 
158  return __isExpired(b.timestamp, b.lifetime);
159  }
160 
161  bool Clock::isExpired(const dtn::data::Timestamp &timestamp, const dtn::data::Number &lifetime)
162  {
163  return __isExpired(timestamp, lifetime);
164  }
165 
166  bool Clock::__isExpired(const dtn::data::Timestamp &timestamp, const dtn::data::Number &lifetime)
167  {
168  // if the quality of time is zero or the clock is bad, then never expire a bundle
169  if ((Clock::getRating() == 0) || dtn::utils::Clock::isBad()) return false;
170 
171  // calculate sigma based on the quality of time and the original lifetime
172  const double sigma_error = lifetime.get<double>() * (1 - Clock::getRating());
173 
174  // calculate adjusted expire time
175  const dtn::data::Timestamp expiretime = timestamp + lifetime + dtn::data::Number(static_cast<dtn::data::Size>(sigma_error));
176 
177  // expiration adjusted by quality of time
178  if ( Clock::getTime() > expiretime) return true;
179 
180  return false;
181  }
182 
184  {
185  struct timeval now;
186  Clock::gettimeofday(&now);
187 
188  // timezone
189  dtn::data::Timestamp offset = Clock::getTimezone() * 3600;
190 
191  // do we believe we are before the year 2000?
192  if (dtn::data::Timestamp(now.tv_sec) < TIMEVAL_CONVERSION)
193  {
194  return 0;
195  }
196 
197  return (dtn::data::Timestamp(now.tv_sec) - TIMEVAL_CONVERSION) + offset;
198  }
199 
201  {
202  struct timeval now;
203  Clock::gettimeofday(&now);
204 
205  // timezone
206  dtn::data::Timestamp offset = Clock::getTimezone() * 3600;
207 
208  return offset + now.tv_sec;
209  }
210 
211  const struct timeval& Clock::getOffset()
212  {
213  return Clock::_offset;
214  }
215 
216  void Clock::setOffset(const struct timeval &tv)
217  {
219  {
220  if (!Clock::_offset_init)
221  {
222  timerclear(&Clock::_offset);
223  Clock::_offset_init = true;
224  }
225  timeradd(&Clock::_offset, &tv, &Clock::_offset);
226  IBRCOMMON_LOGGER_TAG("Clock", info) << "new local offset: " << Clock::toDouble(_offset) << "s" << IBRCOMMON_LOGGER_ENDL;
227  }
228  else
229  {
230  struct timezone tz;
231  struct timeval now;
232  ::gettimeofday(&now, &tz);
233 
234  // adjust by the offset
235  timersub(&now, &tv, &now);
236 
237  // set the local clock to the new timestamp
238  ::settimeofday(&now, &tz);
239  }
240  }
241 
242  void Clock::settimeofday(struct timeval *tv)
243  {
244  struct timezone tz;
245  struct timeval now;
246  ::gettimeofday(&now, &tz);
247 
249  {
250  if (!Clock::_offset_init)
251  {
252  timerclear(&Clock::_offset);
253  Clock::_offset_init = true;
254  }
255  timersub(&now, tv, &Clock::_offset);
256  IBRCOMMON_LOGGER_TAG("Clock", info) << "new local offset: " << Clock::toDouble(_offset) << "s" << IBRCOMMON_LOGGER_ENDL;
257  }
258  else
259  {
260  // set the local clock to the new timestamp
261  ::settimeofday(tv, &tz);
262  }
263  }
264 
265  void Clock::gettimeofday(struct timeval *tv)
266  {
267  struct timezone tz;
268  ::gettimeofday(tv, &tz);
269 
270  // correct by the local offset
272  {
273  if (!Clock::_offset_init)
274  {
275  timerclear(&Clock::_offset);
276  Clock::_offset_init = true;
277  }
278  // add offset
279  timersub(tv, &Clock::_offset, tv);
280  }
281  }
282 
283  double Clock::toDouble(const timeval &val) {
284  return static_cast<double>(val.tv_sec) + (static_cast<double>(val.tv_usec) / 1000000.0);
285  }
286 
288  {
289  if (Clock::getUnixTimestamp() < _boot_timestamp)
290  return 0;
291 
292  return Clock::getUnixTimestamp() - _boot_timestamp;
293  }
294  }
295 }