diff --git a/doc/installation.md b/doc/installation.md index 65be32b..8fabc45 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -371,7 +371,7 @@ DEFVOLUME=PUB001 - `SSLPROXY=YES` is only for a TLS-terminating proxy in front of FTPD. Run bare it promises clients a confidentiality it does not deliver; the member's own comments spell this out. -- `BINDTRIES`/`BINDWAIT` (both 1–100, both default 10) decide how long FTPD +- `BINDTRIES`/`BINDWAIT` (both 1–100, defaulting to 3 and 5) decide how long FTPD keeps trying a listener port it cannot have yet — a port still held, or a stack that is not up. Giving up ends the started task, so raise `BINDTRIES` if `/S FTPD` runs early in an IPL. diff --git a/samplib/ftpdprm0 b/samplib/ftpdprm0 index 29405eb..47dc3d0 100644 --- a/samplib/ftpdprm0 +++ b/samplib/ftpdprm0 @@ -25,16 +25,16 @@ PASVPORTS=22000-22200 # # A bind() that fails for a reason waiting can fix -- the port still held # by something, or the stack not up yet at IPL -- is retried BINDTRIES -# times, BINDWAIT seconds apart. Both 1-100, both default 10, so FTPD -# waits up to 100 seconds before giving up. +# times, BINDWAIT seconds apart. Both 1-100; the defaults 3 and 5 give +# FTPD 15 seconds before it gives up. # # Giving up ends the started task (FTPD056E): an FTPD that cannot listen # has nothing left to do, and no console command re-tries the bind. So # these two decide how much transient trouble a start survives. Raise # BINDTRIES where FTPD is started before TCP/IP is reliably up. # -BINDTRIES=10 -BINDWAIT=10 +BINDTRIES=3 +BINDWAIT=5 # # PASVBIND is where the passive listener binds, PASVADR is what the # client is told to connect to -- they are only the same by default. diff --git a/src/ftpd#cfg.c b/src/ftpd#cfg.c index 5d12458..c46e5e4 100644 --- a/src/ftpd#cfg.c +++ b/src/ftpd#cfg.c @@ -30,9 +30,23 @@ ftpdcfg_defaults(ftpd_config_t *cfg) strcpy(cfg->pasv_bind, "ANY"); /* bind every address, as before */ cfg->pasv_lo = 22000; cfg->pasv_hi = 22200; - cfg->bind_tries = 10; /* HTTPD's defaults: up to 100s of - ** patience before the STC ends */ - cfg->bind_wait = 10; + /* 15 seconds of patience, not HTTPD's 100. HTTPD's number predates a + ** stale port sweep: there, a repeated bind was the only defence against + ** a port a dead instance still held. Here close_stale_port() has + ** already cleared that case before the retry loop is reached (#109), so + ** what still answers EADDRINUSE afterwards is most likely a LIVE foreign + ** listener -- and waiting on one does not help, it does not go away. + ** + ** The cost of waiting also changed: since #111 a bind that never + ** succeeds ends the STC, so the operator who typed /S and is watching + ** the console waits out the whole budget for a verdict. 15 seconds + ** covers TIME_WAIT and a tight restart; a failed start is recognisable + ** as one while someone is still looking at it. + ** + ** The one case that wants far more patience is EADDRNOTAVAIL early in an + ** IPL, and that is what raising BINDTRIES is for. */ + cfg->bind_tries = 3; + cfg->bind_wait = 5; /* Limits */ cfg->max_sessions = 10; cfg->idle_timeout = 300; diff --git a/src/ftpd.c b/src/ftpd.c index c919ac6..0150306 100644 --- a/src/ftpd.c +++ b/src/ftpd.c @@ -459,10 +459,12 @@ bind_retryable(int err) ** give up early when the server is being stopped. ** ** The step is what makes /P work during a retry run. BINDTRIES x -** BINDWAIT can now be 100 seconds; terminate() waits 10 for the socket -** thread and then says FTPD095W SOCKET THREAD DID NOT TERMINATE, so a -** thread asleep in one long STIMER would make every longer retry setting -** worse for the operator than the short one it replaced. +** BINDWAIT is 15 seconds by default but goes to 100 x 100 -- and the +** sites that raise it are exactly the ones that will need to interrupt +** it. terminate() waits 10 seconds for the socket thread and then says +** FTPD095W SOCKET THREAD DID NOT TERMINATE, so a thread asleep in one +** long STIMER would make every longer retry setting worse for the +** operator than the short one it replaced. ** ** Returns 0 when the wait completed, -1 when shutdown was signalled. ** ----------------------------------------------------------------- */