// new incoming block channel, set up handler lob_t block_on_open(link_t link, lob_t open) { ext_block_t block; if(!link) return open; if(lob_get_cmp(open,"type","block")) return open; if((block = xht_get(link->index, "block"))) { LOG("note: new incoming block channel replacing existing one"); // TODO delete old channel }else{ LOG("incoming block channel open"); // create new block if(!(block = malloc(sizeof (struct ext_block_struct)))) return LOG("OOM"); memset(block,0,sizeof (struct ext_block_struct)); block->link = link; // add to list of all blocks block->next = xht_get(link->mesh->index, "blocks"); xht_set(link->mesh->index, "blocks", block); } // create new channel for this block handler block->chan = link_channel(link, open); link_handle(link,block->chan,block_chan_handler,block); return NULL; }
// process a decrypted channel packet link_t link_receive(link_t link, lob_t inner, pipe_t pipe) { chan_t chan; if(!link || !inner) return LOG("bad args"); // see if existing channel and send there if((chan = xht_get(link->index, lob_get(inner,"c")))) { if(channel3_receive(chan->c3, inner)) return LOG("channel receive error, dropping %s",lob_json(inner)); link_pipe(link,pipe); // we trust the pipe at this point if(chan->handle) chan->handle(link, chan->c3, chan->arg); // check if there's any packets to be sent back return link_flush(link, chan->c3, NULL); } // if it's an open, validate and fire event if(!lob_get(inner,"type")) return LOG("invalid channel open, no type %s",lob_json(inner)); if(!exchange3_cid(link->x, inner)) return LOG("invalid channel open id %s",lob_json(inner)); link_pipe(link,pipe); // we trust the pipe at this point inner = mesh_open(link->mesh,link,inner); if(inner) { LOG("unhandled channel open %s",lob_json(inner)); lob_free(inner); return NULL; } return link; }
// internal, get or create a pipe pipe_t tcp4_pipe(net_tcp4_t net, char *ip, int port) { pipe_t pipe; pipe_tcp4_t to; char id[23]; snprintf(id,23,"%s:%d",ip,port); pipe = xht_get(net->pipes,id); if(pipe) return pipe; LOG("new pipe to %s",id); // create new tcp4 pipe if(!(pipe = pipe_new("tcp4"))) return NULL; if(!(pipe->arg = to = malloc(sizeof (struct pipe_tcp4_struct)))) return pipe_free(pipe); memset(to,0,sizeof (struct pipe_tcp4_struct)); to->net = net; to->sa.sin_family = AF_INET; inet_aton(ip, &(to->sa.sin_addr)); to->sa.sin_port = htons(port); if(!(to->chunks = chunks_new(0))) return tcp4_free(pipe); // set up pipe pipe->id = strdup(id); xht_set(net->pipes,pipe->id,pipe); pipe->send = tcp4_send; return pipe; }
// set up internal handler for all incoming packets on this channel link_t link_handle(link_t link, channel3_t c3, void (*handle)(link_t link, channel3_t c3, void *arg), void *arg) { chan_t chan; if(!link || !c3) return LOG("bad args"); chan = xht_get(link->channels, channel3_uid(c3)); if(!chan) return LOG("unknown channel %s",channel3_uid(c3)); chan->handle = handle; chan->arg = arg; return link; }
// get the next incoming block, if any, packet->arg is the link it came from lob_t ext_block_receive(mesh_t mesh) { ext_block_t block; if(!mesh) return LOG("bad args"); block = xht_get(mesh->index, "blocks"); for(;block && block->cache; block = block->next) { // TODO get next block and remove/return it } return NULL; }
pipe_t tcp4_path(link_t link, lob_t path) { net_tcp4_t net; char *ip; int port; // just sanity check the path first if(!link || !path) return NULL; if(!(net = xht_get(link->mesh->index, MUID))) return NULL; if(util_cmp("tcp4",lob_get(path,"type"))) return NULL; if(!(ip = lob_get(path,"ip"))) return LOG("missing ip"); if((port = lob_get_int(path,"port")) <= 0) return LOG("missing port"); return tcp4_pipe(net, ip, port); }
// creates/reuses a single default block channel on the link link_t ext_block_send(link_t link, lob_t block) { channel3_t chan; if(!link || !block) return LOG("bad args"); if(!(chan = xht_get(link->index,"block"))) { // TODO create outgoing channel xht_set(link->index,"block",chan); } // break block into packets and send return link; }
link_t link_get(mesh_t mesh, char *hashname) { link_t link; hashname_t id; if(!mesh || !hashname) return LOG("invalid args"); link = xht_get(mesh->index,hashname); if(!link) { id = hashname_str(hashname); if(!id) return LOG("invalid hashname %s",hashname); link = link_new(mesh,id); } return link; }
pipe_t net_serial_add(net_serial_t net, const char *name, int (*read)(void), int (*write)(uint8_t *buf, size_t len), uint8_t buffer) { pipe_t pipe; pipe_serial_t to; // just sanity checks if(!net || !name || !read || !write) return NULL; pipe = xht_get(net->pipes, name); if(!pipe) { if(!(pipe = pipe_new("serial"))) return NULL; if(!(pipe->arg = to = malloc(sizeof (struct pipe_serial_struct)))) return pipe_free(pipe); memset(to,0,sizeof (struct pipe_serial_struct)); to->net = net; if(!(to->chunks = util_chunks_new(buffer))) { free(to); return pipe_free(pipe); } // set up pipe pipe->id = strdup(name); xht_set(net->pipes,pipe->id,pipe); pipe->send = serial_send; }else{ if(!(to = (pipe_serial_t)pipe->arg)) return NULL; } // these can be modified to->read = read; to->write = write; return pipe; }
net_serial_t net_serial_send(net_serial_t net, const char *name, lob_t packet) { if(!net || !name || !packet) return NULL; serial_send(xht_get(net->pipes, name), packet, NULL); return net; }
thtp_t thtp_get(switch_t s) { thtp_t t; t = xht_get(s->index,"thtp"); return t ? t : thtp_new(s,NULL); }
void ext_thtp(chan_t c) { lob_t p, buf, req, match, note; char *path; thtp_t t = thtp_get(c->s); // incoming note as an answer if((note = chan_notes(c))) { DEBUG_PRINTF("got note resp %.*s",note->json_len,note->json); thtp_send(c,lob_linked(note)); lob_free(note); return; } while((p = chan_pop(c))) { if(!c->arg) { c->arg = buf = p; }else{ buf = c->arg; lob_append(buf,p->body,p->body_len); lob_free(p); } // for now we're processing whole-requests-at-once, to do streaming we can try parsing note->body for the headers anytime if(c->ended) continue; // parse the payload p = lob_parse(buf->body,buf->body_len); // this is a response, send it if((note = lob_unlink(buf))) { lob_free(buf); if(p) { DEBUG_PRINTF("got response %.*s for %.*s",p->json_len,p->json,note->json_len,note->json); } lob_link(note,p); lob_set_str(note,"thtp","resp"); chan_reply(c,note); chan_end(c,NULL); return; } // this is an incoming request lob_free(buf); if(!p) return (void)chan_fail(c,"422"); req = p; DEBUG_PRINTF("thtp req packet %.*s", req->json_len, req->json); path = lob_get_str(req,"path"); match = xht_get(t->index,path); if(!match) match = _thtp_glob(t,path); if(!match) { chan_fail(c,"404"); lob_free(req); return; } // built in response if(lob_linked(match)) { thtp_send(c,lob_linked(match)); lob_free(req); return; } // attach and route request to a new note note = lob_copy(match); lob_link(note,req); lob_set_str(note,"thtp","req"); if(chan_reply(c,note) == 0) return; chan_fail(c,"500"); lob_free(req); } // optionally sends ack if needed chan_ack(c); }