// must be called after every send or receive, pass pkt to e3x_encrypt before sending lob_t e3x_channel_sending(e3x_channel_t c) { lob_t ret; uint32_t now; if(!c) return NULL; // packets waiting if(c->out) { ret = lob_shift(c->out); c->out = ret->next; // if it's a content packet and reliable, add to sent list if(c->seq && ret->id) c->sent = lob_push(c->sent, lob_copy(ret)); return ret; } // check sent list for any flagged to resend now = util_sys_seconds(); for(ret = c->sent; ret; ret = ret->next) { if(!ret->id) continue; if(ret->id == now) continue; // max once per second throttle resend ret->id = now; return ret; } LOG("sending ack %d acked %d",c->ack,c->acked); // if we need to generate an ack/miss yet, do that if(c->ack != c->acked) return e3x_channel_oob(c); return NULL; }
// this will set the default inactivity timeout using this event timer and our uid uint32_t e3x_channel_timeout(e3x_channel_t c, e3x_event_t ev, uint32_t timeout) { if(!c) return 0; // un-set any if(ev != c->ev) { // cancel and clearn any previous timer state c->timeout = 0; if(c->ev) e3x_event_set(c->ev,NULL,c->uid,0); c->ev = NULL; lob_free(c->timer); c->timer = NULL; } // no event manager, no timeouts if(!ev) return 0; // no timeout, just return how much time is left if(!timeout) return _time_left(c); // add/update new timeout c->tsince = util_sys_seconds(); // start timer now c->timeout = timeout; c->ev = ev; c->timer = lob_new(); lob_set_uint(c->timer,"c",c->id); lob_set(c->timer, "id", c->uid); lob_set(c->timer, "err", "timeout"); e3x_event_set(c->ev, c->timer, lob_get(c->timer, "id"), timeout*1000); // ms in the future return _time_left(c); }
// internally calculate until timeout uint32_t _time_left(e3x_channel_t c) { uint32_t at = util_sys_seconds(); if(!c) return 0; if(!c->timeout) return 1; // never timeout // some seconds left yet if((at - c->tsince) < c->timeout) return c->timeout - (at - c->tsince); return 0; }
uint64_t util_at(void) { uint64_t at; uint32_t *half = (uint32_t*)(&at); // store both current seconds and ms since then in one value half[0] = util_sys_seconds(); half[1] = (uint32_t)util_sys_ms(half[0]); return at; }
// load in the key to existing link link_t link_load(link_t link, uint8_t csid, lob_t key) { char hex[3]; lob_t copy; if(!link || !csid || !key) return LOG("bad args"); if(link->x) { link->csid = link->x->csid; // repair in case mesh_unlink was called, any better place? return link; } LOG("adding %x key to link %s",csid,hashname_short(link->id)); // key must be bin if(key->body_len) { copy = lob_new(); lob_body(copy,key->body,key->body_len); }else{ util_hex(&csid,1,hex); copy = lob_get_base32(key,hex); } link->x = e3x_exchange_new(link->mesh->self, csid, copy); if(!link->x) { LOG("invalid %x key %s %s",csid,util_hex(copy->body,copy->body_len,NULL),lob_json(key)); lob_free(copy); return NULL; } link->csid = csid; link->key = copy; e3x_exchange_out(link->x, util_sys_seconds()); LOG("new exchange session to %s",hashname_short(link->id)); return link; }
// load in the key to existing link link_t link_load(link_t link, uint8_t csid, lob_t key) { char hex[3]; lob_t copy; if(!link || !csid || !key) return LOG("bad args"); if(link->x) return link; LOG("adding %x key to link %s",csid,link->id->hashname); // key must be bin if(key->body_len) { copy = lob_copy(key); }else{ util_hex(&csid,1,hex); copy = lob_get_base32(key,hex); } link->x = e3x_exchange_new(link->mesh->self, csid, copy); if(!link->x) { lob_free(copy); return LOG("invalid %x key %d %s",csid,key->body_len,lob_json(key)); } link->csid = csid; link->key = copy; // route packets to this token util_hex(e3x_exchange_token(link->x),16,link->token); xht_set(link->mesh->index,link->token,link); e3x_exchange_out(link->x, util_sys_seconds()); LOG("new session token %s to %s",link->token,link->id->hashname); return link; }
// 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; }