diff --git a/include/ipfs/namesys/pb.h b/include/ipfs/namesys/pb.h index 1d47ef6..82468f1 100644 --- a/include/ipfs/namesys/pb.h +++ b/include/ipfs/namesys/pb.h @@ -1,14 +1,19 @@ #ifndef IPNS_NAMESYS_PB_H #define IPNS_NAMESYS_PB_H + #include - typedef int IpnsEntry_ValidityType; + typedef int32_t IpnsEntry_ValidityType; struct ipns_entry { - // TODO - struct routingResolver *cache; - struct stime *eol; + char *value; + char *signature; + int32_t *validityType; + char *validity; + uint64_t *sequence; + uint64_t *ttl; + struct routingResolver *cache; // cache and eol should be the last items. + struct timespec *eol; }; - struct namesys_pb { // TODO struct ipns_entry *IpnsEntry; @@ -23,8 +28,9 @@ }; int IpnsEntry_ValidityType_value (char *s); + struct ipns_entry* ipfs_namesys_pb_new_ipns_entry (); char* ipfs_namesys_pb_get_validity (struct ipns_entry*); - char* ipfs_ipns_entry_data_for_sig(struct ipns_entry*); + char* ipns_entry_data_for_sig(struct ipns_entry*); char* ipfs_ipns_entry_get_signature(struct ipns_entry*); int ipfs_namesys_pb_get_value (char**, struct ipns_entry*); IpnsEntry_ValidityType ipfs_namesys_pb_get_validity_type (struct ipns_entry*); diff --git a/include/ipfs/namesys/publisher.h b/include/ipfs/namesys/publisher.h new file mode 100644 index 0000000..b68afb0 --- /dev/null +++ b/include/ipfs/namesys/publisher.h @@ -0,0 +1,9 @@ +#ifndef IPFS_PUBLISHER_H + #define IPFS_PUBLISHER_H + char* ipns_entry_data_for_sig (struct ipns_entry *entry); + int ipns_selector_func (int *idx, struct ipns_entry ***recs, char *k, char **vals); + int ipns_select_record (int *idx, struct ipns_entry **recs, char **vals); + // ipns_validate_ipns_record implements ValidatorFunc and verifies that the + // given 'val' is an IpnsEntry and that that entry is valid. + int ipns_validate_ipns_record (char *k, char *val); +#endif // IPFS_PUBLISHER_H diff --git a/include/ipfs/namesys/routing.h b/include/ipfs/namesys/routing.h index 7d6fbdd..bebc872 100644 --- a/include/ipfs/namesys/routing.h +++ b/include/ipfs/namesys/routing.h @@ -10,7 +10,7 @@ struct cacheEntry { char *key; char *value; - struct stime eol; + struct timespec eol; }; struct routingResolver { @@ -29,7 +29,8 @@ // ipfs_namesys_routing_resolve_once implements resolver. Uses the IPFS // routing system to resolve SFS-like names. int ipfs_namesys_routing_resolve_once (char **path, char *name, int depth, char *prefix, struct namesys_pb *pb); - int ipfs_namesys_routing_check_EOL (struct stime *st, struct namesys_pb *pb); + int ipfs_namesys_routing_check_EOL (struct timespec *ts, struct namesys_pb *pb); + int ipfs_namesys_routing_get_value (char*, char*); int ipfs_namesys_routing_getpublic_key (char*, struct MultiHash*); #endif // IPNS_NAMESYS_ROUTING_H diff --git a/include/ipfs/util/time.h b/include/ipfs/util/time.h index 3d49f5c..ec95eb5 100644 --- a/include/ipfs/util/time.h +++ b/include/ipfs/util/time.h @@ -1,12 +1,15 @@ #ifndef IPFS_TIME_H #define IPFS_TIME_H + #ifndef __USE_XOPEN + #define __USE_XOPEN + #endif // __USE_XOPEN - struct stime { - time_t t; - struct timespec ts; - }; + #ifndef __USE_ISOC11 + #define __USE_ISOC11 + #endif // __USE_ISOC11 - int get_gmttime(struct stime *st); - int ipfs_util_time_parse_RFC3339 (struct stime *st, char *s); - char *ipfs_util_time_format_RFC3339 (struct stime *st); + #include + + int ipfs_util_time_parse_RFC3339 (struct timespec *ts, char *s); + char *ipfs_util_time_format_RFC3339 (struct timespec *ts); #endif // IPFS_TIME_H diff --git a/namesys/pb.c b/namesys/pb.c index 4e7d633..a3bf863 100644 --- a/namesys/pb.c +++ b/namesys/pb.c @@ -1,4 +1,5 @@ #include +#include "ipfs/namesys/routing.h" #include "ipfs/namesys/pb.h" int IpnsEntry_ValidityType_value (char *s) @@ -17,3 +18,24 @@ int IpnsEntry_ValidityType_value (char *s) return -1; // not found. } + +struct ipns_entry* ipfs_namesys_pb_new_ipns_entry () +{ + return calloc(1, sizeof (struct ipns_entry)); +} + +void ipfs_namesys_ipnsentry_reset (struct ipns_entry *m) +{ + if (m) { + // ipns_entry is an struct of pointers, + // so we can access as an array of pointers. + char **a = (char **)m; + int i, l = (sizeof (struct ipns_entry) / sizeof (void*)) - 2; // avoid last 2 pointers, cache and eol. + for (i = 0 ; i < l ; i++) { + if (a[i]) { + free (a[i]); // free allocated pointers, + a[i] = NULL; // and mark as free. + } + } + } +} diff --git a/namesys/publisher.c b/namesys/publisher.c new file mode 100644 index 0000000..1710b93 --- /dev/null +++ b/namesys/publisher.c @@ -0,0 +1,125 @@ +#include +#include +#include "ipfs/errs.h" +#include "ipfs/util/time.h" +#include "ipfs/namesys/pb.h" +#include "ipfs/namesys/publisher.h" + +char* ipns_entry_data_for_sig (struct ipns_entry *entry) +{ + char *ret; + + if (!entry || !entry->value || !entry->validity) { + return NULL; + } + ret = calloc (1, strlen(entry->value) + strlen (entry->validity) + sizeof(IpnsEntry_ValidityType) + 1); + if (ret) { + strcpy(ret, entry->value); + strcat(ret, entry->validity); + if (entry->validityType) { + memcpy(ret+strlen(entry->value)+strlen(entry->validity), entry->validityType, sizeof(IpnsEntry_ValidityType)); + } else { + memcpy(ret+strlen(entry->value)+strlen(entry->validity), &IpnsEntry_EOL, sizeof(IpnsEntry_ValidityType)); + } + } + return ret; +} + +int ipns_selector_func (int *idx, struct ipns_entry ***recs, char *k, char **vals) +{ + int err, i, c; + + if (!idx || !recs || !k || !vals) { + return ErrInvalidParam; + } + + for (c = 0 ; vals[c] ; c++); // count array + + *recs = calloc(c+1, sizeof (void*)); // allocate return array. + if (!*recs) { + return ErrAllocFailed; + } + for (i = 0 ; i < c ; i++) { + *recs[i] = calloc(1, sizeof (struct ipns_entry)); // alloc every record + if (!*recs[i]) { + return ErrAllocFailed; + } + //err = proto.Unmarshal(vals[i], *recs[i]); // and decode. + if (err) { + ipfs_namesys_ipnsentry_reset (*recs[i]); // make sure record is empty. + } + } + return ipns_select_record(idx, *recs, vals); +} + +int ipns_select_record (int *idx, struct ipns_entry **recs, char **vals) +{ + int err, i, best_i = -1, best_seq = 0; + struct timespec rt, bestt; + + if (!idx || !recs || !vals) { + return ErrInvalidParam; + } + + for (i = 0 ; recs[i] ; i++) { + if (!(recs[i]->sequence) || *(recs[i]->sequence) < best_seq) { + continue; + } + + if (best_i == -1 || *(recs[i]->sequence) > best_seq) { + best_seq = *(recs[i]->sequence); + best_i = i; + } else if (*(recs[i]->sequence) == best_seq) { + err = ipfs_util_time_parse_RFC3339 (&rt, ipfs_namesys_pb_get_validity (recs[i])); + if (err) { + continue; + } + err = ipfs_util_time_parse_RFC3339 (&bestt, ipfs_namesys_pb_get_validity (recs[best_i])); + if (err) { + continue; + } + if (rt.tv_sec > bestt.tv_sec || (rt.tv_sec == bestt.tv_sec && rt.tv_nsec > bestt.tv_nsec)) { + best_i = i; + } else if (rt.tv_sec == bestt.tv_sec && rt.tv_nsec == bestt.tv_nsec) { + if (memcmp(vals[i], vals[best_i], strlen(vals[best_i])) > 0) { // FIXME: strlen? + best_i = i; + } + } + } + } + if (best_i == -1) { + return ErrNoRecord; + } + *idx = best_i; + return 0; +} + +// ipns_validate_ipns_record implements ValidatorFunc and verifies that the +// given 'val' is an IpnsEntry and that that entry is valid. +int ipns_validate_ipns_record (char *k, char *val) +{ + int err; + struct ipns_entry *entry = ipfs_namesys_pb_new_ipns_entry(); + struct timespec ts, now; + + if (!entry) { + return ErrAllocFailed; + } + //err = proto.Unmarshal(val, entry); + if (err) { + return err; + } + if (ipfs_namesys_pb_get_validity_type (entry) == IpnsEntry_EOL) { + err = ipfs_util_time_parse_RFC3339 (&ts, ipfs_namesys_pb_get_validity (entry)); + if (err) { + //log.Debug("failed parsing time for ipns record EOL") + return err; + } + timespec_get (&now, TIME_UTC); + if (now.tv_nsec > ts.tv_nsec || (now.tv_nsec == ts.tv_nsec && now.tv_nsec > ts.tv_nsec)) { + return ErrExpiredRecord; + } + } else { + return ErrUnrecognizedValidity; + } +} diff --git a/namesys/routing.c b/namesys/routing.c index 3842300..924878b 100644 --- a/namesys/routing.c +++ b/namesys/routing.c @@ -13,15 +13,15 @@ char* ipfs_routing_cache_get (char *key, struct ipns_entry *ientry) { int i; struct routingResolver *cache; - struct stime now; + struct timespec now; if (key && ientry) { cache = ientry->cache; if (cache) { - get_gmttime (&now); + timespec_get (&now); for (i = 0 ; i < cache->next ; i++) { - if (((now.t < cache->data[i]->eol.t || - (now.t == cache->data[i]->eol.t && now.ts.tv_nsec < cache->data[i]->eol.ts.tv_nsec))) && + if (((now.tv_sec < cache->data[i]->eol.tv_sec || + (now.tv_sec == cache->data[i]->eol.tv_sec && now.tv_nsec < cache->data[i]->eol.tv_nsec))) && strcmp(cache->data[i]->key, key) == 0) { return cache->data[i]->value; } @@ -43,8 +43,8 @@ void ipfs_routing_cache_set (char *key, char *value, struct ipns_entry *ientry) if (n) { n->key = key; n->value = value; - get_gmttime (&n->eol); // now - n->eol.t += DefaultResolverCacheTTL; // sum TTL seconds to time seconds. + timespec_get (&n->eol); // now + n->eol.tv_sec += DefaultResolverCacheTTL; // sum TTL seconds to time seconds. cache->data[cache->next++] = n; } } @@ -152,7 +152,7 @@ int ipfs_namesys_routing_resolve_once (char **path, char *name, int depth, char } // check sig with pk - err = libp2p_crypto_verify (ipfs_ipns_entry_data_for_sig(pb->IpnsEntry), ipfs_ipns_entry_get_signature(pb->IpnsEntry), &ok); + err = libp2p_crypto_verify (ipns_entry_data_for_sig(pb->IpnsEntry), pb->IpnsEntry->signature, &ok); if (err || !ok) { char buf[500]; snprintf(buf, sizeof(buf), Err[ErrInvalidSignatureFmt], pubkey); @@ -198,12 +198,12 @@ int ipfs_namesys_routing_resolve_once (char **path, char *name, int depth, char return 0; } -int ipfs_namesys_routing_check_EOL (struct stime *st, struct namesys_pb *pb) +int ipfs_namesys_routing_check_EOL (struct timespec *ts, struct namesys_pb *pb) { int err; - if (ipfs_namesys_pb_get_validity_type (pb->IpnsEntry) == IpnsEntry_EOL) { - err = ipfs_util_time_parse_RFC3339 (st, ipfs_namesys_pb_get_validity (pb->IpnsEntry)); + if (*(pb->IpnsEntry->validityType) == IpnsEntry_EOL) { + err = ipfs_util_time_parse_RFC3339 (ts, pb->IpnsEntry->validity); if (!err) { return 1; } diff --git a/util/time.c b/util/time.c index b438eb8..3eee8c3 100644 --- a/util/time.c +++ b/util/time.c @@ -1,47 +1,26 @@ #include #include #include - -#ifndef __USE_XOPEN - #define __USE_XOPEN -#endif // __USE_XOPEN - -#ifndef __USE_ISOC11 - #define __USE_ISOC11 -#endif // __USE_ISOC11 - -#include #include "ipfs/util/time.h" -int get_gmttime(struct stime *st) { - if (!st) { - return 1; - } - if (!timespec_get(&st->ts, TIME_UTC) || - !time(&st->t)) { - return 2; - } - return 0; -} - -int ipfs_util_time_parse_RFC3339 (struct stime *st, char *s) +int ipfs_util_time_parse_RFC3339 (struct timespec *ts, char *s) { char *r; struct tm tm; - if (!st || !s || strlen(s) != 35) { + if (!ts || !s || strlen(s) != 35) { return 1; } r = strptime (s, "%Y-%m-%dT%H:%M:%S", &tm); if (!r || *r != '.') { return 2; } - st->t = mktime(&tm); - st->ts.tv_nsec = atoll(++r); + ts->tv_sec = mktime(&tm); + ts->tv_nsec = atoll(++r); return 0; } -char *ipfs_util_time_format_RFC3339 (struct stime *st) +char *ipfs_util_time_format_RFC3339 (struct timespec *ts) { char buf[31], *ret; @@ -50,8 +29,8 @@ char *ipfs_util_time_format_RFC3339 (struct stime *st) return NULL; } - if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S.%%09dZ00:00", gmtime(&st->t)) != sizeof(buf)-1 || - snprintf(ret, 36, buf, st->ts.tv_nsec) != 35) { + if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S.%%09dZ00:00", gmtime(&(ts->tv_sec))) != sizeof(buf)-1 || + snprintf(ret, 36, buf, ts->tv_nsec) != 35) { free (ret); return NULL; }