diff options
author | dg <dg@FreeBSD.org> | 1996-04-11 10:22:16 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1996-04-11 10:22:16 +0000 |
commit | 53e950c18529ee4286dcd120640c4544f5651386 (patch) | |
tree | 74ce8d143a92773e944580691fd7a7491a4394fe /libexec/ftpd | |
parent | 414db770b68b564ca18c187735e992086a5c940f (diff) | |
download | FreeBSD-src-53e950c18529ee4286dcd120640c4544f5651386.zip FreeBSD-src-53e950c18529ee4286dcd120640c4544f5651386.tar.gz |
Implemented a "-D" option that causes ftpd to detach and become a daemon -
accepting connections on the FTP port and forking children processes to
handling them. This is lower overhead than spawning ftpd from inetd and
can be a significant win on busy FTP servers. Be sure to disable ftpd in
inetd.conf if you decide to use this option.
These changes are based on similar changes I made to wu-ftpd and have
been in use on wcarchive for several months.
Diffstat (limited to 'libexec/ftpd')
-rw-r--r-- | libexec/ftpd/ftpd.8 | 12 | ||||
-rw-r--r-- | libexec/ftpd/ftpd.c | 137 |
2 files changed, 120 insertions, 29 deletions
diff --git a/libexec/ftpd/ftpd.8 b/libexec/ftpd/ftpd.8 index 6e5b199..8cd6902 100644 --- a/libexec/ftpd/ftpd.8 +++ b/libexec/ftpd/ftpd.8 @@ -41,6 +41,7 @@ Internet File Transfer Protocol server .Sh SYNOPSIS .Nm ftpd .Op Fl dl +.Op Fl D .Op Fl S .Op Fl U .Op Fl T Ar maxtimeout @@ -68,6 +69,16 @@ session is logged using syslog with a facility of LOG_FTP. If this option is specified twice, the retrieve (get), store (put), append, delete, make directory, remove directory and rename operations and their filename arguments are also logged. +.It Fl D +With this option set, +.Nm ftpd +will detach and become a daemon, accepting connections on the FTP port and +forking children processes to handle them. This is lower overhead than +starting +.Nm ftpd +from +.Xr inetd 8 +and is thus useful on busy servers to reduce load. .It Fl S With this option set, .Nm ftpd @@ -295,6 +306,7 @@ Log file for anonymous transfers. .Sh SEE ALSO .Xr ftp 1 , .Xr getusershell 3 , +.Xr inetd 8 , .Xr syslogd 8 .Sh BUGS The server must run as the super-user diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c index 1137d9f..2d7a041 100644 --- a/libexec/ftpd/ftpd.c +++ b/libexec/ftpd/ftpd.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ftpd.c,v 1.14 1996/01/01 08:35:11 peter Exp $ + * $Id: ftpd.c,v 1.15 1996/03/18 11:09:03 davidg Exp $ */ #ifndef lint @@ -100,12 +100,14 @@ static char version[] = "Version 6.00"; extern off_t restart_point; extern char cbuf[]; +struct sockaddr_in server_addr; struct sockaddr_in ctrl_addr; struct sockaddr_in data_source; struct sockaddr_in data_dest; struct sockaddr_in his_addr; struct sockaddr_in pasv_addr; +int daemon_mode; int data; jmp_buf errcatch, urgcatch; int logged_in; @@ -199,6 +201,7 @@ static void send_data __P((FILE *, FILE *, off_t, off_t, int)); static struct passwd * sgetpwnam __P((char *)); static char *sgetsave __P((char *)); +static void reapchild __P((int)); static char * curdir() @@ -225,31 +228,6 @@ main(argc, argv, envp) tzset(); /* in case no timezone database in ~ftp */ - /* - * LOG_NDELAY sets up the logging connection immediately, - * necessary for anonymous ftp's that chroot and can't do it later. - */ - openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); - addrlen = sizeof(his_addr); - if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); - exit(1); - } -#ifdef SKEY - strcpy(addr_string, inet_ntoa(his_addr.sin_addr)); -#endif - addrlen = sizeof(ctrl_addr); - if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); - exit(1); - } -#ifdef IP_TOS - tos = IPTOS_LOWDELAY; - if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); -#endif - data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); - debug = 0; #ifdef OLD_SETPROCTITLE /* * Save start and extent of argv for setproctitle. @@ -262,11 +240,15 @@ main(argc, argv, envp) #ifdef STATS - while ((ch = getopt(argc, argv, "dlSt:T:u:v")) != EOF) { + while ((ch = getopt(argc, argv, "dlDSt:T:u:v")) != EOF) { #else - while ((ch = getopt(argc, argv, "dlUt:T:u:v")) != EOF) { + while ((ch = getopt(argc, argv, "dlDUt:T:u:v")) != EOF) { #endif switch (ch) { + case 'D': + daemon_mode++; + break; + case 'd': debug = 1; break; @@ -316,12 +298,102 @@ main(argc, argv, envp) break; } } + (void) freopen(_PATH_DEVNULL, "w", stderr); - (void) signal(SIGPIPE, lostconn); + + /* + * LOG_NDELAY sets up the logging connection immediately, + * necessary for anonymous ftp's that chroot and can't do it later. + */ + openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); + + if (daemon_mode) { + int ctl_sock, fd; + struct servent *sv; + + /* + * Detach from parent. + */ + if (daemon(1, 1) < 0) { + syslog(LOG_ERR, "failed to become a daemon"); + exit(1); + } + (void) signal(SIGCHLD, reapchild); + /* + * Get port number for ftp/tcp. + */ + sv = getservbyname("ftp", "tcp"); + if (sv == NULL) { + syslog(LOG_ERR, "getservbyname for ftp failed"); + exit(1); + } + /* + * Open a socket, bind it to the FTP port, and start + * listening. + */ + ctl_sock = socket(AF_INET, SOCK_STREAM, 0); + if (ctl_sock < 0) { + syslog(LOG_ERR, "control socket: %m"); + exit(1); + } + if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) + syslog(LOG_ERR, "control setsockopt: %m");; + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = sv->s_port; + if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) { + syslog(LOG_ERR, "control bind: %m"); + exit(1); + } + if (listen(ctl_sock, 32) < 0) { + syslog(LOG_ERR, "control listen: %m"); + exit(1); + } + /* + * Loop forever accepting connection requests and forking off + * children to handle them. + */ + while (1) { + addrlen = sizeof(his_addr); + fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen); + if (fork() == 0) { + /* child */ + (void) dup2(fd, 0); + (void) dup2(fd, 1); + close(ctl_sock); + break; + } + close(fd); + } + } else { + addrlen = sizeof(his_addr); + if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { + syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); + exit(1); + } + } + (void) signal(SIGCHLD, SIG_IGN); + (void) signal(SIGPIPE, lostconn); if ((int)signal(SIGURG, myoob) < 0) syslog(LOG_ERR, "signal: %m"); +#ifdef SKEY + strcpy(addr_string, inet_ntoa(his_addr.sin_addr)); +#endif + addrlen = sizeof(ctrl_addr); + if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { + syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); + exit(1); + } +#ifdef IP_TOS + tos = IPTOS_LOWDELAY; + if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) + syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); +#endif + data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); + /* Try to handle urgent data inline */ #ifdef SO_OOBINLINE if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) @@ -1781,6 +1853,13 @@ out: } } +void +reapchild(signo) + int signo; +{ + while (wait3(NULL, WNOHANG, NULL) > 0); +} + #ifdef OLD_SETPROCTITLE /* * Clobber argv so ps will show what we're doing. (Stolen from sendmail.) |