// generate json of mesh keys and current paths lob_t mesh_json(mesh_t mesh) { lob_t json, paths; if(!mesh) return LOG_ERROR("bad args"); json = lob_new(); lob_set(json,"hashname",hashname_char(mesh->id)); lob_set_raw(json,"keys",0,(char*)mesh->keys->head,mesh->keys->head_len); paths = lob_array(mesh->paths); lob_set_raw(json,"paths",0,(char*)paths->head,paths->head_len); lob_free(paths); return json; }
// ack/miss only base packet lob_t e3x_channel_oob(e3x_channel_t c) { lob_t ret, cur; char *miss; uint32_t seq, last, delta; size_t len; if(!c) return NULL; ret = lob_new(); lob_set_uint(ret,"c",c->id); if(!c->seq) return ret; // check for ack/miss if(c->ack != c->acked) { lob_set_uint(ret,"ack",c->ack); // also check to include misses cur = c->in; last = c->ack; if(cur && (cur->id - last) != 1) { // I'm so tired of strings in c len = 2; if(!(miss = malloc(len))) return lob_free(ret); len = (size_t)snprintf(miss,len,"["); for(seq=c->ack+1; cur; seq++) { // LOG("ack %d seq %d last %d cur %d",c->ack,seq,last,cur->id); // if we have this seq, skip to next packet if(cur->id <= seq) { cur = cur->next; continue; } // insert this missing seq delta delta = seq - last; last = seq; len += (size_t)snprintf(NULL, 0, "%u,", delta) + 1; if(!(miss = realloc(miss, len))) return lob_free(ret); sprintf(miss+strlen(miss),"%u,", delta); } // add current window at the end delta = 100; // TODO calculate this from actual space avail len += (size_t)snprintf(NULL, 0, "%u]", delta) + 1; if(!(miss = realloc(miss, len))) return lob_free(ret); sprintf(miss+strlen(miss),"%u]", delta); lob_set_raw(ret,"miss",4,miss,strlen(miss)); } c->acked = c->ack; } return ret; }
// 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; }
// process any unencrypted handshake packet link_t mesh_receive_handshake(mesh_t mesh, lob_t handshake, pipe_t pipe) { uint32_t now; hashname_t from; link_t link; if(!mesh || !handshake) return LOG("bad args"); if(!lob_get(handshake,"id")) { LOG("bad handshake, no id: %s",lob_json(handshake)); lob_free(handshake); return NULL; } now = util_sys_seconds(); // normalize handshake handshake->id = now; // save when we cached it if(!lob_get(handshake,"type")) lob_set(handshake,"type","link"); // default to link type if(!lob_get_uint(handshake,"at")) lob_set_uint(handshake,"at",now); // require an at LOG("handshake at %d id %s",now,lob_get(handshake,"id")); // validate/extend link handshakes immediately if(util_cmp(lob_get(handshake,"type"),"link") == 0) { // get the csid uint8_t csid = 0; lob_t outer; if((outer = lob_linked(handshake))) { csid = outer->head[0]; }else if(lob_get(handshake,"csid")){ util_unhex(lob_get(handshake,"csid"),2,&csid); } if(!csid) { LOG("bad link handshake, no csid: %s",lob_json(handshake)); lob_free(handshake); return NULL; } char hexid[3] = {0}; util_hex(&csid, 1, hexid); // get attached hashname lob_t tmp = lob_parse(handshake->body, handshake->body_len); from = hashname_vkey(tmp, csid); if(!from) { LOG("bad link handshake, no hashname: %s",lob_json(handshake)); lob_free(tmp); lob_free(handshake); return NULL; } lob_set(handshake,"csid",hexid); lob_set(handshake,"hashname",hashname_char(from)); lob_set_raw(handshake,hexid,2,"true",4); // intermediate format lob_body(handshake, tmp->body, tmp->body_len); // re-attach as raw key lob_free(tmp); // short-cut, if it's a key from an existing link, pass it on // TODO: using mesh_linked here is a stack issue during loopback peer test! if((link = mesh_linkid(mesh,from))) return link_receive_handshake(link, handshake, pipe); LOG("no link found for handshake from %s",hashname_char(from)); // extend the key json to make it compatible w/ normal patterns tmp = lob_new(); lob_set_base32(tmp,hexid,handshake->body,handshake->body_len); lob_set_raw(handshake,"keys",0,(char*)tmp->head,tmp->head_len); lob_free(tmp); // add the path if one if(pipe && pipe->path) { char *paths = malloc(pipe->path->head_len+3); sprintf(paths,"[%.*s]",(int)pipe->path->head_len,(char*)pipe->path->head); lob_set_raw(handshake,"paths",0,paths,pipe->path->head_len+2); free(paths); } } // always add to the front of the cached list if needed in the future mesh->cached = lob_unshift(mesh->cached, handshake); // tell anyone listening about the newly discovered handshake mesh_discover(mesh, handshake, pipe); return NULL; }