]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9775: Significant work towards supporting BEP44, "get" is nearly working committin...
authorShane Bryldt <astaelan@gmail.com>
Fri, 9 Dec 2016 19:12:23 +0000 (19:12 +0000)
committerMike Jerris <mike@jerris.com>
Wed, 25 Jan 2017 20:59:34 +0000 (14:59 -0600)
libs/libks/Makefile.am
libs/libks/src/dht/ks_dht-int.h
libs/libks/src/dht/ks_dht.c
libs/libks/src/dht/ks_dht.h
libs/libks/src/dht/ks_dht_storageitem.c [new file with mode: 0644]

index 2ce72b33d934f0048204dfce20d3de8b64479ac3..94b01d454fb87212bc821e42e113d706dbe3acbc 100644 (file)
@@ -14,7 +14,7 @@ libks_la_SOURCES += src/ks_ssl.c src/kws.c src/ks_rng.c
 libks_la_SOURCES += src/utp/utp_api.cpp src/utp/utp_callbacks.cpp src/utp/utp_hash.cpp src/utp/utp_internal.cpp
 libks_la_SOURCES += src/utp/utp_packedsockaddr.cpp src/utp/utp_utils.cpp src/ks_bencode.c
 libks_la_SOURCES += src/dht/ks_dht.c src/dht/ks_dht_endpoint.c src/dht/ks_dht_message.c src/dht/ks_dht_transaction.c
-libks_la_SOURCES += src/dht/ks_dht_bucket.c 
+libks_la_SOURCES += src/dht/ks_dht_storageitem.c src/dht/ks_dht_bucket.c
 libks_la_SOURCES += crypt/aeskey.c crypt/aestab.c crypt/sha2.c crypt/twofish.c crypt/aes_modes.c crypt/aescrypt.c crypt/twofish_cfb.c 
 #aes.h aescpp.h brg_endian.h aesopt.h aestab.h brg_types.h sha2.h twofish.h
 
index 2d7f06eed45900db54774c5a9e441a941d662d41..d9ec6a8fb2b5bea377a4a54ab5560f11d5d9c36c 100644 (file)
@@ -35,6 +35,7 @@ KS_DECLARE(ks_status_t) ks_dht_send_error(ks_dht_t *dht,
                                                                                  const char *errorstr);
 KS_DECLARE(ks_status_t) ks_dht_send_ping(ks_dht_t *dht, ks_dht_endpoint_t *ep, ks_sockaddr_t *raddr);
 KS_DECLARE(ks_status_t) ks_dht_send_findnode(ks_dht_t *dht, ks_dht_endpoint_t *ep, ks_sockaddr_t *raddr, ks_dht_nodeid_t *targetid);
+KS_DECLARE(ks_status_t) ks_dht_send_get(ks_dht_t *dht, ks_dht_endpoint_t *ep, ks_sockaddr_t *raddr, ks_dht_nodeid_t *targetid);
 
 KS_DECLARE(ks_status_t) ks_dht_process(ks_dht_t *dht, ks_dht_endpoint_t *ep, ks_sockaddr_t *raddr);
 
@@ -44,9 +45,12 @@ KS_DECLARE(ks_status_t) ks_dht_process_error(ks_dht_t *dht, ks_dht_message_t *me
 
 KS_DECLARE(ks_status_t) ks_dht_process_query_ping(ks_dht_t *dht, ks_dht_message_t *message);
 KS_DECLARE(ks_status_t) ks_dht_process_query_findnode(ks_dht_t *dht, ks_dht_message_t *message);
+KS_DECLARE(ks_status_t) ks_dht_process_query_get(ks_dht_t *dht, ks_dht_message_t *message);
+KS_DECLARE(ks_status_t) ks_dht_process_query_put(ks_dht_t *dht, ks_dht_message_t *message);
 
 KS_DECLARE(ks_status_t) ks_dht_process_response_ping(ks_dht_t *dht, ks_dht_message_t *message);
 KS_DECLARE(ks_status_t) ks_dht_process_response_findnode(ks_dht_t *dht, ks_dht_message_t *message);
+KS_DECLARE(ks_status_t) ks_dht_process_response_get(ks_dht_t *dht, ks_dht_message_t *message);
 
 /**
  *
@@ -61,6 +65,24 @@ KS_DECLARE(ks_status_t) ks_dht_endpoint_init(ks_dht_endpoint_t *endpoint,
                                                                                         ks_socket_t sock);
 KS_DECLARE(ks_status_t) ks_dht_endpoint_deinit(ks_dht_endpoint_t *endpoint);
 
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_alloc(ks_dht_storageitem_t **item, ks_pool_t *pool);
+KS_DECLARE(ks_status_t) ks_dht_storageitem_prealloc(ks_dht_storageitem_t *item, ks_pool_t *pool);
+KS_DECLARE(ks_status_t) ks_dht_storageitem_free(ks_dht_storageitem_t *item);
+
+KS_DECLARE(ks_status_t) ks_dht_storageitem_init(ks_dht_storageitem_t *item, struct bencode *v);
+KS_DECLARE(ks_status_t) ks_dht_storageitem_deinit(ks_dht_storageitem_t *item);
+
+KS_DECLARE(ks_status_t) ks_dht_storageitem_create(ks_dht_storageitem_t *item, ks_bool_t mutable);
+KS_DECLARE(ks_status_t) ks_dht_storageitem_immutable(ks_dht_storageitem_t *item);
+KS_DECLARE(ks_status_t) ks_dht_storageitem_mutable(ks_dht_storageitem_t *item,
+                                                                                                  ks_dht_storageitem_key_t *k,
+                                                                                                  uint8_t *salt,
+                                                                                                  ks_size_t salt_length,
+                                                                                                  int64_t sequence,
+                                                                                                  ks_dht_storageitem_signature_t *signature);
 /**
  *
  */
index eb9db01561a414f6d44abbcdaf5e795aa146b7da..c558d826515ab524d9540f504f6d67043d0099f8 100644 (file)
@@ -36,6 +36,10 @@ KS_DECLARE(ks_status_t) ks_dht_alloc(ks_dht_t **dht, ks_pool_t *pool)
        d->transactions_hash = NULL;
        d->rt_ipv4 = NULL;
        d->rt_ipv6 = NULL;
+       d->token_secret_current = 0;
+       d->token_secret_previous = 0;
+       d->token_secret_expiration = 0;
+       d->storage_hash = NULL;
 
        return KS_STATUS_SUCCESS;
 }
@@ -69,6 +73,10 @@ KS_DECLARE(ks_status_t) ks_dht_prealloc(ks_dht_t *dht, ks_pool_t *pool)
        dht->transactions_hash = NULL;
        dht->rt_ipv4 = NULL;
        dht->rt_ipv6 = NULL;
+       dht->token_secret_current = 0;
+       dht->token_secret_previous = 0;
+       dht->token_secret_expiration = 0;
+       dht->storage_hash = NULL;
        
        return KS_STATUS_SUCCESS;
 }
@@ -110,6 +118,8 @@ KS_DECLARE(ks_status_t) ks_dht_init(ks_dht_t *dht)
        ks_hash_create(&dht->registry_query, KS_HASH_MODE_DEFAULT, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, dht->pool);
        ks_dht_register_query(dht, "ping", ks_dht_process_query_ping);
        ks_dht_register_query(dht, "find_node", ks_dht_process_query_findnode);
+       ks_dht_register_query(dht, "get", ks_dht_process_query_get);
+       ks_dht_register_query(dht, "put", ks_dht_process_query_put);
 
        ks_hash_create(&dht->registry_error, KS_HASH_MODE_DEFAULT, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, dht->pool);
        // @todo register 301 error for internal get/put CAS hash mismatch retry handler
@@ -131,6 +141,12 @@ KS_DECLARE(ks_status_t) ks_dht_init(ks_dht_t *dht)
 
        dht->rt_ipv4 = NULL;
        dht->rt_ipv6 = NULL;
+
+       dht->token_secret_current = dht->token_secret_previous = rand();
+       dht->token_secret_expiration = ks_time_now_sec() + KS_DHT_TOKENSECRET_EXPIRATION;
+
+       ks_hash_create(&dht->storage_hash, KS_HASH_MODE_ARBITRARY, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, dht->pool);
+       ks_hash_set_keysize(dht->storage_hash, KS_DHT_NODEID_SIZE);
        
        return KS_STATUS_SUCCESS;
 }
@@ -142,6 +158,14 @@ KS_DECLARE(ks_status_t) ks_dht_deinit(ks_dht_t *dht)
 {
        ks_assert(dht);
 
+       // @todo free storage_hash entries
+       if (dht->storage_hash) {
+               ks_hash_destroy(&dht->storage_hash);
+               dht->storage_hash = NULL;
+       }
+       dht->token_secret_current = 0;
+       dht->token_secret_previous = 0;
+       dht->token_secret_expiration = 0;
        if (dht->rt_ipv4) {
                ks_dhtrt_deinitroute(dht->rt_ipv4);
                dht->rt_ipv4 = NULL;
@@ -489,6 +513,117 @@ KS_DECLARE(ks_status_t) ks_dht_utility_compact_node(ks_dht_nodeid_t *nodeid,
        return ks_dht_utility_compact_address(address, buffer, buffer_length, buffer_size);
 }
 
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_utility_extract_nodeid(struct bencode *args, const char *key, ks_dht_nodeid_t **nodeid)
+{
+       struct bencode *id;
+       const char *idv;
+       ks_size_t idv_len;
+
+       ks_assert(args);
+       ks_assert(key);
+       ks_assert(nodeid);
+
+       *nodeid = NULL;
+       
+    id = ben_dict_get_by_str(args, key);
+    if (!id) {
+               ks_log(KS_LOG_DEBUG, "Message args missing key '%s'\n", key);
+               return KS_STATUS_FAIL;
+       }
+       
+    idv = ben_str_val(id);
+       idv_len = ben_str_len(id);
+    if (idv_len != KS_DHT_NODEID_SIZE) {
+               ks_log(KS_LOG_DEBUG, "Message args '%s' value has an unexpected size of %d\n", key, idv_len);
+               return KS_STATUS_FAIL;
+       }
+
+       *nodeid = (ks_dht_nodeid_t *)idv;
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_utility_extract_token(struct bencode *args, const char *key, ks_dht_token_t **token)
+{
+       struct bencode *tok;
+       const char *tokv;
+       ks_size_t tokv_len;
+
+       ks_assert(args);
+       ks_assert(key);
+       ks_assert(token);
+
+       *token = NULL;
+       
+    tok = ben_dict_get_by_str(args, key);
+    if (!tok) {
+               ks_log(KS_LOG_DEBUG, "Message args missing key '%s'\n", key);
+               return KS_STATUS_FAIL;
+       }
+
+    tokv = ben_str_val(tok);
+       tokv_len = ben_str_len(tok);
+    if (tokv_len != KS_DHT_TOKEN_SIZE) {
+               ks_log(KS_LOG_DEBUG, "Message args '%s' value has an unexpected size of %d\n", key, tokv_len);
+               return KS_STATUS_FAIL;
+       }
+
+       *token = (ks_dht_token_t *)tokv;
+
+       return KS_STATUS_SUCCESS;
+}
+
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_token_generate(uint32_t secret, ks_sockaddr_t *raddr, ks_dht_nodeid_t *target, ks_dht_token_t *token)
+{
+       SHA_CTX sha;
+       uint16_t port = 0;
+
+       ks_assert(raddr);
+       ks_assert(raddr->family == AF_INET || raddr->family == AF_INET6);
+       ks_assert(target);
+       ks_assert(token);
+
+       secret = htonl(secret);
+       port = htons(raddr->port);
+       
+       SHA1_Init(&sha);
+       SHA1_Update(&sha, &secret, sizeof(uint32_t));
+       SHA1_Update(&sha, raddr->host, strlen(raddr->host));
+       SHA1_Update(&sha, &port, sizeof(uint16_t));
+       SHA1_Update(&sha, target->id, KS_DHT_NODEID_SIZE);
+       SHA1_Final(token->token, &sha);
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_bool_t) ks_dht_token_verify(ks_dht_t *dht, ks_sockaddr_t *raddr, ks_dht_nodeid_t *target, ks_dht_token_t *token)
+{
+       ks_dht_token_t tok;
+
+       ks_dht_token_generate(dht->token_secret_current, raddr, target, &tok);
+
+       if (!memcmp(tok.token, token->token, KS_DHT_TOKEN_SIZE)) {
+               return KS_TRUE;
+       }
+
+       ks_dht_token_generate(dht->token_secret_previous, raddr, target, &tok);
+
+       return memcmp(tok.token, token->token, KS_DHT_TOKEN_SIZE) == 0;
+}
+
 /**
  *
  */
@@ -532,6 +667,12 @@ KS_DECLARE(void) ks_dht_idle_expirations(ks_dht_t *dht)
                }
        }
        ks_hash_write_unlock(dht->transactions_hash);
+
+       if (dht->token_secret_expiration && dht->token_secret_expiration <= now) {
+               dht->token_secret_expiration = ks_time_now_sec() + KS_DHT_TOKENSECRET_EXPIRATION;
+               dht->token_secret_previous = dht->token_secret_current;
+               dht->token_secret_current = rand();
+       }
 }
 
 /**
@@ -812,6 +953,32 @@ KS_DECLARE(ks_status_t) ks_dht_send_findnode(ks_dht_t *dht, ks_dht_endpoint_t *e
        return KS_STATUS_SUCCESS;
 }
 
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_send_get(ks_dht_t *dht, ks_dht_endpoint_t *ep, ks_sockaddr_t *raddr, ks_dht_nodeid_t *targetid)
+{
+       ks_dht_message_t *message = NULL;
+       struct bencode *a = NULL;
+       
+       ks_assert(dht);
+       ks_assert(raddr);
+       ks_assert(targetid);
+
+       if (ks_dht_setup_query(dht, ep, raddr, "get", ks_dht_process_response_get, &message, &a) != KS_STATUS_SUCCESS) {
+               return KS_STATUS_FAIL;
+       }
+
+       ben_dict_set(a, ben_blob("id", 2), ben_blob(message->endpoint->nodeid.id, KS_DHT_NODEID_SIZE));
+       // @todo check for target item locally, set seq to item seq to prevent getting back what we already have if a newer seq is not available
+       ben_dict_set(a, ben_blob("target", 6), ben_blob(targetid->id, KS_DHT_NODEID_SIZE));
+
+       ks_log(KS_LOG_DEBUG, "Sending message query get\n");
+       ks_q_push(dht->send_q, (void *)message);
+
+       return KS_STATUS_SUCCESS;
+}
+
 /**
  *
  */
