/* Derived from lib/daemon.c by fastdaemon.sed */ /*- * Copyright (c) 1993, Trusted Information Systems, Incorporated * All rights reserved. * * Redistribution and use are governed by the terms detailed in the * license document ("LICENSE") included with the toolkit. */ /* * 10/27 pjc modified listen to use SOMAXCONN * added sleep on bind failure. */ #include #include #include #include #include #include #include #ifdef SYSV #include #endif #include #include #include #include #include #include #ifndef AIX #include #endif #include #include #include #include #include "firewall.h" #include "libemfw.h" #include "fwstats.h" extern struct fwstats proxy_stats; extern void waitwaitwait(); extern void hup_exit(); extern void got_signal (); extern char* ip2name(struct in_addr); int do_fastdaemon(args) struct fastdaemon_args *args; { struct sockaddr_in sa; int sock,sockl; pid_t pid; int boundok = 1; int reuse = 1; int devnull; #ifdef HAVE_SETSID (void) setsid(); #endif if ((pid = fork()) == -1) return (-1); if (pid) { keep_pid_file (); exit(0); /* parent exits */ } write_pid_file (); devnull = open("/dev/null", O_RDWR, 0); if (devnull != -1) { (void) dup2(devnull, 0); (void) dup2(devnull, 1); (void) dup2(devnull, 2); if (devnull > 2) (void) close(devnull); } sa.sin_family = AF_INET; fastdaemon_sockaddr (&sa, args); sock = socket(AF_INET, SOCK_STREAM, 0); if( sock < 0){ syslog(LLEV,"Failed to create socket, %s", strerror(errno)); exit(1); } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); while( bind(sock, (struct sockaddr *)&sa, sizeof(sa))){ syslog(LLEV,"Failed to bind port %d, %s", args->port, strerror(errno)); syslog(LLEV,"Sleeping for 2 minutes"); sleep(120); boundok=0; } #ifndef SOMAXCONN #define SOMAXCONN 4 #endif if( listen(sock, SOMAXCONN) < 0){ syslog(LLEV,"Failed to listen, %s", strerror(errno)); exit(1); } if( boundok == 0){ fastdaemon_ready (args); } signal(SIGCHLD,waitwaitwait); signal(SIGINT, hup_exit); signal(SIGTERM,hup_exit); while(1){ socklen_t salen = sizeof(sa); sockl = accept(sock, (struct sockaddr *)&sa, &salen); if( sockl < 0){ if( errno == EINTR) { got_signal (); continue; } syslog(LLEV,"Accept failed, %s", strerror(errno)); continue; } if ((proxy_stats.child_limit) && (proxy_stats.child_count > proxy_stats.child_limit)) { syslog(LLEV,"deny host=%.100s/%.100s use of gateway: child limit exceeded",ip2name(sa.sin_addr),inet_ntoa(sa.sin_addr)); close(sockl); continue; } pid = fork(); if( pid < 0){ syslog(LLEV,"Fork failed, %s", strerror(errno)); /* 9/8/95 pjc. Make fork failure non-fatal, just throw connection for now */ close(sockl); continue; } if( pid == 0) break; /* We are the child */ close(sockl); } #ifdef HAVE_SETSID (void)setsid(); #endif signal(SIGHUP, SIG_IGN); close(0); close(1); close(2); dup(sockl); dup(sockl); dup(sockl); close(sockl); close(sock); keep_pid_file (); return 0; }