// FIXME we need better EV_ERROR handling static inline void handle_kqueue_results(poller *p,const struct kevent *kevents,unsigned events){ unsigned n = 0; // nag("Handling %u events\n",events); for(n = 0 ; n < events ; ++n){ const struct kevent *kv = &kevents[n]; if(kv->filter == EVFILT_SIGNAL){ nag("SignalRX (%s)\n",strsignal(kv->ident)); if(kv->ident == SIGCHLD){ p->sigchldrx += kv->data; handle_sigchld(p); } }else{ pollfd_state *state; int fd = kv->ident; if(fd < 0 || fd >= p->pfds_available){ bitch("Invalid fd %d (max %d)\n",fd,p->pfds_available); inc_stateexceptions(); continue; } state = &p->fdstates[fd]; if(fd != state->pfd.fd){ // We might close a descriptor despite // outstanding events later in the vector. Note // them, but don't take action otherwise. handle_invalidated_kevent(kv,fd,state); }else{ struct timeval tvstart,tvend; int r; Gettimeofday(&tvstart,NULL); state->lastuse_time = tvstart.tv_sec; if(kv->flags & EV_ERROR){ handle_kqueue_error(state); r = -1; }else if(kv->filter == EVFILT_READ){ r = handle_kqueue_read(p,state); }else if(kv->filter == EVFILT_WRITE){ r = handle_kqueue_write(p,state); }else if(kv->filter == EVFILT_TIMER){ // nag("Timer callback %d\n",fd); r = handle_kqueue_timeout(p,state); }else{ bitch("Unknown kevent filter %d\n",kv->filter); inc_stateexceptions(); r = 0; } if(!r){ time_avgmax(&state->pfd_avgmax_time,&tvend,&tvstart); }else{ purge_fd_resulthandler(p,state,fd); } } } } }
static void test_handle_sigchld_succeeded() { setup(); expect_value( mock_set_external_callback, callback, wait_child ); handle_sigchld( 3 ); teardown(); }
int main ( int argc, char **argv ) { set_traps(); sigset_t mask; sigemptyset( &mask ); sigaddset( &mask, SIGCHLD ); sigprocmask(SIG_BLOCK, &mask, NULL ); signal_fd = signalfd( -1, &mask, SFD_NONBLOCK ); nsm_proxy = new NSM_Proxy(); init_osc( NULL ); const char *nsm_url = getenv( "NSM_URL" ); if ( nsm_url ) { announce( nsm_url, APP_TITLE, argv[0] ); } else { fprintf( stderr, "Could not register as NSM client.\n" ); exit(1); } struct signalfd_siginfo fdsi; /* listen for sigchld signals and process OSC messages forever */ for ( ;; ) { ssize_t s = read(signal_fd, &fdsi, sizeof(struct signalfd_siginfo)); if (s == sizeof(struct signalfd_siginfo)) { if (fdsi.ssi_signo == SIGCHLD) handle_sigchld(); } lo_server_recv_noblock( losrv, 500 ); if ( die_now ) die(); } }
void check_signals(void) { if (mf_sigchld) handle_sigchld(); if (mf_sigalrm) handle_sigalrm(); if (mf_sigint) handle_sigint(); if (mf_sigquit) handle_sigquit(); if (mf_sigterm) handle_sigterm(); if (mf_sigpipe) handle_sigpipe(); if (mf_sigusr1) handle_sigusr1(); if (mf_sigusr2) handle_sigusr2(); if (mf_sighup) handle_sighup(); if (mf_stupid) { syslog(LOG_ERR,"set a signal handler,but forgot to write code to handle it"); mf_stupid = 0; } }
/*! \todo * \li Add a dpid_idle_timeout variable to dpidrc * \bug Infinite loop if plugin crashes before it accepts a connection */ int main(void) { int i, n = 0, open_max; int dpid_idle_timeout = 60 * 60; /* default, in seconds */ struct timeval select_timeout; sigset_t mask_none; fd_set selected_set; dpi_attr_list = NULL; services_list = NULL; //daemon(0,0); /* Use 0,1 for feedback */ /* TODO: call setsid() ?? */ /* Allow read and write access, but only for the user. * TODO: can this cause trouble with umount? */ umask(0077); /* TODO: make dpid work on any directory. */ // chdir("/"); /* close inherited file descriptors */ open_max = get_open_max(); for (i = 3; i < open_max; i++) dClose(i); /* this sleep used to unmask a race condition */ // sleep(2); dpi_errno = no_errors; /* Get list of available dpis */ numdpis = register_all(&dpi_attr_list); #if 0 /* Get name of socket directory */ dirname = a_Dpi_sockdir_file(); if ((sockdir = init_sockdir(dirname)) == NULL) { ERRMSG("main", "init_sockdir", 0); MSG_ERR("Failed to create socket directory\n"); exit(1); } #endif /* Init and get services list */ fill_services_list(dpi_attr_list, numdpis, &services_list); /* Remove any sockets that may have been leftover from a crash */ //cleanup(); /* Initialise sockets */ if ((numsocks = init_ids_srs_socket()) == -1) { switch (dpi_errno) { case dpid_srs_addrinuse: MSG_ERR("dpid refuses to start, possibly because:\n"); MSG_ERR("\t1) An instance of dpid is already running.\n"); MSG_ERR("\t2) A previous dpid didn't clean up on exit.\n"); exit(1); default: //ERRMSG("main", "init_srs_socket failed", 0); ERRMSG("main", "init_ids_srs_socket failed", 0); exit(1); } } numsocks = init_all_dpi_sockets(dpi_attr_list); est_dpi_terminator(); est_dpi_sigchld(); (void) sigemptyset(&mask_sigchld); (void) sigaddset(&mask_sigchld, SIGCHLD); (void) sigemptyset(&mask_none); (void) sigprocmask(SIG_SETMASK, &mask_none, NULL); printf("dpid started\n"); /* Start main loop */ while (1) { do { (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL); if (caught_sigchld) { handle_sigchld(); caught_sigchld = 0; } (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); select_timeout.tv_sec = dpid_idle_timeout; select_timeout.tv_usec = 0; selected_set = sock_set; n = select(FD_SETSIZE, &selected_set, NULL, NULL, &select_timeout); if (n == 0) { /* select timed out, try to exit */ /* BUG: This is a workaround for dpid not to exit when the * downloads server is active. The proper way to handle it is with * a dpip command that asks the server whether it's busy. * Note: the cookies server may lose session info too. */ if (server_is_running("downloads")) continue; stop_active_dpis(dpi_attr_list, numdpis); //cleanup(); exit(0); } } while (n == -1 && errno == EINTR); if (n == -1) { ERRMSG("main", "select", errno); exit(1); } /* If the service req socket is selected then service the req. */ if (FD_ISSET(srs_fd, &selected_set)) { int sock_fd; socklen_t sin_sz; struct sockaddr_in sin; char *req = NULL; --n; assert(n >= 0); sin_sz = (socklen_t) sizeof(sin); sock_fd = accept(srs_fd, (struct sockaddr *)&sin, &sin_sz); if (sock_fd == -1) { ERRMSG("main", "accept", errno); MSG_ERR("accept on srs socket failed\n"); MSG_ERR("service pending connections, and continue\n"); } else { int command; Dsh *sh; sh = a_Dpip_dsh_new(sock_fd, sock_fd, 1024); read_next: req = get_request(sh); command = get_command(sh, req); switch (command) { case AUTH_CMD: if (a_Dpip_check_auth(req) != -1) { dFree(req); goto read_next; } break; case BYE_CMD: stop_active_dpis(dpi_attr_list, numdpis); //cleanup(); exit(0); break; case CHECK_SERVER_CMD: send_sockport(sock_fd, req, dpi_attr_list); break; case REGISTER_ALL_CMD: register_all_cmd(); break; case UNKNOWN_CMD: { char *d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "DpiError", "Unknown command"); (void) CKD_WRITE(sock_fd, d_cmd); dFree(d_cmd); ERRMSG("main", "Unknown command", 0); MSG_ERR(" for request: %s\n", req); break; } case -1: _ERRMSG("main", "get_command failed", 0); break; } if (req) free(req); a_Dpip_dsh_close(sh); a_Dpip_dsh_free(sh); } } /* While there's a request on one of the plugin sockets * find the matching plugin and start it. */ for (i = 0; n > 0 && i < numdpis; i++) { if (FD_ISSET(dpi_attr_list[i].sock_fd, &selected_set)) { --n; assert(n >= 0); if (dpi_attr_list[i].filter) { /* start a dpi filter plugin and continue watching its socket * for new connections */ (void) sigprocmask(SIG_SETMASK, &mask_none, NULL); start_filter_plugin(dpi_attr_list[i]); } else { /* start a dpi server plugin but don't wait for new connections * on its socket */ numsocks--; assert(numsocks >= 0); FD_CLR(dpi_attr_list[i].sock_fd, &sock_set); if ((dpi_attr_list[i].pid = fork()) == -1) { ERRMSG("main", "fork", errno); /* exit(1); */ } else if (dpi_attr_list[i].pid == 0) { /* child */ (void) sigprocmask(SIG_SETMASK, &mask_none, NULL); start_server_plugin(dpi_attr_list[i]); } } } } } }