// 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; }
/* * This is a tee(1) implementation that works on pipes. It doesn't copy * any data, it simply references the 'in' pages on the 'out' pipe. * The 'flags' used are the SPLICE_F_* variants, currently the only * applicable one is SPLICE_F_NONBLOCK. */ static long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags) { struct pipe_inode_info *ipipe = pipe_info(in->f_dentry->d_inode); struct pipe_inode_info *opipe = pipe_info(out->f_dentry->d_inode); int ret = -EINVAL; /* * Duplicate the contents of ipipe to opipe without actually * copying the data. */ if (ipipe && opipe && ipipe != opipe) { /* * Keep going, unless we encounter an error. The ipipe/opipe * ordering doesn't really matter. */ ret = link_ipipe_prep(ipipe, flags); if (!ret) { ret = link_opipe_prep(opipe, flags); if (!ret) { ret = link_pipe(ipipe, opipe, len, flags); if (!ret && (flags & SPLICE_F_NONBLOCK)) ret = -EAGAIN; } } } return ret; }
link_t mesh_add(mesh_t mesh, lob_t json, pipe_t pipe) { link_t link; lob_t keys, paths; uint8_t csid; if(!mesh || !json) return LOG("bad args"); LOG("mesh add %s",lob_json(json)); link = link_get(mesh, hashname_vchar(lob_get(json,"hashname"))); keys = lob_get_json(json,"keys"); paths = lob_get_array(json,"paths"); if(!link) link = link_keys(mesh, keys); if(!link) LOG("no hashname"); LOG("loading keys/paths"); if(keys && (csid = hashname_id(mesh->keys,keys))) link_load(link, csid, keys); // handle any pipe/paths if(pipe) link_pipe(link, pipe); lob_t path; for(path=paths;path;path = lob_next(path)) link_path(link,path); lob_free(keys); lob_freeall(paths); return link; }
// try to turn a path into a pipe pipe_t link_path(link_t link, lob_t path) { pipe_t pipe; if(!link || !path) return LOG("bad args"); if(!(pipe = mesh_path(link->mesh, link, path))) return NULL; link_pipe(link, pipe); return pipe; }
int main(int argc, char **argv) { mesh_t meshA = mesh_new(3); fail_unless(meshA); lob_t secretsA = mesh_generate(meshA); fail_unless(secretsA); mesh_t meshB = mesh_new(3); fail_unless(meshB); lob_t secretsB = mesh_generate(meshB); fail_unless(secretsB); net_serial_t netA = net_serial_new(meshA, NULL); fail_unless(netA); pipe_t pAB = net_serial_add(netA, "sAB", readerA, writerA, 64); fail_unless(pAB); net_serial_t netB = net_serial_new(meshB, NULL); fail_unless(netB); pipe_t pBA = net_serial_add(netB, "sBA", readerB, writerB, 64); fail_unless(pBA); link_t linkAB = link_pipe(link_keys(meshA, meshB->keys), pAB); link_t linkBA = link_pipe(link_keys(meshB, meshA->keys), pBA); fail_unless(linkAB); fail_unless(linkBA); link_sync(linkAB); // let serial go go go int loop; for(loop = 2000; loop; loop--) { net_serial_loop(netB); net_serial_loop(netA); } LOG("BA %d AB %d",e3x_exchange_out(linkBA->x,0),e3x_exchange_out(linkAB->x,0)); fail_unless(e3x_exchange_out(linkBA->x,0) >= e3x_exchange_out(linkAB->x,0)); fail_unless(e3x_exchange_out(linkBA->x,0) == e3x_exchange_out(linkAB->x,0)); return 0; }
pipe_t pipe_sync(pipe_t p, uint8_t down) { if(!p) return NULL; p->down = down; lob_t list, next; for(list=p->links;list;list = next) { next = lob_next(list); link_t link = list->arg; link_pipe(link, p); // will remove pipe if it's down } return p; }
net_loopback_t net_loopback_new(mesh_t a, mesh_t b) { net_loopback_t pair; if(!(pair = malloc(sizeof (struct net_loopback_struct)))) return LOG("OOM"); memset(pair,0,sizeof (struct net_loopback_struct)); if(!(pair->pipe = pipe_new("pair"))) { free(pair); return LOG("OOM"); } pair->a = a; pair->b = b; pair->pipe->id = strdup("loopback"); pair->pipe->arg = pair; pair->pipe->send = pair_send; // ensure they're linked and piped together link_pipe(link_keys(a,b->keys),pair->pipe); link_pipe(link_keys(b,a->keys),pair->pipe); return pair; }
// process an incoming handshake link_t link_receive_handshake(link_t link, lob_t inner, pipe_t pipe) { link_t ready; uint32_t out, err; seen_t seen; uint8_t csid = 0; char *hexid; lob_t attached, outer = lob_linked(inner); if(!link || !inner || !outer) return LOG("bad args"); hexid = lob_get(inner, "csid"); if(!lob_get(link->mesh->keys, hexid)) return LOG("unsupported csid %s",hexid); util_unhex(hexid, 2, &csid); attached = lob_parse(inner->body, inner->body_len); if(!link->key && link_key(link->mesh, attached, csid) != link) return LOG("invalid/mismatch link handshake"); if((err = e3x_exchange_verify(link->x,outer))) return LOG("handshake verification fail: %d",err); out = e3x_exchange_out(link->x,0); ready = link_up(link); // if bad at, always send current handshake if(e3x_exchange_in(link->x, lob_get_uint(inner,"at")) < out) { LOG("old/bad at: %s (%d,%d,%d)",lob_json(inner),lob_get_int(inner,"at"),e3x_exchange_in(link->x,0),e3x_exchange_out(link->x,0)); // just reset pipe seen and call link_sync to resend handshake for(seen = link->pipes;pipe && seen;seen = seen->next) if(seen->pipe == pipe) seen->at = 0; lob_free(link_sync(link)); return NULL; } // trust/add this pipe if(pipe) link_pipe(link,pipe); // try to sync ephemeral key if(!e3x_exchange_sync(link->x,outer)) return LOG("sync failed"); // we may need to re-sync if(out != e3x_exchange_out(link->x,0)) lob_free(link_sync(link)); // notify of ready state change if(!ready && link_up(link)) { LOG("link ready"); mesh_link(link->mesh, link); } return link; }
void proxy_attach(ape_proxy *proxy, char *pipe, int allow_write, acetables *g_ape) { ape_proxy_pipe *to; transpipe *gpipe; if (proxy == NULL || ((gpipe = get_pipe(pipe, g_ape)) == NULL)) { return; } to = xmalloc(sizeof(*to)); memcpy(to->pipe, gpipe->pubid, strlen(gpipe->pubid)+1); to->allow_write = allow_write; to->next = proxy->to; proxy->to = to; proxy->nlink++; link_pipe(gpipe, proxy->pipe, proxy_detach); }
static void link_exec_set_io_thread (gpointer data, gboolean immediate) { GError *error = NULL; gboolean to_io_thread = TRUE; if (link_is_io_in_thread) return; link_lock (); g_mutex_lock (link_cmd_queue_lock); link_is_io_in_thread = TRUE; link_thread_context = g_main_context_new (); link_thread_loop = g_main_loop_new (link_thread_context, TRUE); link_connections_move_io_T (to_io_thread); link_servers_move_io_T (to_io_thread); if (link_pipe (link_wakeup_fds) < 0) g_error ("Can't create CORBA main-thread wakeup pipe"); link_main_source = link_source_create_watch (link_thread_context, LINK_WAKEUP_POLL, NULL, (G_IO_IN | G_IO_PRI), link_mainloop_handle_input, NULL); link_io_thread = g_thread_create_full (link_io_thread_fn, NULL, 256 * 1024, TRUE, FALSE, G_THREAD_PRIORITY_NORMAL, &error); if (!link_io_thread || error) g_error ("Failed to create linc worker thread"); g_main_loop_quit (link_loop); g_mutex_unlock (link_cmd_queue_lock); link_unlock (); }
// process an incoming handshake link_t link_handshake(link_t link, lob_t inner, lob_t outer, pipe_t pipe) { link_t ready; uint32_t out; if(!link || !inner || !outer) return LOG("bad args"); if(!link->key && link_key(link->mesh,inner) != link) return LOG("invalid/mismatch handshake key"); out = exchange3_out(link->x,0); ready = link_ready(link); // if bad at, always send current handshake if(exchange3_in(link->x, lob_get_int(inner,"at")) < out) { LOG("old/bad at: %s (%d,%d,%d)",lob_json(inner),lob_get_int(inner,"at"),exchange3_in(link->x,0),exchange3_out(link->x,0)); if(pipe) pipe->send(pipe,exchange3_handshake(link->x),link); return NULL; } // trust/add this pipe if(pipe) link_pipe(link,pipe); // try to sync ephemeral key if(!exchange3_sync(link->x,outer)) return LOG("sync failed"); // we may need to re-sync if(out != exchange3_out(link->x,0)) link_sync(link); // notify of ready state change if(!ready && link_ready(link)) { LOG("link ready"); mesh_link(link->mesh, link); } return link; }