/********************************************************************** * %FUNCTION: Event_HandleChildExit * %ARGUMENTS: * es -- event selector * pid -- process-ID of child to wait for * handler -- function to call when child exits * data -- data to pass to handler when child exits * %RETURNS: * 0 on success, -1 on failure. * %DESCRIPTION: * Sets things up so that when a child exits, handler() will be called * with the pid of the child and "data" as arguments. The call will * be synchronous (part of the normal event loop on es). ***********************************************************************/ int Event_HandleChildExit(EventSelector *es, pid_t pid, void (*handler)(pid_t, int, void *), void *data) { struct ChildEntry *ce; sigset_t set; if (Event_HandleSignal(es, SIGCHLD, child_handler) < 0) return -1; ce = malloc(sizeof(struct ChildEntry)); if (!ce) return -1; ce->pid = pid; ce->data = data; ce->handler = handler; /* Critical section: Don't let SIGCHLD mess hash_insert */ sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, NULL); hash_insert(&child_process_table, ce); sigprocmask(SIG_UNBLOCK, &set, NULL); return 0; }
/********************************************************************** * %FUNCTION: Event_HandleChildExit * %ARGUMENTS: * es -- event selector * pid -- process-ID of child to wait for * handler -- function to call when child exits * data -- data to pass to handler when child exits * %RETURNS: * 0 on success, -1 on failure. * %DESCRIPTION: * Sets things up so that when a child exits, handler() will be called * with the pid of the child and "data" as arguments. The call will * be synchronous (part of the normal event loop on es). ***********************************************************************/ int Event_HandleChildExit(EventSelector *es, pid_t pid, void (*handler)(pid_t, int, void *), void *data) { struct ChildEntry *ce; if (Event_HandleSignal(es, SIGCHLD, child_handler) < 0) return -1; ce = malloc(sizeof(struct ChildEntry)); if (!ce) return -1; ce->pid = pid; ce->data = data; ce->handler = handler; hash_insert(&child_process_table, ce); return 0; }
/********************************************************************** * %FUNCTION: network_init * %ARGUMENTS: * es -- an event selector * %RETURNS: * >= 0 if all is OK, <0 if not * %DESCRIPTION: * Initializes network; opens socket on UDP port 1701; sets up * event handler for incoming packets. ***********************************************************************/ int l2tp_network_init(EventSelector *es) { struct sockaddr_in me; int flags; gethostname(Hostname, sizeof(Hostname)); Hostname[sizeof(Hostname)-1] = 0; Event_HandleSignal(es, SIGINT, sigint_handler); if (Sock >= 0) { if (NetworkReadHandler) { Event_DelHandler(es, NetworkReadHandler); NetworkReadHandler = NULL; } close(Sock); Sock = -1; } Sock = socket(PF_INET, SOCK_DGRAM, 0); if (Sock < 0) { l2tp_set_errmsg("network_init: socket: %s", strerror(errno)); return -1; } me.sin_family = AF_INET; me.sin_addr = Settings.listen_addr; me.sin_port = htons((uint16_t) Settings.listen_port); if (bind(Sock, (struct sockaddr *) &me, sizeof(me)) < 0) { l2tp_set_errmsg("network_init: bind: %s", strerror(errno)); close(Sock); Sock = -1; return -1; } /* Set socket non-blocking */ flags = fcntl(Sock, F_GETFL); flags |= O_NONBLOCK; fcntl(Sock, F_SETFL, flags); /* Set up the network read handler */ Event_AddHandler(es, Sock, EVENT_FLAG_READABLE, network_readable, NULL); return Sock; }
int main(int argc, char *argv[]) { EventSelector *es = Event_CreateSelector(); int i; int opt; int do_fork = 1; int debugmask = 0; while((opt = getopt(argc, argv, "d:fh")) != -1) { switch(opt) { case 'h': usage(argc, argv, EXIT_SUCCESS); break; case 'f': do_fork = 0; break; case 'd': sscanf(optarg, "%d", &debugmask); break; default: usage(argc, argv, EXIT_FAILURE); } } openlog(argv[0], LOG_PID, LOG_DAEMON); l2tp_random_init(); l2tp_tunnel_init(es); l2tp_peer_init(); l2tp_debug_set_bitmask(debugmask); /* ASUS if (l2tp_parse_config_file(es, SYSCONFDIR"/l2tp/l2tp.conf") < 0) { */ if (l2tp_parse_config_file(es, SYSCONFDIR"/l2tp.conf") < 0) { l2tp_die(); } if (!l2tp_network_init(es)) { l2tp_die(); } /* Daemonize */ if (do_fork) { i = fork(); if (i < 0) { perror("fork"); exit(EXIT_FAILURE); } else if (i != 0) { /* Parent */ exit(EXIT_SUCCESS); } setsid(); signal(SIGHUP, SIG_IGN); i = fork(); if (i < 0) { perror("fork"); exit(EXIT_FAILURE); } else if (i != 0) { exit(EXIT_SUCCESS); } chdir("/"); /* Point stdin/stdout/stderr to /dev/null */ for (i=0; i<3; i++) { close(i); } i = open("/dev/null", O_RDWR); if (i >= 0) { dup2(i, 0); dup2(i, 1); dup2(i, 2); if (i > 2) close(i); } } Event_HandleSignal(es, SIGINT, sighandler); Event_HandleSignal(es, SIGTERM, sighandler); while(1) { i = Event_HandleEvent(es); if (i < 0) { fprintf(stderr, "Event_HandleEvent returned %d\n", i); l2tp_cleanup(); exit(EXIT_FAILURE); } } return 0; }