static int run_script_select(FILE **sout, FILE **serr, struct cntr *cntr, int logfunc) { int mfd=-1; fd_set fsr; struct timeval tval; int soutfd=fileno(*sout); int serrfd=fileno(*serr); setlinebuf(*sout); setlinebuf(*serr); set_non_blocking(soutfd); set_non_blocking(serrfd); while(1) { mfd=-1; FD_ZERO(&fsr); if(*sout) add_fd_to_sets(soutfd, &fsr, NULL, NULL, &mfd); if(*serr) add_fd_to_sets(serrfd, &fsr, NULL, NULL, &mfd); tval.tv_sec=1; tval.tv_usec=0; if(select(mfd+1, &fsr, NULL, NULL, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("run_script_select error: %s\n", strerror(errno)); return -1; } } if(FD_ISSET(soutfd, &fsr)) log_script_output(sout, NULL, logfunc); if(FD_ISSET(serrfd, &fsr)) log_script_output(serr, cntr, logfunc); if(!*sout && !*serr && got_sigchld) { //fclose(*sout); *sout=NULL; //fclose(*serr); *serr=NULL; got_sigchld=0; return 0; } } // Never get here. return -1; }
int async_rw(char *rcmd, char **rdst, size_t *rlen, char wcmd, const char *wsrc, size_t *wlen) { int mfd=-1; fd_set fsr; fd_set fsw; fd_set fse; int doread=0; int dowrite=0; struct timeval tval; static int read_blocked_on_write=0; static int write_blocked_on_read=0; //printf("in async_rw\n"); if(doing_estimate) return 0; if(fd<0) { logp("fd not ready in async rw: %d\n", fd); return -1; } if(rdst) doread++; // Given a pointer to allocate and read into. if(*wlen) { // More stuff to append to the write buffer. async_append_all_to_write_buffer(wcmd, wsrc, wlen); } if(writebuflen && !write_blocked_on_read) dowrite++; // The write buffer is not yet empty. if(doread) { if(parse_readbuf(rcmd, rdst, rlen)) { logp("error in parse_readbuf\n"); return -1; } if(*rcmd && *rdst) return 0; if(read_blocked_on_write) doread=0; } if(doread || dowrite) { //printf("async_rw loop read %d write %d wbuflen: %d\n", doread, dowrite, writebuflen); mfd=-1; if(doread) FD_ZERO(&fsr); if(dowrite) FD_ZERO(&fsw); FD_ZERO(&fse); add_fd_to_sets(fd, doread?&fsr:NULL, dowrite?&fsw:NULL, &fse, &mfd); tval.tv_sec=setsec; tval.tv_usec=setusec; if(select(mfd+1, doread?&fsr:NULL, dowrite?&fsw:NULL, &fse, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("select error: %s\n", strerror(errno)); return -1; } } if(!FD_ISSET(fd, &fse) && (!doread || !FD_ISSET(fd, &fsr)) && (!dowrite || !FD_ISSET(fd, &fsw))) { //logp("SELECT HIT TIMEOUT - doread: %d, dowrite: %d\n", // doread, dowrite); // Be careful to avoid 'read quick' mode. if((setsec || setusec) && max_network_timeout>0 && network_timeout--<=0) { logp("No activity on network for %d seconds.\n", max_network_timeout); return -1; } return 0; } network_timeout=max_network_timeout; if(FD_ISSET(fd, &fse)) { logp("error on socket\n"); return -1; } if(doread && FD_ISSET(fd, &fsr)) // able to read { int r; read_blocked_on_write=0; if(do_read(&read_blocked_on_write)) return -1; if((r=parse_readbuf(rcmd, rdst, rlen))) logp("error in second parse_readbuf\n"); return r; } if(dowrite && FD_ISSET(fd, &fsw)) // able to write { int r=0; write_blocked_on_read=0; if((r=do_write(&write_blocked_on_read))) logp("error in do_write\n"); return r; } } return 0; }
static int async_rw(struct async *as) { int mfd=-1; fd_set fsr; fd_set fsw; fd_set fse; int doread=0; int dowrite=0; struct timeval tval; if(as->doing_estimate) return 0; if(as->asfd->rbuf) doread++; if(as->asfd->writebuflen && !as->asfd->write_blocked_on_read) dowrite++; // The write buffer is not yet empty. if(doread) { if(as->asfd->parse_readbuf(as->asfd)) return -1; if(as->asfd->rbuf->buf && !as->asfd->writebuflen) return 0; if(as->asfd->read_blocked_on_write) doread=0; } if(doread || dowrite) { mfd=-1; if(doread) FD_ZERO(&fsr); if(dowrite) FD_ZERO(&fsw); FD_ZERO(&fse); add_fd_to_sets(as->asfd->fd, doread?&fsr:NULL, dowrite?&fsw:NULL, &fse, &mfd); tval.tv_sec=as->setsec; tval.tv_usec=as->setusec; if(select(mfd+1, doread?&fsr:NULL, dowrite?&fsw:NULL, &fse, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("select error in %s: %s\n", __func__, strerror(errno)); return -1; } } if(!FD_ISSET(as->asfd->fd, &fse) && (!doread || !FD_ISSET(as->asfd->fd, &fsr)) && (!dowrite || !FD_ISSET(as->asfd->fd, &fsw))) { // Be careful to avoid 'read quick' mode. if((as->setsec || as->setusec) && as->asfd->max_network_timeout>0 && as->asfd->network_timeout--<=0) { logp("No activity on network for %d seconds.\n", as->asfd->max_network_timeout); return -1; } return 0; } as->asfd->network_timeout=as->asfd->max_network_timeout; if(FD_ISSET(as->asfd->fd, &fse)) { logp("error on socket\n"); return -1; } if(doread && FD_ISSET(as->asfd->fd, &fsr)) // able to read { if(as->asfd->ssl) { as->asfd->read_blocked_on_write=0; if(as->asfd->do_read_ssl(as->asfd)) return -1; } else { if(as->asfd->do_read(as->asfd)) return -1; } return as->asfd->parse_readbuf(as->asfd); } if(dowrite && FD_ISSET(as->asfd->fd, &fsw)) // able to write { if(as->asfd->ssl) { as->asfd->write_blocked_on_read=0; return as->asfd->do_write_ssl(as->asfd); } else return as->asfd->do_write(as->asfd); } } return 0; }
int status_client_ncurses(struct config *conf, enum action act, const char *sclient) { int fd=0; int ret=0; int sel=0; char *rbuf=NULL; char buf[512]=""; int count=0; int details=0; char *last_rbuf=NULL; int srbr=0; char *client=NULL; int enterpressed=0; // int loop=0; int reqdone=0; #ifdef HAVE_NCURSES_H int stdinfd=fileno(stdin); actg=act; // So that the sighandler can call endwin(). #else if(act==ACTION_STATUS) { printf("To use the live status monitor, you need to recompile with ncurses support.\n"); return -1; } #endif setup_signals(); /* NULL == ::1 or 127.0.0.1 */ if((fd=init_client_socket(NULL, conf->status_port))<0) return -1; set_non_blocking(fd); #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) { initscr(); start_color(); init_pair(1, COLOR_WHITE, COLOR_BLACK); init_pair(2, COLOR_WHITE, COLOR_BLACK); init_pair(3, COLOR_WHITE, COLOR_BLACK); raw(); keypad(stdscr, TRUE); noecho(); curs_set(0); halfdelay(3); //nodelay(stdscr, TRUE); } #endif #ifdef DBFP dbfp=fopen("/tmp/dbfp", "w"); #endif while(!ret) { int l; int mfd=-1; fd_set fsr; fd_set fse; struct timeval tval; // Failsafe to prevent the snapshot ever getting permanently // stuck. //if(act==ACTION_STATUS_SNAPSHOT && loop++>10000) // break; if(sclient && !client) { client=strdup(sclient); details=1; } if((enterpressed || need_status()) && !reqdone) { char *req=NULL; if(details && client) req=client; if(request_status(fd, req, conf)) { ret=-1; break; } enterpressed=0; if(act==ACTION_STATUS_SNAPSHOT) reqdone++; } FD_ZERO(&fsr); FD_ZERO(&fse); tval.tv_sec=1; tval.tv_usec=0; add_fd_to_sets(fd, &fsr, NULL, &fse, &mfd); #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) add_fd_to_sets(stdinfd, &fsr, NULL, &fse, &mfd); #endif if(select(mfd+1, &fsr, NULL, &fse, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("select error: %s\n", strerror(errno)); ret=-1; break; } continue; } if(FD_ISSET(fd, &fse)) { ret=-1; break; } #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) { if(FD_ISSET(stdinfd, &fse)) { ret=-1; break; } if(FD_ISSET(stdinfd, &fsr)) { int quit=0; switch(getch()) { case 'q': case 'Q': quit++; break; case KEY_UP: case 'k': case 'K': if(details) break; sel--; break; case KEY_DOWN: case 'j': case 'J': if(details) break; sel++; break; case KEY_ENTER: case '\n': case ' ': if(details) details=0; else details++; enterpressed++; break; case KEY_LEFT: case 'h': case 'H': details=0; break; case KEY_RIGHT: case 'l': case 'L': details++; break; case KEY_NPAGE: { int row=0, col=0; getmaxyx(stdscr, row, col); sel+=row-TOP_SPACE; break; } case KEY_PPAGE: { int row=0, col=0; getmaxyx(stdscr, row, col); sel-=row-TOP_SPACE; break; } } if(quit) break; if(sel<0) sel=0; if(sel>=count) sel=count-1; // Attempt to print stuff to the screen right // now, to give the impression of key strokes // being responsive. if(!details && !sclient) { if((srbr=show_rbuf(last_rbuf, conf, sel, &client, &count, details, sclient))<0) { ret=-1; break; } if(!details) print_star(sel); refresh(); } } } #endif if(FD_ISSET(fd, &fsr)) { // ready to read. if((l=read(fd, buf, sizeof(buf)-1))>0) { size_t r=0; buf[l]='\0'; if(rbuf) r=strlen(rbuf); rbuf=(char *)realloc(rbuf, r+l+1); if(!r) *rbuf='\0'; strcat(rbuf+r, buf); } else break; if(act==ACTION_STATUS_SNAPSHOT) { if(rbuf) { if(!strcmp(rbuf, "\n")) { // This happens when there are // no backup clients. break; } if(strstr(rbuf, "\n-list end-\n")) { printf("%s", rbuf); break; } } continue; } //if(rbuf) printf("rbuf: %s\n", rbuf); /* if(l<0) { ret=-1; break; } */ } if((srbr=show_rbuf(rbuf, conf, sel, &client, &count, details, sclient))<0) { ret=-1; break; } else if(srbr) { // Remember it, so that we can present the detailed // screen without delay, above. if(last_rbuf) free(last_rbuf); last_rbuf=rbuf; rbuf=NULL; } if(sclient) details++; usleep(20000); #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) { flushinp(); continue; } #endif if(count) { printf("\n"); break; } } #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) endwin(); #endif close_fd(&fd); if(last_rbuf) free(last_rbuf); if(rbuf) free(rbuf); #ifdef DBFP if(dbfp) fclose(dbfp); #endif return ret; }
static int async_io(struct async *as, int doread) { int mfd=-1; fd_set fsr; fd_set fsw; fd_set fse; int dosomething=0; struct timeval tval; struct asfd *asfd; static int s=0; as->now=time(NULL); if(!as->last_time) as->last_time=as->now; if(as->doing_estimate) goto end; FD_ZERO(&fsr); FD_ZERO(&fsw); FD_ZERO(&fse); tval.tv_sec=as->setsec; tval.tv_usec=as->setusec; for(asfd=as->asfd; asfd; asfd=asfd->next) { if(asfd->fdtype==ASFD_FD_SERVER_PIPE_WRITE || asfd->fdtype==ASFD_FD_CHILD_PIPE_WRITE || asfd->fdtype==ASFD_FD_CLIENT_MONITOR_WRITE) asfd->doread=0; else asfd->doread=doread; asfd->dowrite=0; if(doread) { if(asfd->parse_readbuf(asfd)) return asfd_problem(asfd); if(asfd->rbuf->buf || asfd->read_blocked_on_write) asfd->doread=0; } if(asfd->writebuflen && !asfd->write_blocked_on_read) asfd->dowrite++; // The write buffer is not yet empty. if(!asfd->doread && !asfd->dowrite) continue; add_fd_to_sets(asfd->fd, asfd->doread?&fsr:NULL, asfd->dowrite?&fsw:NULL, &fse, &mfd); dosomething++; } if(!dosomething) goto end; /* for(asfd=as->asfd; asfd; asfd=asfd->next) { printf("%s: %d %d %d %d\n", asfd->desc, asfd->doread, asfd->dowrite, asfd->readbuflen, asfd->writebuflen); } */ errno=0; s=select(mfd+1, &fsr, &fsw, &fse, &tval); if(errno==EAGAIN || errno==EINTR) goto end; if(s<0) { logp("select error in %s: %s\n", __func__, strerror(errno)); as->last_time=as->now; return -1; } for(asfd=as->asfd; asfd; asfd=asfd->next) { if(FD_ISSET(asfd->fd, &fse)) { switch(asfd->fdtype) { case ASFD_FD_SERVER_LISTEN_MAIN: case ASFD_FD_SERVER_LISTEN_STATUS: as->last_time=as->now; return -1; default: logp("%s: had an exception\n", asfd->desc); return asfd_problem(asfd); } } if(asfd->doread && FD_ISSET(asfd->fd, &fsr)) // Able to read. { asfd->network_timeout=asfd->max_network_timeout; switch(asfd->fdtype) { case ASFD_FD_SERVER_LISTEN_MAIN: case ASFD_FD_SERVER_LISTEN_STATUS: // Indicate to the caller that we have // a new incoming client. asfd->new_client++; break; default: if(asfd->do_read(asfd) || asfd->parse_readbuf(asfd)) return asfd_problem(asfd); break; } } if(asfd->dowrite && FD_ISSET(asfd->fd, &fsw)) // Able to write. { asfd->network_timeout=asfd->max_network_timeout; if(asfd->do_write(asfd)) return asfd_problem(asfd); } if((!asfd->doread || !FD_ISSET(asfd->fd, &fsr)) && (!asfd->dowrite || !FD_ISSET(asfd->fd, &fsw))) { // Be careful to avoid 'read quick' mode. if((as->setsec || as->setusec) && asfd->fdtype!=ASFD_FD_SERVER_LISTEN_MAIN && asfd->fdtype!=ASFD_FD_SERVER_LISTEN_STATUS && as->now-as->last_time>0 && as->now-as->last_time>0 && asfd->max_network_timeout>0 && asfd->network_timeout--<=0) { logp("%s: no activity for %d seconds.\n", asfd->desc, asfd->max_network_timeout); return asfd_problem(asfd); } } } end: as->last_time=as->now; return 0; }
static int run_server(struct conf *conf, const char *conffile, int *rfd, const char *oldport, const char *oldstatusport) { int ret=0; SSL_CTX *ctx=NULL; int found_normal_child=0; if(!(ctx=ssl_initialise_ctx(conf))) { logp("error initialising ssl ctx\n"); return 1; } if((ssl_load_dh_params(ctx, conf))) { logp("error loading dh params\n"); return 1; } if(!oldport || strcmp(oldport, conf->port)) { close_fd(rfd); if((*rfd=init_listen_socket(conf->port, 1))<0) return 1; } if(conf->status_port && (!oldstatusport || strcmp(oldstatusport, conf->status_port))) { close_fd(&sfd); if((sfd=init_listen_socket(conf->status_port, 0))<0) return 1; } while(!hupreload) { int mfd=-1; fd_set fsr; fd_set fsw; fd_set fse; struct timeval tval; if(sigchld) { chld_check_for_exiting(); sigchld=0; } FD_ZERO(&fsr); FD_ZERO(&fse); tval.tv_sec=1; tval.tv_usec=0; add_fd_to_sets(*rfd, &fsr, NULL, &fse, &mfd); if(sfd>=0) add_fd_to_sets(sfd, &fsr, NULL, &fse, &mfd); // Add read fds of normal children. found_normal_child=chld_add_fd_to_normal_sets(conf, &fsr, &fse, &mfd); // Leave if we had a SIGUSR1 and there are no children // running. if(gentleshutdown) { if(!gentleshutdown_logged) { logp("got SIGUSR2 gentle reload signal\n"); logp("will shut down once children have exited\n"); gentleshutdown_logged++; } else if(!found_normal_child) { logp("all children have exited - shutting down\n"); break; } } if(select(mfd+1, &fsr, NULL, &fse, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("select error in normal part of %s: %s\n", __func__, strerror(errno)); ret=1; break; } } if(FD_ISSET(*rfd, &fse)) { // Happens when a client exits. //logp("error on listening socket.\n"); if(!conf->forking) { gentleshutdown++; break; } continue; } if((sfd>=0 && FD_ISSET(sfd, &fse))) { // Happens when a client exits. //logp("error on status socket.\n"); if(!conf->forking) { gentleshutdown++; break; } continue; } if(FD_ISSET(*rfd, &fsr)) { // A normal client is incoming. if(process_incoming_client(*rfd, conf, ctx, conffile, 0 /* not a status client */)) { ret=1; break; } if(!conf->forking) { gentleshutdown++; break; } } if(sfd>=0 && FD_ISSET(sfd, &fsr)) { // A status client is incoming. //printf("status client?\n"); if(process_incoming_client(sfd, conf, ctx, conffile, 1 /* a status client */)) { ret=1; break; } if(!conf->forking) { gentleshutdown++; break; } } if(chld_fd_isset_normal(conf, &fsr, &fse)) { ret=1; break; } // Have a separate select for writing to status server children mfd=-1; FD_ZERO(&fsw); FD_ZERO(&fse); if(!chld_add_fd_to_status_sets(conf, &fsw, &fse, &mfd)) { // Did not find any status server children. // No need to do the select. continue; } // Do not hang around - doing the status stuff is a lower // priority thing than dealing with normal clients. tval.tv_sec=0; tval.tv_usec=500; //printf("try status server\n"); if(select(mfd+1, NULL, &fsw, &fse, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("select error in status part of %s: %s\n", __func__, strerror(errno)); ret=1; break; } } if(chld_fd_isset_status(conf, &fsw, &fse)) { ret=1; break; } } if(hupreload) logp("got SIGHUP reload signal\n"); ssl_destroy_ctx(ctx); return ret; }