#include <tr_rp.h>
#include <tr_idp.h>
#include <tr_name_internal.h>
+#include <trp_internal.h>
#include <tr_comm.h>
#include <tr_debug.h>
-
+#include <tr_util.h>
static int tr_comm_destructor(void *obj)
{
return memb->expiry;
}
+/**
+ * Get the expiration according to the realtime clock
+ *
+ * @param memb
+ * @param result space to store the result
+ * @return pointer to the result, or null on error
+ */
+struct timespec *tr_comm_memb_get_expiry_realtime(TR_COMM_MEMB *memb, struct timespec *result)
+{
+ return tr_clock_convert(TRP_CLOCK, memb->expiry, CLOCK_REALTIME, result);
+}
+
int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime)
{
tr_debug("tr_comm_memb_is_expired: (cur->tv_sec>memb->expiry->tv_sec)=(%u > %u)=%s",
static json_t *expiry_to_json_string(TR_COMM_MEMB *memb)
{
- struct timespec ts_zero = {0, 0};
+ struct timespec ts = {0}; /* initialization to zero is important */
char *s = NULL;
json_t *jstr = NULL;
- if (tr_cmp_timespec(tr_comm_memb_get_expiry(memb), &ts_zero) == 0) {
- s = strdup("");
- } else {
- s = timespec_to_str(tr_comm_memb_get_expiry(memb));
- }
+ if (tr_cmp_timespec(tr_comm_memb_get_expiry(memb), &ts) > 0) {
+ if (tr_comm_memb_get_expiry_realtime(memb, &ts) == NULL)
+ s = strdup("error");
+ else
+ s = timespec_to_str(&ts);
- if (s) {
- jstr = json_string(s);
- free(s);
+ if (s) {
+ jstr = json_string(s);
+ free(s);
+ }
}
return jstr;
}
}
-/* Returns 0 if ts1==ts2, <0 if ts1<ts2, >= if ts1>ts2.
- * Assumes that tv_nsec <= 1e9. */
-int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2)
+/**
+ * Compare two timespecs
+ *
+ * Assumes tv_nsec <= 1e9
+ *
+ * @param ts1
+ * @param ts2
+ * @return 0 if ts1==ts2, -1 if ts1<ts2, 1 if ts1>ts2.
+ */
+int tr_cmp_timespec(const struct timespec *ts1, const struct timespec *ts2)
{
if (ts1->tv_sec > ts2->tv_sec)
return 1;
}
/**
+ * Compute ts1 + ts2
+ *
+ * @param ts1
+ * @param ts2
+ * @param sum ts1 + ts2
+ * @return 0 on success, nonzero on error
+ */
+int tr_add_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *sum)
+{
+ const time_t ONE_BILLION = 1000000000;
+
+ if (!ts1 || !ts2 || !sum)
+ return -1;
+
+ /* would be nice to do range checking, but I don't know a portable way to get the
+ * max value of a time_t. Figure that nsec <= 1e9 and seconds are unlikely to go off
+ * too close to infinity, so overflow is unlikely */
+ sum->tv_nsec = ts1->tv_nsec + ts2->tv_nsec;
+ sum->tv_sec = ts1->tv_sec + ts2->tv_sec;
+
+ /* make sure that we have no more than a second worth of nsec */
+ while (sum->tv_nsec >= ONE_BILLION) {
+ sum->tv_nsec -= ONE_BILLION;
+ sum->tv_sec += 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Compute ts1 - ts2
+ *
+ * Allows negative results, which will be represented as a negative tv_sec.
+ * The returned tv_nsec is always positive and less than 1e9.
+ *
+ * (The value represented is tv_sec + tv_nsec/1e9 seconds - this is a little
+ * counterintuitive when tv_sec is positive. E.g., -1.5 seconds is represented
+ * as {-2, 500000000).)
+ *
+ * @param ts1
+ * @param ts2
+ * @param diff ts1 - ts2
+ * @return 0 on success, nonzero on error
+ */
+int tr_sub_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *diff)
+{
+ const time_t ONE_BILLION = 1000000000;
+ struct timespec ts1_copy = {0};
+ struct timespec ts2_copy = {0};
+
+ if (!ts1 || !ts2 || !diff)
+ return -1;
+
+ ts1_copy = *ts1;
+ ts2_copy = *ts2;
+
+ while (ts2_copy.tv_nsec > ts1_copy.tv_nsec) {
+ /* Reduce ts2 by one second worth of nsec, balanced by removing a second
+ * from ts1. Repeat until ts2->tv_nsec <= ts1->tv_nsec. */
+ ts2_copy.tv_nsec -= ONE_BILLION;
+ ts1_copy.tv_sec -= 1;
+ }
+
+ diff->tv_nsec = ts1_copy.tv_nsec - ts2_copy.tv_nsec; /* >= 0 */
+ diff->tv_sec = ts1_copy.tv_sec - ts2_copy.tv_sec; /* sign indeterminate */
+
+ /* make sure we have no more than 1 sec worth of nsec */
+ while (diff->tv_nsec > ONE_BILLION) {
+ diff->tv_nsec -= ONE_BILLION;
+ diff->tv_sec += 1;
+ }
+
+ return 0;
+}
+
+/**
* Convert a struct timespec to a string representation
* @param ts
* @return
*/
-char *timespec_to_str(struct timespec *ts)
+char *timespec_to_str(const struct timespec *ts)
{
struct tm tm;
char *s=NULL;
- if (localtime_r(&(ts->tv_sec), &tm)==NULL)
+ if (gmtime_r(&(ts->tv_sec), &tm)==NULL)
return NULL;
s=malloc(40); /* long enough to contain strftime result */
if (s==NULL)
return NULL;
- if (strftime(s, 40, "%F %T", &tm)==0) {
+ if (strftime(s, 40, "%F %T UTC", &tm)==0) {
free(s);
return NULL;
}
return s;
}
+/**
+ * Convert a time from one clock to another
+ *
+ * Because this involves reading each clock, it is not exact.
+ *
+ * @param from clock to convert from
+ * @param when time to convert, measured on the 'from' clock
+ * @param to clock to convert to
+ * @param dst destination, measured on the 'to' clock
+ * @return dst or null on error
+ */
+struct timespec *tr_clock_convert(clockid_t from, const struct timespec *when,
+ clockid_t to, struct timespec *dst)
+{
+ struct timespec now_from = {0};
+ struct timespec diff = {0}; /* difference between when and now_from */
+ struct timespec now_to = {0};
+
+ if ((clock_gettime(from, &now_from) != 0)
+ || (clock_gettime(to, &now_to) != 0)) {
+ return NULL;
+ }
+ if (tr_sub_timespec(when, &now_from, &diff) != 0) {
+ return NULL;
+ }
+ if (tr_add_timespec(&now_to, &diff, dst) != 0) {
+ return NULL;
+ }
+ return dst;
+}
\ No newline at end of file
unsigned int tr_comm_memb_get_interval(TR_COMM_MEMB *memb);
void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time);
struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb);
+struct timespec *tr_comm_memb_get_expiry_realtime(TR_COMM_MEMB *memb, struct timespec *result);
int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime);
void tr_comm_memb_set_triggered(TR_COMM_MEMB *memb, int trig);
int tr_comm_memb_is_triggered(TR_COMM_MEMB *memb);
/* NB, tr_bin_to_hex() is also prototyped in trust_router/tr_dh.h */
TR_EXPORT void tr_bin_to_hex(const unsigned char * bin, size_t binlen,
char * hex_out, size_t hex_len);
-TR_EXPORT int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2);
-char *timespec_to_str(struct timespec *ts);
+TR_EXPORT int tr_cmp_timespec(const struct timespec *ts1, const struct timespec *ts2);
+int tr_add_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *sum);
+int tr_sub_timespec(const struct timespec *ts1_copy, const struct timespec *ts2_copy, struct timespec *diff);
+char *timespec_to_str(const struct timespec *ts);
+struct timespec *tr_clock_convert(clockid_t from, const struct timespec *when,
+ clockid_t to, struct timespec *dst);
#endif /* TR_UTIL_H */
int trp_route_get_interval(TRP_ROUTE *entry);
void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp);
struct timespec *trp_route_get_expiry(TRP_ROUTE *entry);
+struct timespec *trp_route_get_expiry_realtime(TRP_ROUTE *comm, struct timespec *result);
void trp_route_set_local(TRP_ROUTE *entry, int local);
int trp_route_is_local(TRP_ROUTE *entry);
void trp_route_set_triggered(TRP_ROUTE *entry, int trig);
#include <tr_debug.h>
#include <trust_router/trp.h>
#include <trust_router/tid.h>
+#include <tr_util.h>
/* Note: be careful mixing talloc with glib. */
return entry->expiry;
}
+/**
+ * Get the expiration according to the realtime clock
+ *
+ * @param entry
+ * @param result space to store the result
+ * @return pointer to the result, or null on error
+ */
+struct timespec *trp_route_get_expiry_realtime(TRP_ROUTE *entry, struct timespec *result)
+{
+ return tr_clock_convert(TRP_CLOCK, entry->expiry, CLOCK_REALTIME, result);
+}
+
void trp_route_set_local(TRP_ROUTE *entry, int local)
{
entry->local=local;
/* helper */
static json_t *expiry_to_json_string(TRP_ROUTE *route)
{
- struct timespec ts_zero = {0, 0};
+ struct timespec ts = {0}; /* initialization to zero is important */
char *s = NULL;
json_t *jstr = NULL;
- if (tr_cmp_timespec(trp_route_get_expiry(route), &ts_zero) > 0) {
- s = timespec_to_str(trp_route_get_expiry(route));
+ if (tr_cmp_timespec(trp_route_get_expiry(route), &ts) > 0) {
+ if (trp_route_get_expiry_realtime(route, &ts) == NULL)
+ s = strdup("error");
+ else
+ s = timespec_to_str(&ts);
if (s) {
jstr = json_string(s);
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
struct timespec sweep_time={0,0};
+ struct timespec tmp = {0};
TR_COMM_MEMB *memb=NULL;
TR_COMM_ITER *iter=NULL;
TRP_RC rc=TRP_ERROR;
tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf,
tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf,
tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf,
- timespec_to_str(tr_comm_memb_get_expiry(memb)));
+ timespec_to_str(tr_comm_memb_get_expiry_realtime(memb, &tmp)));
tr_comm_table_remove_memb(trps->ctable, memb);
tr_comm_memb_free(memb);
} else {
tr_comm_memb_expire(memb);
trps_compute_expiry(trps, tr_comm_memb_get_interval(memb), tr_comm_memb_get_expiry(memb));
tr_debug("trps_sweep_ctable: community membership expired at %s, resetting expiry to %s (%.*s in %.*s, origin %.*s).",
- timespec_to_str(&sweep_time),
- timespec_to_str(tr_comm_memb_get_expiry(memb)),
+ timespec_to_str(tr_clock_convert(TRP_CLOCK, &sweep_time, CLOCK_REALTIME, &tmp)),
+ timespec_to_str(tr_comm_memb_get_expiry_realtime(memb, &tmp)),
tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf,
tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf,
tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf);