static int ssh2_needs_bytes_as_libssh2_is_impatient(eventer_t e, int mask, void *closure, struct timeval *now) { ssh2_check_info_t *ci = closure; eventer_t asynch_e; if(mask & EVENTER_EXCEPTION) { noit_check_t *check = ci->check; ci->timed_out = 0; ci->error = strdup("ssh connection failed"); ssh2_log_results(ci->self, ci->check); ssh2_cleanup(ci->self, ci->check); eventer_remove_fd(e->fd); e->opset->close(e->fd, &mask, e); check->flags &= ~NP_RUNNING; return 0; } /* We steal the timeout_event as it has the exact timeout we want. */ assert(ci->timeout_event); asynch_e = eventer_remove(ci->timeout_event); assert(asynch_e); ci->timeout_event = NULL; ci->synch_fd_event = NULL; asynch_e->fd = e->fd; asynch_e->callback = ssh2_drive_session; asynch_e->closure = closure; asynch_e->mask = EVENTER_ASYNCH; eventer_add(asynch_e); eventer_remove_fd(e->fd); return 0; }
int noit_http_rest_raw_handler(eventer_t e, int mask, void *closure, struct timeval *now) { int newmask = EVENTER_READ | EVENTER_EXCEPTION, rv, done = 0; acceptor_closure_t *ac = closure; noit_http_rest_closure_t *restc = ac->service_ctx; if(mask & EVENTER_EXCEPTION || (restc && restc->wants_shutdown)) { /* Exceptions cause us to simply snip the connection */ eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); acceptor_closure_free(ac); return 0; } if(!ac->service_ctx) { ac->service_ctx = restc = noit_http_rest_closure_alloc(); ac->service_ctx_free = noit_http_rest_closure_free; restc->ac = ac; restc->http_ctx = noit_http_session_ctx_new(noit_rest_request_dispatcher, restc, e, ac); } rv = noit_http_session_drive(e, mask, restc->http_ctx, now, &done); if(done) { acceptor_closure_free(ac); } return rv; }
int noit_control_dispatch(eventer_t e, int mask, void *closure, struct timeval *now) { u_int32_t cmd; int len = 0, callmask = mask; void *vdelegation_table; noit_hash_table *delegation_table = NULL; acceptor_closure_t *ac = closure; assert(ac->rlen >= 0); while(len >= 0 && ac->rlen < sizeof(cmd)) { len = e->opset->read(e->fd, ((char *)&cmd) + ac->rlen, sizeof(cmd) - ac->rlen, &mask, e); if(len == -1 && errno == EAGAIN) return EVENTER_READ | EVENTER_EXCEPTION; if(len > 0) ac->rlen += len; } assert(ac->rlen >= 0 && ac->rlen <= sizeof(cmd)); if(callmask & EVENTER_EXCEPTION || ac->rlen != sizeof(cmd)) { int newmask; socket_error: /* Exceptions cause us to simply snip the connection */ eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); acceptor_closure_free(ac); return 0; } ac->cmd = ntohl(cmd); /* Lookup cmd and dispatch */ if(noit_hash_retrieve(&listener_commands, (char *)&ac->dispatch, sizeof(ac->dispatch), (void **)&vdelegation_table)) { void *vfunc; delegation_table = (noit_hash_table *)vdelegation_table; if(noit_hash_retrieve(delegation_table, (char *)&ac->cmd, sizeof(ac->cmd), &vfunc)) { e->callback = *((eventer_func_t *)vfunc); return e->callback(e, callmask, closure, now); } else { const char *event_name; noitL(noit_error, "listener (%s %p) has no command: 0x%08x\n", (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???", delegation_table, cmd); } } else { const char *event_name; noitL(noit_error, "No delegation table for listener (%s %p)\n", (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???", delegation_table); } goto socket_error; }
int noit_http_rest_handler(eventer_t e, int mask, void *closure, struct timeval *now) { int newmask = EVENTER_READ | EVENTER_EXCEPTION, rv, done = 0; acceptor_closure_t *ac = closure; noit_http_rest_closure_t *restc = ac->service_ctx; if(mask & EVENTER_EXCEPTION || (restc && restc->wants_shutdown)) { socket_error: /* Exceptions cause us to simply snip the connection */ eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); acceptor_closure_free(ac); return 0; } if(!ac->service_ctx) { const char *primer = ""; ac->service_ctx = restc = noit_http_rest_closure_alloc(); ac->service_ctx_free = noit_http_rest_closure_free; restc->ac = ac; restc->remote_cn = strdup(ac->remote_cn ? ac->remote_cn : ""); restc->http_ctx = noit_http_session_ctx_new(noit_rest_request_dispatcher, restc, e, ac); switch(ac->cmd) { case NOIT_CONTROL_DELETE: primer = "DELE"; break; case NOIT_CONTROL_GET: primer = "GET "; break; case NOIT_CONTROL_HEAD: primer = "HEAD"; break; case NOIT_CONTROL_POST: primer = "POST"; break; case NOIT_CONTROL_PUT: primer = "PUT "; break; case NOIT_CONTROL_MERGE: primer = "MERG"; break; default: goto socket_error; } noit_http_session_prime_input(restc->http_ctx, primer, 4); } rv = noit_http_session_drive(e, mask, restc->http_ctx, now, &done); if(done) { acceptor_closure_free(ac); } return rv; }
static void dns_ctx_handle_free(void *vh) { dns_ctx_handle_t *h = vh; free(h->ns); eventer_remove_fd(h->e->fd); eventer_free(h->e); h->e = NULL; if(h->timeout) { eventer_remove(h->timeout); eventer_free(h->timeout); h->timeout = NULL; } dns_close(h->ctx); dns_free(h->ctx); assert(h->timeout == NULL); free(h); }
static int noit_snmp_session_cleanse(struct target_session *ts) { if(ts->refcnt == 0 && ts->sess_handle) { eventer_remove_fd(ts->fd); ts->fd = -1; if(ts->timeoutevent) { eventer_remove(ts->timeoutevent); ts->timeoutevent = NULL; } snmp_sess_close(ts->sess_handle); ts->sess_handle = NULL; if(!ts->in_table) { free(ts); } return 1; } return 0; }
static int noit_listener_accept_ssl(eventer_t e, int mask, void *closure, struct timeval *tv) { int rv; listener_closure_t listener_closure = (listener_closure_t)closure; acceptor_closure_t *ac = NULL; if(!closure) goto socketfail; ac = listener_closure->dispatch_closure; rv = eventer_SSL_accept(e, &mask); if(rv > 0) { eventer_ssl_ctx_t *sslctx; e->callback = listener_closure->dispatch_callback; /* We must make a copy of the acceptor_closure_t for each new * connection. */ if((sslctx = eventer_get_eventer_ssl_ctx(e)) != NULL) { const char *cn, *end; cn = eventer_ssl_get_peer_subject(sslctx); if(cn && (cn = strstr(cn, "CN=")) != NULL) { cn += 3; end = cn; while(*end && *end != '/') end++; ac->remote_cn = malloc(end - cn + 1); memcpy(ac->remote_cn, cn, end - cn); ac->remote_cn[end-cn] = '\0'; } } e->closure = ac; noitL(nldeb, "noit_listener[%s] SSL_accept on fd %d [%s]\n", eventer_name_for_callback_e(e->callback, e), e->fd, ac->remote_cn ? ac->remote_cn : "anonymous"); if(listener_closure) free(listener_closure); return e->callback(e, mask, e->closure, tv); } if(errno == EAGAIN) return mask|EVENTER_EXCEPTION; socketfail: if(listener_closure) free(listener_closure); if(ac) acceptor_closure_free(ac); eventer_remove_fd(e->fd); e->opset->close(e->fd, &mask, e); return 0; }
static int ssh2_connect_timeout(eventer_t e, int mask, void *closure, struct timeval *now) { eventer_t fde; ssh2_check_info_t *ci = closure; noit_check_t *check = ci->check; ci->timeout_event = NULL; /* This is us, return 0 will free this */ ci->error = strdup("ssh connect timeout"); if(ci->synch_fd_event) { fde = ci->synch_fd_event; eventer_remove_fd(fde->fd); fde->opset->close(fde->fd, &mask, fde); eventer_free(fde); ci->synch_fd_event = NULL; } ssh2_log_results(ci->self, ci->check); ssh2_cleanup(ci->self, ci->check); check->flags &= ~NP_RUNNING; return 0; }
static int ssh2_connect_complete(eventer_t e, int mask, void *closure, struct timeval *now) { ssh2_check_info_t *ci = closure; if(mask & EVENTER_EXCEPTION) { noit_check_t *check = ci->check; ci->timed_out = 0; ci->error = strdup("ssh connection failed"); ssh2_log_results(ci->self, ci->check); ssh2_cleanup(ci->self, ci->check); eventer_remove_fd(e->fd); e->opset->close(e->fd, &mask, e); check->flags &= ~NP_RUNNING; return 0; } ci->available = 1; e->callback = ssh2_needs_bytes_as_libssh2_is_impatient; e->mask = EVENTER_READ | EVENTER_EXCEPTION; return e->mask; }
int mtev_capabilities_handler(eventer_t e, int mask, void *closure, struct timeval *now) { int newmask = EVENTER_WRITE | EVENTER_EXCEPTION; acceptor_closure_t *ac = closure; mtev_capsvc_closure_t *cl = ac->service_ctx; if(mask & EVENTER_EXCEPTION) { socket_error: /* Exceptions cause us to simply snip the connection */ cleanup_shutdown: eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); if(cl) { if(cl->buff) free(cl->buff); free(cl); } acceptor_closure_free(ac); return 0; } if(!ac->service_ctx) { cl = ac->service_ctx = calloc(1, sizeof(*cl)); mtev_capabilities_tobuff(cl, ac->dispatch); } while(cl->towrite > cl->written) { int len; while((len = e->opset->write(e->fd, cl->buff + cl->written, cl->towrite - cl->written, &newmask, e)) == -1 && errno == EINTR); if(len < 0) { if(errno == EAGAIN) return newmask | EVENTER_EXCEPTION; goto socket_error; } cl->written += len; } goto cleanup_shutdown; }
int stratcon_realtime_recv_handler(eventer_t e, int mask, void *closure, struct timeval *now) { static u_int32_t livestream_cmd = 0; noit_connection_ctx_t *nctx = closure; realtime_recv_ctx_t *ctx = nctx->consumer_ctx; int len; u_int32_t nint; char uuid_str[37]; if(!livestream_cmd) livestream_cmd = htonl(NOIT_LIVESTREAM_DATA_FEED); if(mask & EVENTER_EXCEPTION || nctx->wants_shutdown) { socket_error: ctx->state = REALTIME_HTTP_WANT_INITIATE; ctx->count = 0; ctx->bytes_read = 0; ctx->bytes_written = 0; ctx->bytes_expected = 0; if(ctx->buffer) free(ctx->buffer); ctx->buffer = NULL; /* We close the event here and null it in the context * because the noit_connection_ctx_dealloc() will both close * it and free it (which our caller will double free) and * we consider double frees to be harmful. */ eventer_remove_fd(e->fd); e->opset->close(e->fd, &mask, e); nctx->e = NULL; noit_connection_ctx_dealloc(nctx); return 0; } #define full_nb_write(data, wlen) do { \ if(!ctx->bytes_expected) { \ ctx->bytes_written = 0; \ ctx->bytes_expected = wlen; \ } \ while(ctx->bytes_written < ctx->bytes_expected) { \ while(-1 == (len = e->opset->write(e->fd, ((char *)data) + ctx->bytes_written, \ ctx->bytes_expected - ctx->bytes_written, \ &mask, e)) && errno == EINTR); \ if(len < 0) { \ if(errno == EAGAIN) return mask | EVENTER_EXCEPTION; \ goto socket_error; \ } \ ctx->bytes_written += len; \ } \ if(ctx->bytes_written != ctx->bytes_expected) { \ noitL(noit_error, "short write on initiating stream [%d != %d].\n", \ ctx->bytes_written, ctx->bytes_expected); \ goto socket_error; \ } \ ctx->bytes_expected = 0; \ } while(0) noit_connection_update_timeout(nctx); while(1) { u_int32_t net_body_len; switch(ctx->state) { case REALTIME_HTTP_WANT_INITIATE: full_nb_write(&livestream_cmd, sizeof(livestream_cmd)); ctx->state = REALTIME_HTTP_WANT_SEND_INTERVAL; /* FALLTHROUGH */ case REALTIME_HTTP_WANT_SEND_INTERVAL: nint = htonl(ctx->rt->interval); full_nb_write(&nint, sizeof(nint)); ctx->state = REALTIME_HTTP_WANT_SEND_UUID; /* FALLTHROUGH */ case REALTIME_HTTP_WANT_SEND_UUID: uuid_unparse_lower(ctx->rt->checkid, uuid_str); full_nb_write(uuid_str, 36); ctx->state = REALTIME_HTTP_WANT_HEADER; /* FALLTHROUGH */ case REALTIME_HTTP_WANT_HEADER: FULLREAD(e, ctx, sizeof(u_int32_t)); memcpy(&net_body_len, ctx->buffer, sizeof(u_int32_t)); ctx->body_len = ntohl(net_body_len); free(ctx->buffer); ctx->buffer = NULL; ctx->state = REALTIME_HTTP_WANT_BODY; break; case REALTIME_HTTP_WANT_BODY: FULLREAD(e, ctx, ctx->body_len); if(stratcon_line_to_javascript(ctx->ctx, ctx->buffer, &ctx->hack_inc_id)) goto socket_error; free(ctx->buffer); ctx->buffer = NULL; ctx->state = REALTIME_HTTP_WANT_HEADER; break; } } }
int noit_console_handler(eventer_t e, int mask, void *closure, struct timeval *now) { int newmask = EVENTER_READ | EVENTER_EXCEPTION; int keep_going; acceptor_closure_t *ac = closure; noit_console_closure_t ncct = ac->service_ctx; if(mask & EVENTER_EXCEPTION || (ncct && ncct->wants_shutdown)) { socket_error: /* Exceptions cause us to simply snip the connection */ /* This removes the log feed which is important to do before calling close */ eventer_remove_fd(e->fd); if(ncct) noit_console_closure_free(ncct); if(ac) acceptor_closure_free(ac); e->opset->close(e->fd, &newmask, e); return 0; } if(!ac->service_ctx) { ncct = ac->service_ctx = noit_console_closure_alloc(); } if(!ncct->initialized) { ncct->e = e; if(allocate_pty(&ncct->pty_master, &ncct->pty_slave)) { nc_printf(ncct, "Failed to open pty: %s\n", strerror(errno)); ncct->wants_shutdown = 1; goto socket_error; } else { int i; const char *line_protocol; HistEvent ev; ncct->hist = history_init(); history(ncct->hist, &ev, H_SETSIZE, 500); ncct->el = el_init("noitd", ncct->pty_master, NULL, e->fd, e, e->fd, e); if(!ncct->el) goto socket_error; if(el_set(ncct->el, EL_USERDATA, ncct)) { noitL(noit_error, "Cannot set userdata on noitedit session\n"); goto socket_error; } if(el_set(ncct->el, EL_EDITOR, "emacs")) noitL(noit_error, "Cannot set emacs mode on console\n"); if(el_set(ncct->el, EL_HIST, history, ncct->hist)) noitL(noit_error, "Cannot set history on console\n"); el_set(ncct->el, EL_ADDFN, "noit_complete", "auto completion functions for noit", noit_edit_complete); el_set(ncct->el, EL_BIND, "^I", "noit_complete", NULL); for(i=EL_NUM_FCNS; i < ncct->el->el_map.nfunc; i++) { if(ncct->el->el_map.func[i] == noit_edit_complete) { ncct->noit_edit_complete_cmdnum = i; break; } } if(!noit_hash_retr_str(ac->config, "line_protocol", strlen("line_protocol"), &line_protocol)) { line_protocol = NULL; } if(line_protocol && !strcasecmp(line_protocol, "telnet")) { ncct->telnet = noit_console_telnet_alloc(ncct); ncct->output_cooker = nc_telnet_cooker; } noit_console_state_init(ncct); } snprintf(ncct->feed_path, sizeof(ncct->feed_path), "console/%d", e->fd); noit_log_stream_new(ncct->feed_path, "noit_console", ncct->feed_path, ncct, NULL); noit_console_motd(e, ac, ncct); ncct->initialized = 1; } /* If we still have data to send back to the client, this will take * care of that */ if(noit_console_continue_sending(ncct, &newmask) < 0) { if(ncct->wants_shutdown || errno != EAGAIN) goto socket_error; return newmask | EVENTER_EXCEPTION; } for(keep_going=1 ; keep_going ; ) { int len, plen; char sbuf[4096]; const char *buffer; keep_going = 0; buffer = el_gets(ncct->el, &plen); if(!el_eagain(ncct->el)) { if(!buffer) { buffer = "exit"; plen = 4; nc_write(ncct, "\n", 1); } keep_going++; } len = e->opset->read(e->fd, sbuf, sizeof(sbuf)-1, &newmask, e); if(len == 0 || (len < 0 && errno != EAGAIN)) { eventer_remove_fd(e->fd); if(ncct) noit_console_closure_free(ncct); if(ac) acceptor_closure_free(ac); e->opset->close(e->fd, &newmask, e); return 0; } if(len > 0) { keep_going++; sbuf[len] = '\0'; if(ncct->telnet) { noit_console_telnet_telrcv(ncct, sbuf, len); ptyflush(ncct); } else { int written; written = write(ncct->pty_slave, sbuf, len); if(written <= 0) goto socket_error; assert(written == len); } } if(buffer) { char *cmd_buffer; cmd_buffer = malloc(plen+1); memcpy(cmd_buffer, buffer, plen); /* chomp */ cmd_buffer[plen] = '\0'; if(cmd_buffer[plen-1] == '\n') cmd_buffer[plen-1] = '\0'; noitL(noit_debug, "IN[%d]: '%s'\n", plen, cmd_buffer); noit_console_dispatch(e, cmd_buffer, ncct); free(cmd_buffer); } if(noit_console_continue_sending(ncct, &newmask) == -1) { if(ncct->wants_shutdown || errno != EAGAIN) goto socket_error; return newmask | EVENTER_EXCEPTION; } if(ncct->wants_shutdown) goto socket_error; } return newmask | EVENTER_EXCEPTION; }
int noit_jlog_handler(eventer_t e, int mask, void *closure, struct timeval *now) { eventer_t newe; pthread_t tid; pthread_attr_t tattr; int newmask = EVENTER_READ | EVENTER_EXCEPTION; acceptor_closure_t *ac = closure; noit_jlog_closure_t *jcl = ac->service_ctx; char errbuff[256]; const char *errstr = "unknown error"; if(mask & EVENTER_EXCEPTION || (jcl && jcl->wants_shutdown)) { int len, nlen; socket_error: /* Exceptions cause us to simply snip the connection */ len = strlen(errstr); nlen = htonl(0 - len); e->opset->write(e->fd, &nlen, sizeof(nlen), &newmask, e); e->opset->write(e->fd, errstr, strlen(errstr), &newmask, e); eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); if(jcl) noit_jlog_closure_free(jcl); acceptor_closure_free(ac); return 0; } if(!ac->service_ctx) { noit_log_stream_t ls; const char *logname, *type; int first_attempt = 1; char path[PATH_MAX], subscriber[256], *sub; jcl = ac->service_ctx = noit_jlog_closure_alloc(); if(!noit_hash_retr_str(ac->config, "log_transit_feed_name", strlen("log_transit_feed_name"), &logname)) { errstr = "No 'log_transit_feed_name' specified in log_transit."; noitL(noit_error, "%s\n", errstr); goto socket_error; } ls = noit_log_stream_find(logname); if(!ls) { snprintf(errbuff, sizeof(errbuff), "Could not find log '%s' for log_transit.", logname); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } type = noit_log_stream_get_type(ls); if(!type || strcmp(type, "jlog")) { snprintf(errbuff, sizeof(errbuff), "Log '%s' for log_transit is not a jlog.", logname); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } if(ac->cmd == NOIT_JLOG_DATA_FEED) { if(!ac->remote_cn) { errstr = "jlog transit started to unidentified party."; noitL(noit_error, "%s\n", errstr); goto socket_error; } strlcpy(subscriber, ac->remote_cn, sizeof(subscriber)); jcl->feed_stats = noit_jlog_feed_stats(subscriber); } else { jcl->feed_stats = noit_jlog_feed_stats("~"); snprintf(subscriber, sizeof(subscriber), "~%07d", noit_atomic_inc32(&tmpfeedcounter)); } jcl->subscriber = strdup(subscriber); strlcpy(path, noit_log_stream_get_path(ls), sizeof(path)); sub = strchr(path, '('); if(sub) { char *esub = strchr(sub, ')'); if(esub) { *esub = '\0'; *sub++ = '\0'; } } jcl->jlog = jlog_new(path); if(ac->cmd == NOIT_JLOG_DATA_TEMP_FEED) { add_sub: if(jlog_ctx_add_subscriber(jcl->jlog, jcl->subscriber, JLOG_END) == -1) { snprintf(errbuff, sizeof(errbuff), "jlog reader[%s] error: %s", jcl->subscriber, jlog_ctx_err_string(jcl->jlog)); errstr = errbuff; noitL(noit_error, "%s\n", errstr); } } if(jlog_ctx_open_reader(jcl->jlog, jcl->subscriber) == -1) { if(sub && !strcmp(sub, "*")) { if(first_attempt) { jlog_ctx_close(jcl->jlog); jcl->jlog = jlog_new(path); first_attempt = 0; goto add_sub; } } snprintf(errbuff, sizeof(errbuff), "jlog reader[%s] error: %s", jcl->subscriber, jlog_ctx_err_string(jcl->jlog)); errstr = errbuff; noitL(noit_error, "%s\n", errstr); goto socket_error; } } /* The jlog stuff is disk I/O and can block us. * We'll create a new thread to just handle this connection. */ eventer_remove_fd(e->fd); newe = eventer_alloc(); memcpy(newe, e, sizeof(*e)); pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); gettimeofday(&jcl->feed_stats->last_connection, NULL); noit_atomic_inc32(&jcl->feed_stats->connections); if(pthread_create(&tid, &tattr, noit_jlog_thread_main, newe) == 0) { return 0; } /* Undo our dup */ eventer_free(newe); /* Creating the thread failed, close it down and deschedule. */ e->opset->close(e->fd, &newmask, e); return 0; }
int noit_capabilities_handler(eventer_t e, int mask, void *closure, struct timeval *now) { int newmask = EVENTER_WRITE | EVENTER_EXCEPTION; acceptor_closure_t *ac = closure; noit_capsvc_closure_t *cl = ac->service_ctx; if(mask & EVENTER_EXCEPTION) { socket_error: /* Exceptions cause us to simply snip the connection */ cleanup_shutdown: eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); if(cl) { if(cl->buff) free(cl->buff); free(cl); } if(ac) acceptor_closure_free(ac); return 0; } if(!ac->service_ctx) { char vbuff[128]; noit_hash_table *lc; noit_hash_iter iter = NOIT_HASH_ITER_ZERO; const char *k; int klen; void *data; xmlDocPtr xmldoc; xmlNodePtr root, cmds; cl = ac->service_ctx = calloc(1, sizeof(*cl)); /* fill out capabilities */ noit_build_version(vbuff, sizeof(vbuff)); /* Create an XML Document */ xmldoc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(xmldoc, NULL, (xmlChar *)"noit_capabilities", NULL); xmlDocSetRootElement(xmldoc, root); /* Fill in the document */ xmlNewTextChild(root, NULL, (xmlChar *)"version", (xmlChar *)vbuff); cmds = xmlNewNode(NULL, (xmlChar *)"services"); xmlAddChild(root, cmds); lc = noit_listener_commands(); while(noit_hash_next(lc, &iter, &k, &klen, &data)) { xmlNodePtr cnode; char hexcode[11]; const char *name; eventer_func_t *f = (eventer_func_t *)k; noit_hash_table *sc = (noit_hash_table *)data; noit_hash_iter sc_iter = NOIT_HASH_ITER_ZERO; const char *sc_k; int sc_klen; void *sc_data; name = eventer_name_for_callback(*f); cnode = xmlNewNode(NULL, (xmlChar *)"service"); xmlSetProp(cnode, (xmlChar *)"name", name ? (xmlChar *)name : NULL); if(*f == ac->dispatch) xmlSetProp(cnode, (xmlChar *)"connected", (xmlChar *)"true"); xmlAddChild(cmds, cnode); while(noit_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) { xmlNodePtr scnode; char *name_copy, *version = NULL; eventer_func_t *f = (eventer_func_t *)sc_data; snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k)); name = eventer_name_for_callback(*f); name_copy = strdup(name ? name : "[[unknown]]"); version = strchr(name_copy, '/'); if(version) *version++ = '\0'; scnode = xmlNewNode(NULL, (xmlChar *)"command"); xmlSetProp(scnode, (xmlChar *)"name", (xmlChar *)name_copy); if(version) xmlSetProp(scnode, (xmlChar *)"version", (xmlChar *)version); xmlSetProp(scnode, (xmlChar *)"code", (xmlChar *)hexcode); xmlAddChild(cnode, scnode); free(name_copy); } } /* Write it out to a buffer and copy it for writing */ cl->buff = noit_xmlSaveToBuffer(xmldoc); cl->towrite = strlen(cl->buff); /* Clean up after ourselves */ xmlFreeDoc(xmldoc); } while(cl->towrite > cl->written) { int len; while((len = e->opset->write(e->fd, cl->buff + cl->written, cl->towrite - cl->written, &newmask, e)) == -1 && errno == EINTR); if(len < 0) { if(errno == EAGAIN) return newmask | EVENTER_EXCEPTION; goto socket_error; } cl->written += len; } goto cleanup_shutdown; }
int noit_livestream_handler(eventer_t e, int mask, void *closure, struct timeval *now) { eventer_t newe; pthread_t tid; int newmask = EVENTER_READ | EVENTER_EXCEPTION; acceptor_closure_t *ac = closure; noit_livestream_closure_t *jcl = ac->service_ctx; if(mask & EVENTER_EXCEPTION || (jcl && jcl->wants_shutdown)) { socket_error: /* Exceptions cause us to simply snip the connection */ eventer_remove_fd(e->fd); e->opset->close(e->fd, &newmask, e); if(jcl) noit_livestream_closure_free(jcl); if(ac) acceptor_closure_free(ac); return 0; } if(!ac->service_ctx || !jcl->feed) { int len; jcl = ac->service_ctx = noit_livestream_closure_alloc(); /* Setup logger to this channel */ if(!jcl->period) { u_int32_t nperiod; len = e->opset->read(e->fd, &nperiod, sizeof(nperiod), &mask, e); if(len == -1 && errno == EAGAIN) return mask | EVENTER_EXCEPTION; if(len != sizeof(nperiod)) goto socket_error; jcl->period = ntohl(nperiod); if(!jcl->period) { noitL(noit_error, "period of 0 specified in livestream. not allowed.\n"); goto socket_error; } } while(jcl->uuid_read < 36) { len = e->opset->read(e->fd, jcl->uuid_str + jcl->uuid_read, 36 - jcl->uuid_read, &mask, e); if(len == -1 && errno == EAGAIN) return mask | EVENTER_EXCEPTION; if(len == 0) goto socket_error; jcl->uuid_read += len; } jcl->uuid_str[36] = '\0'; if(uuid_parse(jcl->uuid_str, jcl->uuid)) { noitL(noit_error, "bad uuid received in livestream handler '%s'\n", jcl->uuid_str); goto socket_error; } jcl->feed = malloc(32); snprintf(jcl->feed, 32, "livestream/%d", noit_atomic_inc32(&ls_counter)); noit_log_stream_new(jcl->feed, "noit_livestream", jcl->feed, jcl, NULL); jcl->check = noit_check_watch(jcl->uuid, jcl->period); if(!jcl->check) { e->opset->close(e->fd, &newmask, e); return 0; } /* This check must be watched from the livestream */ noit_check_transient_add_feed(jcl->check, jcl->feed); /* Note the check */ noit_check_log_check(jcl->check); /* kick it off, if it isn't running already */ if(!NOIT_CHECK_LIVE(jcl->check)) noit_check_activate(jcl->check); } eventer_remove_fd(e->fd); newe = eventer_alloc(); memcpy(newe, e, sizeof(*e)); if(pthread_create(&tid, NULL, noit_livestream_thread_main, newe) == 0) { return 0; } noit_check_transient_remove_feed(jcl->check, jcl->feed); noit_livestream_closure_free(jcl); /* Undo our dup */ eventer_free(newe); /* Creating the thread failed, close it down and deschedule. */ e->opset->close(e->fd, &newmask, e); return 0; }
static int ssh2_drive_session(eventer_t e, int mask, void *closure, struct timeval *now) { int i; const char *fingerprint; ssh2_check_info_t *ci = closure; struct timeval diff; int timeout_ms = 10; /* 10ms, gets set below */ if(ci->state == WANT_CLOSE) { noit_check_t *check = ci->check; ssh2_log_results(ci->self, ci->check); ssh2_cleanup(ci->self, ci->check); eventer_remove_fd(e->fd); e->opset->close(e->fd, &mask, e); check->flags &= ~NP_RUNNING; return 0; } switch(mask) { case EVENTER_ASYNCH_WORK: if(eventer_set_fd_blocking(e->fd)) { ci->timed_out = 0; ci->error = strdup("socket error"); return 0; } ci->session = libssh2_session_init(); #define set_method(a,b) do { \ int rv; \ if(ci->methods.a && \ (rv = libssh2_session_method_pref(ci->session, b, ci->methods.a)) != 0) { \ ci->timed_out = 0; \ ci->error = strdup((rv == LIBSSH2_ERROR_METHOD_NOT_SUPPORTED) ? \ #a " method not supported" : "error setting " #a); \ return 0; \ } \ } while(0) set_method(kex, LIBSSH2_METHOD_KEX); set_method(hostkey, LIBSSH2_METHOD_HOSTKEY); set_method(crypt_cs, LIBSSH2_METHOD_CRYPT_CS); set_method(crypt_sc, LIBSSH2_METHOD_CRYPT_SC); set_method(mac_cs, LIBSSH2_METHOD_MAC_CS); set_method(mac_sc, LIBSSH2_METHOD_MAC_SC); set_method(comp_cs, LIBSSH2_METHOD_COMP_CS); set_method(comp_sc, LIBSSH2_METHOD_COMP_SC); if(compare_timeval(*now, e->whence) < 0) { sub_timeval(e->whence, *now, &diff); timeout_ms = diff.tv_sec * 1000 + diff.tv_usec / 1000; } #if LIBSSH2_VERSION_NUM >= 0x010209 libssh2_session_set_timeout(ci->session, timeout_ms); #endif if (libssh2_session_startup(ci->session, e->fd)) { ci->timed_out = 0; ci->error = strdup("ssh session startup failed"); return 0; } fingerprint = libssh2_hostkey_hash(ci->session, LIBSSH2_HOSTKEY_HASH_MD5); for(i=0;i<16;i++) { snprintf(ci->fingerprint + (i*2), 3, "%02x", (unsigned char)fingerprint[i]); } ci->fingerprint[32] = '\0'; ci->timed_out = 0; return 0; break; case EVENTER_ASYNCH_CLEANUP: if(ci->session) { libssh2_session_disconnect(ci->session, "Bye!"); libssh2_session_free(ci->session); ci->session = NULL; } ci->state = WANT_CLOSE; break; default: abort(); } return 0; }