int main(int argc, char **argv) { unsigned char buf[256]; int size, s, cntrl_s, cntrl_fd; socklen_t cntrl_len; struct sockaddr_un cntrl_addr; fd_set read_fds, write_fds; int fd_max; if (ax25_config_load_ports() == 0) { fprintf(stderr, "ax25rtd: no AX.25 port configured\n"); return 1; } load_config(); load_cache(); if (fork()) return 0; if ((s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_AX25))) == -1) { perror("AX.25 socket"); return 1; } if ((cntrl_s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("Control socket"); return 1; } unlink(DATA_AX25ROUTED_CTL_SOCK); cntrl_addr.sun_family = AF_UNIX; strcpy(cntrl_addr.sun_path, DATA_AX25ROUTED_CTL_SOCK); cntrl_len = sizeof(cntrl_addr.sun_family) + strlen(DATA_AX25ROUTED_CTL_SOCK); if (bind(cntrl_s, (struct sockaddr *) &cntrl_addr, cntrl_len) < 0) { perror("bind Control socket"); daemon_shutdown(1); } chmod(DATA_AX25ROUTED_CTL_SOCK, 0600); listen(cntrl_s, 1); signal(SIGUSR1, sig_debug); signal(SIGHUP, sig_reload); signal(SIGTERM, sig_term); cntrl_fd = -1; for (;;) { fd_max = 0; FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_MAX(s); if (cntrl_fd > 0) { FD_MAX(cntrl_fd); FD_SET(cntrl_fd, &write_fds); } else { FD_MAX(cntrl_s); } if (select(fd_max + 1, &read_fds, NULL, &write_fds, NULL) < 0) { if (errno == EINTR) /* woops! */ continue; if (!FD_ISSET(cntrl_fd, &write_fds)) { perror("select"); save_cache(); daemon_shutdown(1); } else { close(cntrl_fd); cntrl_fd = -1; continue; } } if (cntrl_fd > 0) { if (FD_ISSET(cntrl_fd, &read_fds)) { size = read(cntrl_fd, buf, sizeof(buf)); if (size > 0) { buf[size] = '\0'; interpret_command(cntrl_fd, buf); } else { close(cntrl_fd); cntrl_fd = -1; } } } else if (FD_ISSET(cntrl_s, &read_fds)) { if ((cntrl_fd = accept(cntrl_s, (struct sockaddr *) &cntrl_addr, &cntrl_len)) < 0) { perror("accept Control"); save_cache(); daemon_shutdown(1); } } if (reload) reload_config(); if (FD_ISSET(s, &read_fds)) ax25_receive(s); } return 0; /* what ?! */ }
static int main_loop(SESSION *sess) { fd_set rfds, wfds, exfds; int i, stdin_closed; sess->inbuf = queue_new(INLET_QUEUE_SIZE); sess->outbuf = queue_new(OUTLET_QUEUE_SIZE); if (sess->inbuf == NULL || sess->outbuf == NULL) error(1, "Can't allocate the mainstream queues.\n"); for (i = 0; i < sess->num_workers; i++) { sess->workers[i].inbuf = queue_new(INQUEUE_SIZE); sess->workers[i].outbuf = queue_new(OUTQUEUE_SIZE); if (sess->workers[i].inbuf == NULL || sess->workers[i].outbuf == NULL) error(1, "Failed to allocate buffer queues.\n"); } FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&exfds); stdin_closed = 0; for (;;) { int maxfd=-1, nevents; struct timeval tv, *timeout; if (stdin_closed || is_queue_full(sess->inbuf)) FD_CLR(STDIN_FILENO, &rfds); else { FD_SET(STDIN_FILENO, &rfds); maxfd = FD_MAX(maxfd, STDIN_FILENO); } if (!is_queue_empty(sess->outbuf)) { FD_SET(STDOUT_FILENO, &wfds); maxfd = FD_MAX(maxfd, STDOUT_FILENO); } else FD_CLR(STDOUT_FILENO, &wfds); for (i = 0; i < sess->num_workers; i++) { WORKER *w=&sess->workers[i]; if (!IS_STDOUT_ALIVE(w) || is_queue_full(w->inbuf)) FD_CLR(w->stdout_fd, &rfds); else { FD_SET(w->stdout_fd, &rfds); maxfd = FD_MAX(maxfd, w->stdout_fd); } if (IS_STDIN_ALIVE(w) && !is_queue_empty(w->outbuf)) { FD_SET(w->stdin_fd, &wfds); maxfd = FD_MAX(maxfd, w->stdin_fd); } else FD_CLR(w->stdin_fd, &wfds); } if (maxfd < 0 && sess->running_workers <= 0) break; tv.tv_sec = 0; tv.tv_usec = 500000; timeout = &tv; if ((nevents = select(maxfd + 1, &rfds, &wfds, &exfds, timeout)) == -1) { if (errno == EINTR) continue; perror("echidna"); error(1, "Error on select()\n"); } if (nevents == 0) { /* select timed out. */ if (!is_queue_full(sess->outbuf)) { /* Traverse all workers and try processing for blocked output queues. */ for (i = 0; i < sess->num_workers; i++) { WORKER *w=&sess->workers[i]; if (w->status == STATUS_RUNNING && !is_queue_empty(w->inbuf)) w->input_handler(sess, w); } } continue; } if (FD_ISSET(STDIN_FILENO, &rfds)) { char *bufstart; qsize_t bufsize; ssize_t rsize; bufsize = queue_num_continuous_vacant(sess->inbuf, &bufstart); if ((rsize = read(STDIN_FILENO, bufstart, bufsize)) < 0) error(1, "Error on reading from stdin.\n"); if (rsize == 0) stdin_closed = 1; else queue_queued(sess->inbuf, rsize); sess->input_handler(sess); } if (FD_ISSET(STDOUT_FILENO, &wfds)) { char *bufstart; qsize_t bufsize; ssize_t wsize; bufsize = queue_num_continuous_filled(sess->outbuf, &bufstart); if ((wsize = write(STDOUT_FILENO, bufstart, bufsize)) < 0) { if (errno != EAGAIN) error(1, "Error on writing to stdout.\n"); } queue_consumed(sess->outbuf, wsize); for (i = 0; i < sess->num_workers; i++) { WORKER *w=&sess->workers[i]; if (!is_queue_empty(w->inbuf)) w->input_handler(sess, w); } } for (i = 0; i < sess->num_workers; i++) { WORKER *w=&sess->workers[i]; if (FD_ISSET(w->stdout_fd, &rfds)) { char *bufstart; qsize_t bufsize; ssize_t rsize; bufsize = queue_num_continuous_vacant(w->inbuf, &bufstart); if ((rsize = read(w->stdout_fd, bufstart, bufsize)) < 0) error(1, "Error on reading from worker %d.\n", i); if (rsize == 0) w->status = STATUS_TERMINATED; else queue_queued(w->inbuf, rsize); w->input_handler(sess, w); } if (FD_ISSET(w->stdin_fd, &wfds)) { char *bufstart; qsize_t bufsize; ssize_t wsize; bufsize = queue_num_continuous_filled(w->outbuf, &bufstart); if ((wsize = write(w->stdin_fd, bufstart, bufsize)) < 0) { if (errno != EAGAIN) error(1, "Error on writing to worker %d.\n", i); } queue_consumed(w->outbuf, wsize); sess->input_handler(sess); } else if (stdin_closed && w->status == STATUS_RUNNING && is_queue_empty(w->outbuf)) { w->status = STATUS_FLUSHING; if (close(w->stdin_fd) == -1) perror("close"); } } } for (i = 0; i < sess->num_workers; i++) { queue_destroy(sess->workers[i].inbuf); queue_destroy(sess->workers[i].outbuf); } queue_destroy(sess->inbuf); queue_destroy(sess->outbuf); return 0; }