@@ -1035,9 +1202,7 @@ KS_DECLARE(ks_status_t) ks_dht_process_error(ks_dht_t *dht, ks_dht_message_t *me
  */
 KS_DECLARE(ks_status_t) ks_dht_process_query_ping(ks_dht_t *dht, ks_dht_message_t *message)
 {
-       struct bencode *id;
-       //const char *idv;
-       ks_size_t idv_len;
+       ks_dht_nodeid_t *id;
        ks_dht_message_t *response = NULL;
        struct bencode *r = NULL;
 
@@ -1045,16 +1210,7 @@ KS_DECLARE(ks_status_t) ks_dht_process_query_ping(ks_dht_t *dht, ks_dht_message_
        ks_assert(message);
        ks_assert(message->args);
 
-    id = ben_dict_get_by_str(message->args, "id");
-    if (!id) {
-               ks_log(KS_LOG_DEBUG, "Message args missing required key 'id'\n");
-               return KS_STATUS_FAIL;
-       }
-       
-    //idv = ben_str_val(id);
-       idv_len = ben_str_len(id);
-    if (idv_len != KS_DHT_NODEID_SIZE) {
-               ks_log(KS_LOG_DEBUG, "Message args 'id' value has an unexpected size of %d\n", idv_len);
+       if (ks_dht_utility_extract_nodeid(message->args, "id", &id) != KS_STATUS_SUCCESS) {
                return KS_STATUS_FAIL;
        }
 
@@ -1085,13 +1241,9 @@ KS_DECLARE(ks_status_t) ks_dht_process_query_ping(ks_dht_t *dht, ks_dht_message_
  */
 KS_DECLARE(ks_status_t) ks_dht_process_query_findnode(ks_dht_t *dht, ks_dht_message_t *message)
 {
-       struct bencode *id;
-       struct bencode *target;
+       ks_dht_nodeid_t *id;
+       ks_dht_nodeid_t *target;
        struct bencode *want;
-       const char *idv;
-       //const char *targetv;
-       ks_size_t idv_len;
-       ks_size_t targetv_len;
        ks_bool_t want4 = KS_FALSE;
        ks_bool_t want6 = KS_FALSE;
        ks_dht_message_t *response = NULL;
@@ -1105,35 +1257,14 @@ KS_DECLARE(ks_status_t) ks_dht_process_query_findnode(ks_dht_t *dht, ks_dht_mess
        ks_assert(message);
        ks_assert(message->args);
 
-       
-    id = ben_dict_get_by_str(message->args, "id");
-    if (!id) {
-               ks_log(KS_LOG_DEBUG, "Message args missing required key 'id'\n");
-               return KS_STATUS_FAIL;
-       }
-       
-    idv = ben_str_val(id);
-       idv_len = ben_str_len(id);
-    if (idv_len != KS_DHT_NODEID_SIZE) {
-               ks_log(KS_LOG_DEBUG, "Message args 'id' value has an unexpected size of %d\n", idv_len);
-               return KS_STATUS_FAIL;
-       }
-
-       
-       target = ben_dict_get_by_str(message->args, "target");
-    if (!target) {
-               ks_log(KS_LOG_DEBUG, "Message args missing required key 'target'\n");
+       if (ks_dht_utility_extract_nodeid(message->args, "id", &id) != KS_STATUS_SUCCESS) {
                return KS_STATUS_FAIL;
        }
 
-    //targetv = ben_str_val(target);
-    targetv_len = ben_str_len(target);
-    if (targetv_len != KS_DHT_NODEID_SIZE) {
-               ks_log(KS_LOG_DEBUG, "Message args 'target' value has an unexpected size of %d\n", targetv_len);
+       if (ks_dht_utility_extract_nodeid(message->args, "target", &target) != KS_STATUS_SUCCESS) {
                return KS_STATUS_FAIL;
        }
 
-       
        want = ben_dict_get_by_str(message->args, "want");
        if (want) {
                size_t want_len = ben_list_len(want);
@@ -1168,7 +1299,7 @@ KS_DECLARE(ks_status_t) ks_dht_process_query_findnode(ks_dht_t *dht, ks_dht_mess
        }
 
        // @todo remove this, testing only
-       if (ks_dht_utility_compact_node((ks_dht_nodeid_t *)idv,
+       if (ks_dht_utility_compact_node(id,
                                                                        &message->raddr,
                                                                        message->raddr.family == AF_INET ? buffer4 : buffer6,
                                                                        message->raddr.family == AF_INET ? &buffer4_length : &buffer6_length,
@@ -1200,6 +1331,121 @@ KS_DECLARE(ks_status_t) ks_dht_process_query_findnode(ks_dht_t *dht, ks_dht_mess
        return KS_STATUS_SUCCESS;
 }
 
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_process_query_get(ks_dht_t *dht, ks_dht_message_t *message)
+{
+       ks_dht_nodeid_t *id;
+       ks_dht_nodeid_t *target;
+       struct bencode *seq;
+       int64_t sequence = -1;
+       ks_bool_t sequence_snuffed = KS_FALSE;
+       ks_dht_token_t token;
+       ks_dht_storageitem_t *item = NULL;
+       ks_dht_message_t *response = NULL;
+       struct bencode *r = NULL;
+
+       ks_assert(dht);
+       ks_assert(message);
+       ks_assert(message->args);
+
+       if (ks_dht_utility_extract_nodeid(message->args, "id", &id) != KS_STATUS_SUCCESS) {
+               return KS_STATUS_FAIL;
+       }
+
+       if (ks_dht_utility_extract_nodeid(message->args, "target", &target) != KS_STATUS_SUCCESS) {
+               return KS_STATUS_FAIL;
+       }
+       
+       seq = ben_dict_get_by_str(message->args, "seq");
+       if (seq) {
+               sequence = ben_int_val(seq);
+       }
+
+       // @todo add/touch bucket entry for remote node
+
+       ks_log(KS_LOG_DEBUG, "Message query get is valid\n");
+
+       ks_dht_token_generate(dht->token_secret_current, &message->raddr, target, &token);
+       
+       item = ks_hash_search(dht->storage_hash, (void *)target, KS_READLOCKED);
+       ks_hash_read_unlock(dht->storage_hash);
+
+       sequence_snuffed = item && sequence >= 0 && item->seq <= sequence;
+       // @todo if sequence is provided then requester has the data so if the local sequence is lower, maybe create job to update local data from the requester?
+
+       // @todo find closest ipv4 and ipv6 nodes to target
+
+       // @todo compact ipv4 and ipv6 nodes into separate buffers
+       
+       if (ks_dht_setup_response(dht,
+                                                         message->endpoint,
+                                                         &message->raddr,
+                                                         message->transactionid,
+                                                         message->transactionid_length,
+                                                         &response,
+                                                         &r) != KS_STATUS_SUCCESS) {
+               return KS_STATUS_FAIL;
+       }
+
+       ben_dict_set(r, ben_blob("id", 2), ben_blob(response->endpoint->nodeid.id, KS_DHT_NODEID_SIZE));
+       ben_dict_set(r, ben_blob("token", 5), ben_blob(token.token, KS_DHT_TOKEN_SIZE));
+       if (item) {
+               if (item->mutable) {
+                       if (!sequence_snuffed) {
+                               ben_dict_set(r, ben_blob("k", 1), ben_blob(item->pk.key, KS_DHT_STORAGEITEM_KEY_SIZE));
+                               ben_dict_set(r, ben_blob("sig", 3), ben_blob(item->sig.sig, KS_DHT_STORAGEITEM_SIGNATURE_SIZE));
+                       }
+                       ben_dict_set(r, ben_blob("seq", 3), ben_int(item->seq));
+               }
+               if (!sequence_snuffed) {
+                       ben_dict_set(r, ben_blob("v", 1), ben_clone(item->v));
+               }
+       }
+       // @todo nodes, nodes6
+
+       ks_log(KS_LOG_DEBUG, "Sending message response get\n");
+       ks_q_push(dht->send_q, (void *)response);
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_process_query_put(ks_dht_t *dht, ks_dht_message_t *message)
+{
+       ks_dht_message_t *response = NULL;
+       struct bencode *r = NULL;
+
+       ks_assert(dht);
+       ks_assert(message);
+       ks_assert(message->args);
+
+       // @todo add/touch bucket entry for remote node
+
+       ks_log(KS_LOG_DEBUG, "Message query put is valid\n");
+
+       if (ks_dht_setup_response(dht,
+                                                         message->endpoint,
+                                                         &message->raddr,
+                                                         message->transactionid,
+                                                         message->transactionid_length,
+                                                         &response,
+                                                         &r) != KS_STATUS_SUCCESS) {
+               return KS_STATUS_FAIL;
+       }
+
+       //ben_dict_set(r, ben_blob("id", 2), ben_blob(response->endpoint->nodeid.id, KS_DHT_NODEID_SIZE));
+
+       ks_log(KS_LOG_DEBUG, "Sending message response put\n");
+       ks_q_push(dht->send_q, (void *)response);
+
+       return KS_STATUS_SUCCESS;
+}
+
+
 /**
  *
  */
@@ -1230,6 +1476,36 @@ KS_DECLARE(ks_status_t) ks_dht_process_response_findnode(ks_dht_t *dht, ks_dht_m
        return KS_STATUS_SUCCESS;
 }
 
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_process_response_get(ks_dht_t *dht, ks_dht_message_t *message)
+{
+       ks_dht_nodeid_t *id;
+       ks_dht_token_t *token;
+       
+       ks_assert(dht);
+       ks_assert(message);
+
+       // @todo use ks_dht_storageitem_mutable or ks_dht_storageitem_immutable if v is provided
+       if (ks_dht_utility_extract_nodeid(message->args, "id", &id) != KS_STATUS_SUCCESS) {
+               return KS_STATUS_FAIL;
+       }
+       
+       if (ks_dht_utility_extract_token(message->args, "token", &token) != KS_STATUS_SUCCESS) {
+               return KS_STATUS_FAIL;
+       }
+
+       // @todo add extract function for mutable ks_dht_storageitem_key_t
+       // @todo add extract function for mutable ks_dht_storageitem_signature_t
+       
+       // @todo add/touch bucket entry for remote node and other nodes returned
+
+       ks_log(KS_LOG_DEBUG, "Message response get is reached\n");
+
+       return KS_STATUS_SUCCESS;
+}
+
 /* For Emacs:
  * Local Variables:
  * mode:c
index c1251bac9382b7b06c08fe7f4c23d2a25d7afd2f..48427a4cb33e9ce0f6a4558f262f3171a7b69f70 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "ks.h"
 #include "ks_bencode.h"
+#include "sodium.h"
 
 KS_BEGIN_EXTERN_C
 
@@ -19,14 +20,26 @@ KS_BEGIN_EXTERN_C
 
 #define KS_DHT_TRANSACTION_EXPIRATION_DELAY 30
 
+#define KS_DHT_STORAGEITEM_KEY_SIZE crypto_sign_PUBLICKEYBYTES
+#define KS_DHT_STORAGEITEM_SALT_MAX_SIZE 64
+#define KS_DHT_STORAGEITEM_SIGNATURE_SIZE crypto_sign_BYTES
+
+#define KS_DHT_TOKEN_SIZE SHA_DIGEST_LENGTH
+#define KS_DHT_TOKENSECRET_EXPIRATION 300
+
 typedef struct ks_dht_s ks_dht_t;
 typedef struct ks_dht_nodeid_s ks_dht_nodeid_t;
+typedef struct ks_dht_token_s ks_dht_token_t;
+typedef struct ks_dht_storageitem_key_s ks_dht_storageitem_key_t;
+typedef struct ks_dht_storageitem_signature_s ks_dht_storageitem_signature_t;
 typedef struct ks_dht_message_s ks_dht_message_t;
 typedef struct ks_dht_endpoint_s ks_dht_endpoint_t;
 typedef struct ks_dht_transaction_s ks_dht_transaction_t;
 typedef struct ks_dht_node_s ks_dht_node_t;
 typedef struct ks_dhtrt_routetable_s ks_dhtrt_routetable_t;
 typedef struct ks_dhtrt_querynodes_s ks_dhtrt_querynodes_t;
+typedef struct ks_dht_storageitem_s ks_dht_storageitem_t;
+
 
 typedef ks_status_t (*ks_dht_message_callback_t)(ks_dht_t *dht, ks_dht_message_t *message);
 
@@ -60,6 +73,18 @@ struct ks_dhtrt_querynodes_s {
     ks_dht_node_t* nodes[ KS_DHT_MESSAGE_QUERY_MAX_SIZE]; /* out: array of peers (ks_dht_node_t* nodes[incount]) */
 };
 
+struct ks_dht_token_s {
+       uint8_t token[KS_DHT_TOKEN_SIZE];
+};
+
+struct ks_dht_storageitem_key_s {
+       uint8_t key[KS_DHT_STORAGEITEM_KEY_SIZE];
+};
+
+struct ks_dht_storageitem_signature_s {
+       uint8_t sig[KS_DHT_STORAGEITEM_SIGNATURE_SIZE];
+};
+
 struct ks_dht_message_s {
        ks_pool_t *pool;
        ks_dht_endpoint_t *endpoint;
@@ -87,6 +112,20 @@ struct ks_dht_transaction_s {
        ks_bool_t finished;
 };
 
+struct ks_dht_storageitem_s {
+       ks_pool_t *pool;
+       ks_dht_nodeid_t id;
+
+       struct bencode *v;
+       
+       ks_bool_t mutable;
+       ks_dht_storageitem_key_t pk;
+       ks_dht_storageitem_key_t sk;
+       uint8_t salt[KS_DHT_STORAGEITEM_SALT_MAX_SIZE];
+       ks_size_t salt_length;
+       int64_t seq;
+       ks_dht_storageitem_signature_t sig;
+};
 
 struct ks_dht_s {
        ks_pool_t *pool;
@@ -117,6 +156,11 @@ struct ks_dht_s {
 
        ks_dhtrt_routetable_t *rt_ipv4;
        ks_dhtrt_routetable_t *rt_ipv6;
+
+       volatile uint32_t token_secret_current;
+       volatile uint32_t token_secret_previous;
+       ks_time_t token_secret_expiration;
+       ks_hash_t *storage_hash;
 };
 
 /**
diff --git a/libs/libks/src/dht/ks_dht_storageitem.c b/libs/libks/src/dht/ks_dht_storageitem.c
new file mode 100644 (file)
index 0000000..8672b77
--- /dev/null
@@ -0,0 +1,208 @@
+#include "ks_dht.h"
+#include "ks_dht-int.h"
+#include "sodium.h"
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_alloc(ks_dht_storageitem_t **item, ks_pool_t *pool)
+{
+       ks_dht_storageitem_t *si;
+
+       ks_assert(item);
+       ks_assert(pool);
+       
+       *item = si = ks_pool_alloc(pool, sizeof(ks_dht_storageitem_t));
+       si->pool = pool;
+       si->v = NULL;
+       si->mutable = KS_FALSE;
+       si->salt_length = 0;
+       si->seq = 0;
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_prealloc(ks_dht_storageitem_t *item, ks_pool_t *pool)
+{
+       ks_assert(item);
+       ks_assert(pool);
+
+       item->pool = pool;
+       item->v = NULL;
+       item->mutable = KS_FALSE;
+       item->salt_length = 0;
+       item->seq = 0;
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_free(ks_dht_storageitem_t *item)
+{
+       ks_assert(item);
+
+       ks_dht_storageitem_deinit(item);
+       ks_pool_free(item->pool, item);
+
+       return KS_STATUS_SUCCESS;
+}
+
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_init(ks_dht_storageitem_t *item, struct bencode *v)
+{
+       ks_assert(item);
+       ks_assert(item->pool);
+       ks_assert(v);
+       ks_assert(SHA_DIGEST_LENGTH == KS_DHT_NODEID_SIZE);
+
+       item->v = ben_clone(v);
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_deinit(ks_dht_storageitem_t *item)
+{
+       ks_assert(item);
+
+       if (item->v) {
+               ben_free(item->v);
+               item->v = NULL;
+       }
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_create(ks_dht_storageitem_t *item, ks_bool_t mutable)
+{
+       SHA_CTX sha;
+
+       ks_assert(item);
+       ks_assert(item->pool);
+       ks_assert(item->v);
+       
+       item->mutable = mutable;
+
+       if (!mutable) {
+               size_t enc_len = 0;
+               uint8_t *enc = ben_encode(&enc_len, item->v);
+               SHA1_Init(&sha);
+               SHA1_Update(&sha, enc, enc_len);
+               SHA1_Final(item->id.id, &sha);
+               free(enc);
+       } else {
+               size_t enc_len = 0;
+               uint8_t *enc = NULL;
+               struct bencode *sig = ben_dict();
+               
+               crypto_sign_keypair(item->pk.key, item->sk.key);
+               randombytes_buf(item->salt, KS_DHT_STORAGEITEM_SALT_MAX_SIZE);
+               item->salt_length = KS_DHT_STORAGEITEM_SALT_MAX_SIZE;
+               item->seq = 1;
+
+               ben_dict_set(sig, ben_blob("salt", 4), ben_blob(item->salt, item->salt_length));
+               ben_dict_set(sig, ben_blob("seq", 3), ben_int(item->seq));
+               ben_dict_set(sig, ben_blob("v", 1), ben_clone(item->v));
+               enc = ben_encode(&enc_len, sig);
+               ben_free(sig);
+
+               SHA1_Init(&sha);
+               SHA1_Update(&sha, enc, enc_len);
+               SHA1_Final(item->sig.sig, &sha);
+
+               free(enc);
+
+               SHA1_Init(&sha);
+               SHA1_Update(&sha, item->pk.key, KS_DHT_STORAGEITEM_KEY_SIZE);
+               SHA1_Update(&sha, item->salt, item->salt_length);
+               SHA1_Final(item->id.id, &sha);
+       }
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_immutable(ks_dht_storageitem_t *item)
+{
+       SHA_CTX sha;
+       size_t enc_len = 0;
+       uint8_t *enc = NULL;
+       
+       ks_assert(item);
+       ks_assert(item->v);
+
+       item->mutable = KS_FALSE;
+       
+       enc = ben_encode(&enc_len, item->v);
+       SHA1_Init(&sha);
+       SHA1_Update(&sha, enc, enc_len);
+       SHA1_Final(item->id.id, &sha);
+       free(enc);
+
+       return KS_STATUS_SUCCESS;
+}
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_mutable(ks_dht_storageitem_t *item,
+                                                                                                  ks_dht_storageitem_key_t *k,
+                                                                                                  uint8_t *salt,
+                                                                                                  ks_size_t salt_length,
+                                                                                                  int64_t sequence,
+                                                                                                  ks_dht_storageitem_signature_t *signature)
+{
+       SHA_CTX sha;
+       
+       ks_assert(item);
+       ks_assert(item->v);
+       ks_assert(k);
+       ks_assert(!(!salt && salt_length > 0));
+       ks_assert(salt_length > KS_DHT_STORAGEITEM_SIGNATURE_SIZE);
+       ks_assert(signature);
+
+       item->mutable = KS_TRUE;
+
+       memcpy(item->pk.key, k->key, KS_DHT_STORAGEITEM_KEY_SIZE);
+       if (salt && salt_length > 0) {
+               memcpy(item->salt, salt, salt_length);
+               item->salt_length = salt_length;
+       }
+       item->seq = sequence;
+       memcpy(item->sig.sig, signature->sig, KS_DHT_STORAGEITEM_SIGNATURE_SIZE);
+
+       SHA1_Init(&sha);
+       SHA1_Update(&sha, item->pk.key, KS_DHT_STORAGEITEM_KEY_SIZE);
+       if (item->salt && item->salt_length > 0) {
+               SHA1_Update(&sha, item->salt, item->salt_length);
+       }
+       SHA1_Final(item->id.id, &sha);
+
+       return KS_STATUS_SUCCESS;
+}
+                                                                                               
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */