void daemon_t::_grandchild( pipe_t & c_pipe, pipe_t & g_pipe ) { try { c_pipe.writer().close(); _init(); // Initialization finished successfully -- let parent know everything is ok. g_pipe.writer().write( ok ); g_pipe.writer().close(); } catch ( std::exception const & ex ) { g_pipe.writer().write( string_t( ex.what() ) + "\n" ); throw; } catch ( ... ) { g_pipe.writer().write( "Unknown exception occurred\n" ); throw; }; // try _body(); }; // _grandchild
pipe_t pipe_free(pipe_t p) { free(p->type); if(p->id) free(p->id); if(p->path) lob_free(p->path); if(p->notify) LOG("pipe free'd leaking notifications"); if(p->free) p->free(p); free(p); return NULL; }
// safe wrapper around ->send pipe_t pipe_send(pipe_t pipe, lob_t packet, link_t link) { if(!pipe || !packet) return NULL; if(!pipe->send || pipe->down) { LOG("dropping packet to down pipe %s: %s",pipe->id, lob_json(packet)); lob_free(packet); return pipe; } pipe->send(pipe, packet, link); return pipe; }
// encrypt and send this one packet on this pipe link_t link_direct(link_t link, lob_t inner, pipe_t pipe) { if(!link || !inner) return LOG("bad args"); if(!pipe && (!link->pipes || !(pipe = link->pipes->pipe))) return LOG("no network"); // add an outgoing cid if none set if(!lob_get_int(inner,"c")) lob_set_uint(inner,"c",e3x_exchange_cid(link->x, NULL)); pipe->send(pipe, e3x_exchange_send(link->x, inner), link); return link; }
// 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; }
void daemon_t::_child( pipe_t & c_pipe, pipe_t & g_pipe ) { try { int error = -1; c_pipe.reader().close(); g_pipe.reader().close(); // Reopen standard streams. // Associate all the standard streams with `/dev/null'. file_t null( * this ); null.open( "/dev/null", O_RDONLY, 0 ); error = dup2( null.fd(), STDIN_FILENO ); SYSERR( error < 0, "dup2", "Reopening stdin" ); null.close(); null.open( "/dev/null", O_WRONLY, 0 ); error = dup2( null.fd(), STDOUT_FILENO ); SYSERR( error < 0, "dup2", "Reopening stdout" ); error = dup2( null.fd(), STDERR_FILENO ); SYSERR( error < 0, "dup2", "Reopening stderr" ); null.close(); pid_t sid = 0; ESYSCALL( "creating session", "setsid", sid = setsid(), sid > 0, "session " << sid << " created" ); // Ignore unused signals. // We ignore signals in child so in grandchild these signals are fro the very beginning. // If daemon need any of these signals, it will handle them explicitly. thread_t::ignore_signal( SIGHUP ); thread_t::ignore_signal( SIGINT ); thread_t::ignore_signal( SIGQUIT ); thread_t::ignore_signal( SIGUSR1 ); thread_t::ignore_signal( SIGUSR2 ); thread_t::ignore_signal( SIGTERM ); thread_t::ignore_signal( SIGCHLD ); thread_t::ignore_signal( SIGTTIN ); thread_t::ignore_signal( SIGTTOU ); thread_t::ignore_signal( SIGWINCH ); pid_t pid = 0; ESYSCALL( "forking grandchild process", "fork", pid = fork(), pid >= 0, "grandchild process forked " << ( pid == 0 ? "(i am grandchild)" : "(i am child)" ) ); if ( pid == 0 ) { _grandchild( c_pipe, g_pipe ); return; // TODO: or exit? }; // if g_pipe.writer().close(); ESYSCALL( "anti-zombying grandchild", "waitpid", error = waitpid( pid, NULL, WNOHANG ), error != -1, "grandchild anti-zombied" ); // We cannot just close pipe: on the parent end ir will be not clear if everything is ok // or child silently died. So let us write `ok' to the pipe -- parent will know that we // are really ok. c_pipe.writer().write( ok ); } catch ( std::exception const & ex ) { c_pipe.writer().write( string_t( ex.what() ) + "\n" ); } catch ( ... ) { c_pipe.writer().write( "Unknown exception occurred\n" ); }; // try c_pipe.writer().close(); }; // _child