#include <stdint.h> #include <stddef.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include "sync_keys.h" #include "mem.h" // Definitions of what a key is #define KEY_LEN_BITS (KEY_LEN<<3) // Note PREFIX_STEP_BITS >1 hasn't been tested yet #define NODE_CHILDREN (1<<PREFIX_STEP_BITS) #define INTERESTING_COUNT 16 typedef struct { uint8_t min_prefix_len:7; uint8_t stored:1; uint8_t prefix_len; sync_key_t key; }key_message_t; #define MESSAGE_FROM_KEY(K) {.key=*K, .prefix_len=KEY_LEN_BITS} #define MESSAGE_BYTES (KEY_LEN +2) // definitions for how we track the state of a set of keys #define NOT_SENT 0 #define SENT 1 #define QUEUED 2 #define DONT_SEND 3 struct node{ struct node *transmit_next; struct node *transmit_prev; key_message_t message; uint8_t send_state; uint8_t sent_count; void *context; struct node *children[NODE_CHILDREN]; }; struct sync_peer_state{ struct sync_peer_state *next; void *peer_context; unsigned send_count; unsigned recv_count; struct node *root; }; struct sync_state{ void *context; peer_has has; peer_does_not_have has_not; peer_now_has now_has; unsigned key_count; unsigned sent_root; unsigned sent_messages; unsigned sent_record_count; unsigned received_record_count; unsigned received_uninteresting; unsigned progress; struct sync_peer_state *peers; struct node *root; struct node *transmit_ptr; }; // XOR the source key into the destination key // the leading prefix_len bits of the source key will be copied, the remaining bits will be XOR'd static void sync_xor(const sync_key_t *src_key, key_message_t *dest_key) { unsigned i=0; assert(dest_key->prefix_len < KEY_LEN_BITS); // Assign whole prefix bytes for(;i<(dest_key->prefix_len>>3);i++) dest_key->key.key[i] = src_key->key[i]; if (dest_key->prefix_len&7){ // Mix assignment and xor for the byte of overlap uint8_t mask = (0xFF00>>(dest_key->prefix_len&7)) & 0xFF; dest_key->key.key[i] = (mask & src_key->key[i]) | (dest_key->key.key[i] ^ src_key->key[i]); i++; } // Xor whole remaining bytes for (;i<KEY_LEN;i++) dest_key->key.key[i] ^= src_key->key[i]; } #define sync_xor_node(N,K) sync_xor((K), &(N)->message) // return len bits from the key, starting at offset static uint8_t sync_get_bits(uint8_t offset, uint8_t len, const sync_key_t *key) { assert(len <= 8); assert(offset+len < KEY_LEN_BITS); unsigned start_byte = (offset>>3); uint16_t context = key->key[start_byte] <<8; if (start_byte+1 < KEY_LEN) context |= key->key[start_byte+1]; return (context >> (16 - (offset & 7) - len)) & ((1<<len) -1); } #define MIN_VAL(X,Y) ((X)<(Y)?(X):(Y)) #define MAX_VAL(X,Y) ((X)<(Y)?(Y):(X)) // Compare two keys, returning zero if they represent the same set of leaf nodes. static int cmp_message(const key_message_t *first, const key_message_t *second) { uint8_t common_prefix_len = MIN_VAL(first->prefix_len, second->prefix_len); uint8_t first_xor_begin = (first->prefix_len == KEY_LEN_BITS)?first->min_prefix_len:first->prefix_len; uint8_t second_xor_begin = (second->prefix_len == KEY_LEN_BITS)?second->min_prefix_len:second->prefix_len; uint8_t xor_begin_offset = MAX_VAL(first_xor_begin, second_xor_begin); int ret=0; // TODO at least we can compare before common_prefix_len and after xor_begin_offset // But we aren't comparing the bits in the middle if (common_prefix_len < xor_begin_offset){ if (common_prefix_len>=8 && memcmp(&first->key, &second->key, common_prefix_len>>3)!=0) ret = -1; else{ uint8_t xor_begin_byte = (xor_begin_offset+7)>>3; if (xor_begin_byte < KEY_LEN && memcmp(&first->key.key[xor_begin_byte], &second->key.key[xor_begin_byte], KEY_LEN - xor_begin_byte)!=0) ret = -1; } }else{ ret = memcmp(&first->key, &second->key, KEY_LEN); } return ret; } // XOR all existing children of *node, into this destination key. static void xor_children(struct node *node, key_message_t *dest) { if (node->message.prefix_len == KEY_LEN_BITS){ sync_xor(&node->message.key, dest); }else{ unsigned i; for (i=0;i<NODE_CHILDREN;i++){ if (node->children[i]) xor_children(node->children[i], dest); } } } // Add a new key into the state tree, XOR'ing the key into each parent node static struct node *add_key(struct node **root, const sync_key_t *key, void *context, uint8_t stored) { uint8_t prefix_len = 0; struct node **node = root; uint8_t min_prefix_len = prefix_len; while(*node){ uint8_t child_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, key); if ((*node)->message.prefix_len == prefix_len){ sync_xor_node((*node), key); if ((*node)->send_state == SENT) (*node)->send_state = NOT_SENT; if ((*node)->send_state == QUEUED && (*node)->sent_count>0) (*node)->send_state = DONT_SEND; // reset the send counter (*node)->sent_count=0; prefix_len += PREFIX_STEP_BITS; min_prefix_len = prefix_len; node = &(*node)->children[child_index]; if (!*node) break; continue; } // this node represents a range of prefix bits uint8_t node_child_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &(*node)->message.key); // if the prefix matches the key, keep searching. if (child_index == node_child_index){ prefix_len += PREFIX_STEP_BITS; continue; } // if there is a mismatch in the range of prefix bits, we need to create a new node to represent the new range. struct node *parent = emalloc_zero(sizeof(struct node)); parent->message.min_prefix_len = min_prefix_len; parent->message.prefix_len = prefix_len; parent->message.stored = stored; parent->children[node_child_index] = *node; min_prefix_len = prefix_len + PREFIX_STEP_BITS; assert(min_prefix_len <= (*node)->message.prefix_len); (*node)->message.min_prefix_len = min_prefix_len; // xor all the existing children of this node, we can't assume the prefix bits are right in the existing node. // we might be able to speed this up by using the prefix bits of the passed in key xor_children(parent, &parent->message); *node = parent; } // create final leaf node *node = emalloc_zero(sizeof(struct node)); (*node)->message.key = *key; (*node)->message.min_prefix_len = min_prefix_len; (*node)->message.prefix_len = KEY_LEN_BITS; (*node)->message.stored = stored; (*node)->context = context; return (*node); } // Recursively free the memory used by this tree static void free_node(struct sync_state *state, struct node *node) { if (!node) return; unsigned i; for (i=0;i<NODE_CHILDREN;i++) free_node(state, node->children[i]); if (node->transmit_next){ assert(state); assert(node->transmit_prev); if (node->transmit_next == node){ assert(node->transmit_prev==node); state->transmit_ptr = NULL; }else{ if (state->transmit_ptr == node) state->transmit_ptr = node->transmit_prev; node->transmit_next->transmit_prev = node->transmit_prev; node->transmit_prev->transmit_next = node->transmit_next; } } free(node); } static void remove_key(struct sync_state *state, struct node **root, const sync_key_t *key) { uint8_t prefix_len = 0; struct node **node = root; struct node **parent = NULL; while((*node)->message.prefix_len != KEY_LEN_BITS){ uint8_t child_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, key); // this node represents a range of prefix bits if (prefix_len < (*node)->message.prefix_len){ uint8_t node_child_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &(*node)->message.key); assert(child_index == node_child_index); prefix_len += PREFIX_STEP_BITS; continue; } sync_xor_node((*node), key); if ((*node)->send_state == SENT) (*node)->send_state = NOT_SENT; if ((*node)->send_state == QUEUED && (*node)->sent_count>0) (*node)->send_state = DONT_SEND; // reset the send counter (*node)->sent_count=0; parent = node; node = &(*node)->children[child_index]; assert(*node); prefix_len += PREFIX_STEP_BITS; } free_node(state, (*node)); *node = NULL; if (!parent) return; node = NULL; // If *parent has <= 1 child now, we need to remove *parent as well unsigned i; for (i=0;i<NODE_CHILDREN;i++){ if ((*parent)->children[i]){ if (node) return; node = &(*parent)->children[i]; } } assert(node); struct node *c = *node; // remove child ptr so it isn't free'd *node = NULL; c->message.min_prefix_len = (*parent)->message.min_prefix_len; free_node(state, *parent); *parent = c; } // find the node which matches this key, or NULL static const struct node * find_message(const struct node *node, const key_message_t *message) { if (!node) return NULL; uint8_t prefix_len = node->message.prefix_len; while(1){ if (cmp_message(&node->message, message)==0) return node; if (node->message.prefix_len == KEY_LEN_BITS) return NULL; uint8_t child_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &message->key); if (prefix_len < node->message.prefix_len){ // TODO optimise this case by comparing all possible prefix bits in one hit uint8_t node_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &node->message.key); if (node_index != child_index) return NULL; }else{ node = node->children[child_index]; if (!node) return NULL; } prefix_len+=PREFIX_STEP_BITS; } } int sync_key_exists(const struct sync_state *state, const sync_key_t *key) { key_message_t message = MESSAGE_FROM_KEY(key); return find_message(state->root, &message) ? 1:0; } int sync_has_transmit_queued(const struct sync_state *state) { return state->transmit_ptr?1:0; } // returns NULL if the node already exists static struct node * add_key_if_missing(struct node **root, const key_message_t *message, uint8_t stored) { assert(message->prefix_len == KEY_LEN_BITS); if (find_message(*root, message)!=NULL) return NULL; return add_key(root, &message->key, NULL, stored); } void sync_add_key(struct sync_state *state, const sync_key_t *key, void *context) { key_message_t message = MESSAGE_FROM_KEY(key); struct node *node = (struct node *)find_message(state->root, &message); if (node){ node->message.stored = 1; node->context = context; return; } state->key_count++; state->progress=0; add_key(&state->root, key, context, 1); struct sync_peer_state *peer_state = state->peers; while(peer_state){ if (find_message(peer_state->root, &message)){ remove_key(state, &peer_state->root, key); peer_state->recv_count--; } peer_state = peer_state->next; } } void sync_free_peer_state(struct sync_state *state, void *peer_context){ struct sync_peer_state **peer_state = &state->peers; while(*peer_state){ if ((*peer_state)->peer_context == peer_context){ struct sync_peer_state *free_peer = (*peer_state); free_node(state, free_peer->root); *peer_state = free_peer->next; free(free_peer); return; } } } struct sync_state* sync_alloc_state(void *context, peer_has has, peer_does_not_have has_not, peer_now_has now_has){ struct sync_state *state = emalloc_zero(sizeof (struct sync_state)); state->context = context; state->has = has; state->has_not = has_not; state->now_has = now_has; return state; } // clear all memory used by this state void sync_free_state(struct sync_state *state){ while(state->transmit_ptr){ struct node *p = state->transmit_ptr; state->transmit_ptr = state->transmit_ptr->transmit_next; p->transmit_next=NULL; p->transmit_prev=NULL; } free_node(NULL, state->root); while(state->peers){ struct sync_peer_state *peer_state = state->peers; free_node(NULL, peer_state->root); state->peers = peer_state->next; free(peer_state); } free(state); } static void copy_message(uint8_t *buff, const key_message_t *message) { if (message){ buff[0] = (message->stored?0x80:0) | (message->min_prefix_len & 0x7f); buff[1] = message->prefix_len; memcpy(&buff[2], &message->key.key[0], KEY_LEN); }else{ bzero(buff, MESSAGE_BYTES); buff[0] = 0x80; buff[1] = KEY_LEN_BITS+1; } } // prepare a network packet buffer, with as many queued outgoing messages that we can fit size_t sync_build_message(struct sync_state *state, uint8_t *buff, size_t len) { size_t offset=0; state->sent_messages++; state->progress++; struct node *tail = state->transmit_ptr; while(tail && offset + MESSAGE_BYTES<=len){ struct node *head = tail->transmit_next; assert(head->transmit_prev == tail); if (head->send_state == QUEUED){ copy_message(&buff[offset], &head->message); offset+=MESSAGE_BYTES; head->sent_count++; state->sent_record_count++; if (head->sent_count>=SYNC_MAX_RETRIES) head->send_state = SENT; } if (head->send_state == QUEUED){ // advance tail pointer tail = head; }else{ struct node *next = head->transmit_next; head->transmit_next = NULL; head->transmit_prev = NULL; if (head == tail || next == head){ // transmit loop is now empty tail = NULL; break; }else{ // remove from the transmit loop tail->transmit_next = next; next->transmit_prev = tail; } } // stop if we just sent everything in the loop once. if (head == state->transmit_ptr) break; } state->transmit_ptr = tail; // If we don't have anything else to send, always send our root tree node if(offset + MESSAGE_BYTES<=len && offset==0){ state->sent_root++; copy_message(&buff[offset], state->root ? &state->root->message : NULL); offset+=MESSAGE_BYTES; state->sent_record_count++; } return offset; } // Add a tree node into our transmission queue // the node can be added to the head or tail of the list. static void queue_node(struct sync_state *state, struct node *node, uint8_t head) { node->send_state = QUEUED; if (node->transmit_next) return; if (node->message.prefix_len == KEY_LEN_BITS) state->progress=0; // insert this node into the transmit loop if (!state->transmit_ptr){ state->transmit_ptr = node; node->transmit_next = node; node->transmit_prev = node; }else{ node->transmit_next = state->transmit_ptr->transmit_next; node->transmit_prev = state->transmit_ptr; node->transmit_next->transmit_prev = node; node->transmit_prev->transmit_next = node; // advance past this node to transmit it last if (!head) state->transmit_ptr = node; } } static unsigned peer_is_missing(struct sync_state *state, struct sync_peer_state *peer, const struct node *node, uint8_t allow_remove) { const struct node *peer_node = find_message(peer->root, &node->message); if (peer_node){ if (peer_node->message.stored && allow_remove){ // peer has now received this key? if (state->now_has) state->now_has(state->context, peer->peer_context, node->context, &node->message.key); remove_key(state, &peer->root, &node->message.key); peer->send_count --; return 1; } return 0; } add_key(&peer->root, &node->message.key, node->context, 1); peer->send_count ++; state->progress=0; if (state->has_not) state->has_not(state->context, peer->peer_context, node->context, &node->message.key); return 1; } // traverse the children of this node, and add them all to the transmit queue // optionally ignoring a single child of this node. static void peer_missing_leaf_nodes( struct sync_state *state, struct sync_peer_state *peer, struct node *node, unsigned except, uint8_t allow_remove) { if (node->message.prefix_len == KEY_LEN_BITS){ if (peer_is_missing(state, peer, node, allow_remove)) queue_node(state, node, 1); }else{ unsigned i; for (i=0;i<NODE_CHILDREN;i++){ if (i!=except && node->children[i]) peer_missing_leaf_nodes(state, peer, node->children[i], NODE_CHILDREN, allow_remove); } } } static void peer_add_key(struct sync_state *state, struct sync_peer_state *peer_state, const key_message_t *message) { if (message->prefix_len != KEY_LEN_BITS || !message->stored) return; struct node *node = add_key_if_missing(&peer_state->root, message, 0); if (node){ //Yay, they told us something we didn't know. state->progress=0; peer_state->recv_count++; if (state->has) state->has(state->context, peer_state->peer_context, &message->key); queue_node(state, node, 0); } } /* static void de_queue(struct node *node){ if (node->send_state == QUEUED) node->send_state = DONT_SEND; for (unsigned i=0;i<NODE_CHILDREN;i++) if (node->children[i]) de_queue(node->children[i]); } */ static unsigned peer_has_received_all(struct sync_state *state, struct sync_peer_state *peer_state, struct node *peer_node) { if (!peer_node) return 0; unsigned ret=0; if (peer_node->message.prefix_len == KEY_LEN_BITS){ if (peer_node->message.stored){ if (state->now_has) state->now_has(state->context, peer_state->peer_context, peer_node->context, &peer_node->message.key); remove_key(state, &peer_state->root, &peer_node->message.key); peer_state->send_count --; ret=1; } }else{ // duplicate the child pointers, as removing an immediate child key *will* also free this peer node. struct node *children[NODE_CHILDREN]; memcpy(children, peer_node->children, sizeof(children)); unsigned i; for (i=0;i<NODE_CHILDREN;i++) ret+=peer_has_received_all(state, peer_state, children[i]); } return ret; } // add information about keys sent to this peer, // remove information about keys received from this peer // (both operations are XOR's) // returns a struct node if this message is an exact match static struct node * remove_differences(struct sync_peer_state *peer_state, key_message_t *message) { if (!peer_state->root || !message->stored) return NULL; struct node *peer_node = peer_state->root; uint8_t prefix_len = 0; while(prefix_len < message->prefix_len){ if (peer_node->message.prefix_len == KEY_LEN_BITS){ if (cmp_message(message, &peer_node->message)==0) break; if (message->prefix_len == KEY_LEN_BITS) return NULL; } uint8_t child_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &message->key); if (prefix_len < peer_node->message.prefix_len){ // TODO optimise this case by comparing all possible prefix bits in one hit uint8_t node_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &peer_node->message.key); if (node_index != child_index) return NULL; // no match }else{ peer_node = peer_node->children[child_index]; if (!peer_node) return NULL; } prefix_len+=PREFIX_STEP_BITS; } if (message->prefix_len < KEY_LEN_BITS){ if (peer_node->message.prefix_len == message->prefix_len || peer_node->message.prefix_len == KEY_LEN_BITS){ // shortcut, we can xor the nodes sync_xor(&peer_node->message.key, message); }else{ // we need to xor all children so we can get the prefix bits right. xor_children(peer_node, message); } } return peer_node; } // Proccess one incoming tree record. static int recv_key(struct sync_state *state, struct sync_peer_state *peer_state, const key_message_t *message) { // sanity check on two header bytes. if (message->min_prefix_len > message->prefix_len || message->prefix_len > KEY_LEN_BITS+1) return WHYF("Malformed message (min_prefix = %u, prefix = %u)", message->min_prefix_len, message->prefix_len); state->received_record_count++; /* Possible outcomes; key is an exact match for part of our tree Yay, nothing to do. key->prefix_len == KEY_LEN_BITS && we don't have this node Woohoo, we discovered something we didn't know before! they are missing sibling nodes between their min_prefix_len and prefix_len queue all the sibling leaf nodes! our node doesn't match XOR our node against theirs search our tree for a single leaf node that matches this result if found; queue this leaf node for transmission else drill down our tree while our node has only one child? TODO our tree nodes should never have one child queue (N-1 of?) this node's children for transmission */ if (!state->root){ peer_add_key(state, peer_state, message); return 0; } if (message->prefix_len == KEY_LEN_BITS+1){ // peer has no node of their own, they don't have anything that we have. peer_missing_leaf_nodes(state, peer_state, state->root, NODE_CHILDREN, 0); return 0; } key_message_t peer_message = *message; // first, remove information from peer_message that we have already learnt about this peer struct node *peer_node = remove_differences(peer_state, &peer_message); struct node *node = state->root; uint8_t prefix_len = 0; uint8_t is_blank = 1; unsigned i; for (i=(peer_message.prefix_len>>3)+1;i<KEY_LEN && is_blank;i++) if (peer_message.key.key[i]) is_blank = 0; while(1){ if (cmp_message(message, &node->message)==0){ // if we queued this exact message, there's no point sending it now. // but don't cancel every child, that breaks with multiple peers. if (node->send_state == QUEUED) node->send_state = DONT_SEND; if (message->stored){ // we can mark any keys they need as being received if (peer_has_received_all(state, peer_state, peer_node)==0) state->received_uninteresting++; }else{ // peer is ACK'ing that they need to know this key, which we have if (peer_is_missing(state, peer_state, node, 0)==0) state->received_uninteresting++; } return 0; } // Nothing to do if we understand the rest of the differences if (cmp_message(&peer_message, &node->message)==0){ state->received_uninteresting++; return 0; } // once we've looked at all of the prefix_len bits of the incoming key // we need to stop if (peer_message.prefix_len <= prefix_len){ if (is_blank){ // This peer doesn't know any of the children of this node peer_missing_leaf_nodes(state, peer_state, node, NODE_CHILDREN, 1); }else if (node->message.prefix_len > peer_message.prefix_len){ // reply with our matching node queue_node(state, node, 1); }else{ // compare their node to our tree, test if we can easily detect a part of our tree they don't know // Note, this only works if there are an odd number of different leaf nodes // With an even number of keys, the XOR will wipe out the prefix bits. // work out the difference between their node and ours key_message_t test_message = peer_message; sync_xor(&node->message.key, &test_message); // if we can explain the difference based on a matching node, queue all leaf nodes struct node *test_node = node; uint8_t test_prefix = prefix_len; while(test_node) { if (cmp_message(&test_message, &test_node->message)==0){ // This peer doesn't know any of the children of this node peer_missing_leaf_nodes(state, peer_state, test_node, NODE_CHILDREN, 1); return 0; } if (test_node->message.prefix_len == KEY_LEN_BITS) break; uint8_t child_index = sync_get_bits(test_prefix, PREFIX_STEP_BITS, &test_message.key); if (test_prefix<test_node->message.prefix_len){ // TODO optimise this case by comparing all possible prefix bits in one hit uint8_t node_index = sync_get_bits(test_prefix, PREFIX_STEP_BITS, &test_node->message.key); if (node_index != child_index) break; // no match }else{ test_node = test_node->children[child_index]; } test_prefix+=PREFIX_STEP_BITS; } // queue the transmission of all child nodes of this node unsigned i; for (i=0;i<NODE_CHILDREN;i++){ if (node->children[i]) queue_node(state, node->children[i], 0); } } return 0; } // which branch of the tree should we look at next uint8_t key_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &peer_message.key); // if our node represents a large range of the keyspace, find the first prefix bit that differs while (prefix_len < node->message.prefix_len && prefix_len < peer_message.prefix_len){ // check the next step bits uint8_t existing_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &node->message.key); if (key_index != existing_index){ // If the prefix of our node differs from theirs, they don't have any of these keys // send them all if (prefix_len >= peer_message.min_prefix_len && peer_message.stored){ peer_missing_leaf_nodes(state, peer_state, node, NODE_CHILDREN, 0); if (peer_message.prefix_len != KEY_LEN_BITS) // and after they have added all these missing keys, they need to know // this summary node so they can be reminded to send this key or it's children again. queue_node(state, node, 0); } if (peer_message.prefix_len == KEY_LEN_BITS) peer_add_key(state, peer_state, &peer_message); return 0; } prefix_len += PREFIX_STEP_BITS; key_index = sync_get_bits(prefix_len, PREFIX_STEP_BITS, &peer_message.key); } if (message->prefix_len <= prefix_len) continue; assert(prefix_len == node->message.prefix_len); if (peer_message.min_prefix_len <= node->message.prefix_len && peer_message.stored){ // send all keys to the other party, except for the child @key_index // they don't have any of these siblings peer_missing_leaf_nodes(state, peer_state, node, key_index, 0); } // look at the next node in our graph if (!node->children[key_index]){ // we know nothing about this key if (peer_message.prefix_len == KEY_LEN_BITS){ peer_add_key(state, peer_state, &peer_message); }else{ // hopefully the other party will tell us something, // and we won't get stuck in a loop talking about the same node. queue_node(state, node, 0); } return 0; } // Don't retransmit if we have heard some kind of confirmation of delivery from a peer // this is broken! //if (node->sent_count>0 && node->send_state == QUEUED) // node->send_state = SENT; node = node->children[key_index]; prefix_len += PREFIX_STEP_BITS; } } // Process all incoming messages from this packet buffer int sync_recv_message(struct sync_state *state, void *peer_context, const uint8_t *buff, size_t len) { assert(peer_context); struct sync_peer_state *peer_state = state->peers; while(peer_state && peer_state->peer_context != peer_context){ peer_state = peer_state->next; } if (!peer_state){ peer_state = emalloc_zero(sizeof(struct sync_peer_state)); peer_state->peer_context = peer_context; peer_state->next = state->peers; state->peers = peer_state; } size_t offset=0; if (len%MESSAGE_BYTES) return -1; while(offset + MESSAGE_BYTES<=len){ const uint8_t *p = &buff[offset]; key_message_t message; bzero(&message, sizeof message); message.stored = (p[0]&0x80)?1:0; message.min_prefix_len = p[0]&0x7F; message.prefix_len = p[1]; memcpy(&message.key.key[0], &p[2], KEY_LEN); if (recv_key(state, peer_state, &message)==-1) return -1; offset+=MESSAGE_BYTES; } return 0; } static void enum_diffs(struct sync_state *state, struct sync_peer_state *peer_state, struct node *node, void (*callback)(void *context, void *peer_context, const sync_key_t *key, uint8_t theirs)) { if (!node) return; if (node->message.prefix_len == KEY_LEN_BITS){ callback(state->context, peer_state->peer_context, &node->message.key, node->message.stored); }else{ unsigned i; for (i=0;i<NODE_CHILDREN;i++){ enum_diffs(state, peer_state, node->children[i], callback); } } } void sync_enum_differences(struct sync_state *state, void (*callback)(void *context, void *peer_context, const sync_key_t *key, uint8_t theirs)) { struct sync_peer_state *peer_state = state->peers; while(peer_state){ enum_diffs(state, peer_state, peer_state->root, callback); peer_state = peer_state->next; } }