// get keys from query lob_t util_uri_keys(lob_t uri) { uint32_t i; char *key, *value; lob_t keys, query = lob_linked(uri); if(!query) return NULL; keys = lob_new(); // loop through all keyval pairs to find cs** for(i=0;(key = lob_get_index(query,i));i+=2) { value = lob_get_index(query,i+1); if(strlen(key) != 4 || strncmp(key,"cs",2) != 0 || !value) continue; // skip non-csid keys lob_set_len(keys,key+2,2,value,strlen(value)); } return keys; }
// get paths from host and query lob_t util_uri_paths(lob_t uri) { uint32_t i; uint16_t port; uint8_t *buf; size_t len; char *key, *value; lob_t paths, query = lob_linked(uri); if(!query) return NULL; paths = NULL; // gen paths from host/port if((port = lob_get_uint(uri,"port"))) { key = lob_get(uri,"host"); paths = lob_chain(paths); lob_set(paths,"type","upd4"); lob_set(paths,"ip",key); lob_set_uint(paths,"port",port); paths = lob_chain(paths); lob_set(paths,"type","tcp4"); lob_set(paths,"ip",key); lob_set_uint(paths,"port",port); } // loop through all keyval pairs to find paths buf = NULL; for(i=0;(key = lob_get_index(query,i));i+=2) { value = lob_get_index(query,i+1); if(util_cmp(key,"paths") != 0 || !value) continue; len = base32_decode_floor(strlen(value)); buf = util_reallocf(buf,len); if(!buf) continue; if(base32_decode(value,strlen(value),buf,len) < len) continue; paths = lob_link(lob_parse(buf,len), paths); } free(buf); return paths; }
// create hashname from intermediate values as hex/base32 key/value pairs hashname_t hashname_key(lob_t key, uint8_t csid) { unsigned int i, start; uint8_t hash[64]; char *id, *value, hexid[3]; hashname_t hn = NULL; if(!key) return LOG("invalid args"); util_hex(&csid, 1, hexid); // get in sorted order lob_sort(key); // loop through all keys rolling up for(i=0;(id = lob_get_index(key,i));i+=2) { value = lob_get_index(key,i+1); if(strlen(id) != 2 || !util_ishex(id,2) || !value) continue; // skip non-id keys // hash the id util_unhex(id,2,hash+32); start = (i == 0) ? 32 : 0; // only first one excludes previous rollup e3x_hash(hash+start,(32-start)+1,hash); // hash in place // get the value from the body if matching csid arg if(util_cmp(id, hexid) == 0) { if(key->body_len == 0) return LOG("missing key body"); // hash the body e3x_hash(key->body,key->body_len,hash+32); }else{ if(strlen(value) != 52) return LOG("invalid value %s %d",value,strlen(value)); if(base32_decode(value,52,hash+32,32) != 32) return LOG("base32 decode failed %s",value); } e3x_hash(hash,64,hash); } if(!i || i % 2 != 0) return LOG("invalid keys %d",i); hn = hashname_new(hash); return hn; }
lob_t util_uri_add_keys(lob_t uri, lob_t keys) { uint32_t i; char *key, *value, csid[5]; lob_t query = lob_linked(uri); if(!uri || !keys) return NULL; if(!query) { query = lob_new(); lob_link(uri, query); } for(i=0;(key = lob_get_index(keys,i));i+=2) { value = lob_get_index(keys,i+1); if(strlen(key) != 2 || !value) continue; // paranoid snprintf(csid,5,"cs%s",key); lob_set(query,csid,value); } return uri; }
// intermediate hashes in the json, if id is given it is attached as BODY instead lob_t hashname_im(lob_t keys, uint8_t id) { uint32_t i; size_t len; uint8_t *buf, hash[32]; char *key, *value, hex[3]; lob_t im; if(!keys) return LOG("bad args"); // loop through all keys and create intermediates im = lob_new(); buf = NULL; util_hex(&id,1,hex); for(i=0;(key = lob_get_index(keys,i));i+=2) { value = lob_get_index(keys,i+1); if(strlen(key) != 2 || !value) continue; // skip non-csid keys len = base32_decode_floor(strlen(value)); // save to body raw or as a base32 intermediate value if(id && util_cmp(hex,key) == 0) { lob_body(im,NULL,len); if(base32_decode(value,strlen(value),im->body,len) != len) continue; lob_set_raw(im,key,0,"true",4); }else{ buf = util_reallocf(buf,len); if(!buf) return lob_free(im); if(base32_decode(value,strlen(value),buf,len) != len) continue; // store the hash intermediate value e3x_hash(buf,len,hash); lob_set_base32(im,key,hash,32); } } if(buf) free(buf); return im; }
lob_t link_handshakes(link_t link) { uint32_t i; uint8_t csid; char *key; lob_t tmp, hs = NULL, handshakes = NULL; if(!link) return NULL; // no keys means we have to generate a handshake for each key if(!link->x) { for(i=0;(key = lob_get_index(link->mesh->keys,i));i+=2) { util_unhex(key,2,&csid); hs = lob_new(); tmp = hashname_im(link->mesh->keys, csid); lob_body(hs, lob_raw(tmp), lob_len(tmp)); lob_free(tmp); handshakes = lob_link(hs, handshakes); } }else{ // generate one just for this csid handshakes = lob_new(); tmp = hashname_im(link->mesh->keys, link->csid); lob_body(handshakes, lob_raw(tmp), lob_len(tmp)); lob_free(tmp); } // add any custom per-link for(hs = link->handshakes; hs; hs = lob_linked(hs)) handshakes = lob_link(lob_copy(hs), handshakes); // add any mesh-wide handshakes for(hs = link->mesh->handshakes; hs; hs = lob_linked(hs)) handshakes = lob_link(lob_copy(hs), handshakes); // encrypt them if we can if(link->x) { tmp = handshakes; handshakes = NULL; for(hs = tmp; hs; hs = lob_linked(hs)) handshakes = lob_link(e3x_exchange_handshake(link->x, hs), handshakes); lob_free(tmp); } return handshakes; }
uint8_t hashname_id(lob_t a, lob_t b) { uint8_t id, best; uint32_t i; char *key; if(!a || !b) return 0; best = 0; for(i=0;(key = lob_get_index(a,i));i+=2) { if(strlen(key) != 2) continue; if(!lob_get(b,key)) continue; id = 0; util_unhex(key,2,&id); if(id > best) best = id; } return best; }
int main(int argc, char **argv) { lob_t packet; packet = lob_new(); fail_unless(packet); lob_free(packet); uint8_t buf[1024]; char *hex = "001d7b2274797065223a2274657374222c22666f6f223a5b22626172225d7d616e792062696e61727921"; uint8_t len = strlen(hex)/2; util_unhex(hex,strlen(hex),buf); packet = lob_parse(buf,len); fail_unless(packet); fail_unless(lob_len(packet)); fail_unless(packet->head_len == 29); fail_unless(packet->body_len == 11); fail_unless(util_cmp(lob_get(packet,"type"),"test") == 0); fail_unless(util_cmp(lob_get(packet,"foo"),"[\"bar\"]") == 0); lob_free(packet); packet = lob_new(); lob_set_base32(packet,"32",buf,len); fail_unless(lob_get(packet,"32")); fail_unless(strlen(lob_get(packet,"32")) == (base32_encode_length(len)-1)); lob_t bin = lob_get_base32(packet,"32"); fail_unless(bin); fail_unless(bin->body_len == len); lob_set(packet,"key","value"); fail_unless(lob_keys(packet) == 2); // test sorting lob_set(packet,"zz","value"); lob_set(packet,"a","value"); lob_set(packet,"z","value"); lob_sort(packet); fail_unless(util_cmp(lob_get_index(packet,0),"32") == 0); fail_unless(util_cmp(lob_get_index(packet,2),"a") == 0); fail_unless(util_cmp(lob_get_index(packet,4),"key") == 0); fail_unless(util_cmp(lob_get_index(packet,6),"z") == 0); fail_unless(util_cmp(lob_get_index(packet,8),"zz") == 0); lob_free(packet); // minimal comparison test lob_t a = lob_new(); lob_set(a,"foo","bar"); lob_t b = lob_new(); lob_set(b,"foo","bar"); fail_unless(lob_cmp(a,b) == 0); lob_set(b,"bar","foo"); fail_unless(lob_cmp(a,b) != 0); // lots of basic list testing lob_t list = lob_new(); lob_t item = lob_new(); fail_unless(lob_push(list,item)); fail_unless(lob_pop(list) == item); list = item->next; fail_unless((list = lob_unshift(list,item))); fail_unless(lob_shift(list) == item); list = item->next; fail_unless(lob_push(list,item)); fail_unless(list->next == item); lob_t insert = lob_new(); fail_unless(lob_insert(list,list,insert)); fail_unless(list->next == insert); fail_unless(insert->next == item); fail_unless(lob_splice(list,insert)); fail_unless(list->next == item); lob_t array = lob_array(list); fail_unless(array); fail_unless(util_cmp(lob_json(array),"[,]") == 0); fail_unless(lob_freeall(list) == NULL); // simple index testing lob_t index = lob_new(); lob_t c1 = lob_new(); lob_set(c1,"id","c1"); lob_push(index,c1); lob_t c2 = lob_new(); lob_set(c2,"id","c2"); lob_push(index,c2); fail_unless(lob_match(index,"id","c1") == c1); fail_unless(lob_match(index,"id","c2") == c2); float f = 42.42; lob_t ft = lob_new(); lob_head(ft,(uint8_t*)"{\"foo\":42.42}",13); fail_unless(lob_get_float(ft,"foo") == f); lob_set_float(ft,"bar2",f,2); fail_unless(lob_get_float(ft,"bar2") == f); lob_set_float(ft,"bar1",f,1); fail_unless(lob_get_cmp(ft,"bar1","42.4") == 0); lob_set_float(ft,"bar0",f,0); fail_unless(lob_get_int(ft,"bar0") == 42); LOG("floats %s",lob_json(ft)); return 0; }
// serialize out from lob format to "uri" key and return it char *util_uri_format(lob_t uri) { char *part, *key, *value; uint32_t i, prev = 0; lob_t buf, query; if(!uri) return NULL; // use a lob body as the buffer to build it up buf = lob_new(); part = lob_get(uri, "protocol"); if(part) { lob_append_str(buf, part); }else{ lob_append_str(buf, "link"); } lob_append_str(buf, "://"); part = lob_get(uri, "hostname"); if(part) { lob_append_str(buf, part); part = lob_get(uri, "port"); if(part) { lob_append_str(buf, ":"); lob_append_str(buf, part); } }else{ part = lob_get(uri, "host"); if(part) lob_append_str(buf, part); } part = lob_get(uri, "path"); if(part) { lob_append_str(buf, part); }else{ lob_append_str(buf, "/"); } // append on any query string for(query = lob_linked(uri); query; query = lob_linked(query)) { for(i=0;(key = lob_get_index(query,i));i+=2) { value = lob_get_index(query,i+1); if(!strlen(key) || !value) continue; // paranoid lob_append_str(buf,(prev++)?"&":"?"); lob_append_str(buf,key); lob_append_str(buf,"="); lob_append_str(buf,value); } } if((part = lob_get(uri, "hash"))) { lob_append_str(buf, "#"); lob_append_str(buf, part); } lob_set_len(uri,"uri",3,(char*)buf->body,buf->body_len); lob_free(buf); return lob_get(uri,"uri"); }