summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordg <dg@FreeBSD.org>1996-04-11 10:22:16 +0000
committerdg <dg@FreeBSD.org>1996-04-11 10:22:16 +0000
commit53e950c18529ee4286dcd120640c4544f5651386 (patch)
tree74ce8d143a92773e944580691fd7a7491a4394fe
parent414db770b68b564ca18c187735e992086a5c940f (diff)
downloadFreeBSD-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.
-rw-r--r--libexec/ftpd/ftpd.812
-rw-r--r--libexec/ftpd/ftpd.c137
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.)
OpenPOWER on IntegriCloud