>FIN_WAIT_2 has no universally mandated timeout in TCP protocol, so some
>OSes keep these sockets indefinitely without cleanup.
This may have been true at one time. However, all the examples I'm seem
imply that the current default timeout is 60 seconds. Also, looking that
the FreeBSD 3.2 sources which are very close to the code used to port the
stack we use, I'm pretty sure can see where the timeout is set to 2 times
the Maximum Segment Lifetime which would be 2 minutes on a system with the
default settings.
>I add, that i've seen that even closing apache the hundreds of sockets
>stay in FIN_WAIT_2 and do not disappear
How long did you wait? I would not be surprised if the timeout was 2
minutes.
You can try the attached and see if it can deal with the sockets stuck in
FIN_WAIT_2. It's basically a manual version of socktidy. Run it as
CloseSocket and give it a list of sockets to close.
I've never tested it against FIN_WAIT_2 sockets, so it might have no
ettect.
Steven
--
----------------------------------------------------------------------
"Steven Levine" <steve53@earthlink.net> Warp/DIY/BlueLion etc.
www.scoug.com www.arcanoae.com www.warpcave.com
----------------------------------------------------------------------
/* CloseSocket - close socket
Copyright (c) 2002-2017 Steven Levine and Associates, Inc.
All rights reserved.
2001-06-14 SHL - Release
2014-06-12 SHL Sync with templates
2016-10-19 SHL Sync with templates
2017-11-30 SHL Correct typo
2017-11-30 SHL Convert to Globals style
2017-11-30 SHL Sync with templates
*/
signal on Error
signal on Failure name Error
signal on Halt
signal on NotReady name Error
signal on NoValue name Error
signal on Syntax name Error
ScanArgsSwitch: procedure expose (Globals) curSw curSwArg
select
when curSw == 'h' | curSw == '?' then
call ScanArgsHelp
when curSw == 'V' then do
say gCmdName gVersion
exit
end
otherwise
call ScanArgsUsage 'switch '''curSw''' unexpected'
end /* select */
ScanArgsArg: procedure expose (Globals) curArg
i = gArgList.0 + 1
gArgList.i = curArg
gArgList.0 = i
return
/* end ScanArgsArg */
/*=== ScanArgsTerm() ScanArgs scan end exit routine ===*/
ScanArgsTerm: procedure expose (Globals)
if gArgList.0 = 0 then
call ScanArgsUsage 'required arguments missing'
return
/* end ScanArgsTerm */
/*=== ScanArgsHelp() Display ScanArgs usage help exit routine ===*/
ScanArgsHelp:
say
say 'Try to close selected sockets.'
say
say 'Usage:' gCmdName '[-h] [-V] [-?] socket...'
say
say ' -h -? Display this message'
say ' -V Display version number and quit'
say
say ' socket Socket to close'
exit 255
ScanArgsUsage:
parse arg msg
say
if msg \== '' then
say msg
say 'Usage:' gCmdName '[-h] [-V] [-?] socket...'
exit 255
/* end ScanArgsUsage */
/*==============================================================================*/
/*=== SkelRexxFunc standards - Delete unused - Move modified above this mark ===*/
/*==============================================================================*/
/*=== DbgMsg([level, ]message,...) Write multi-line message to STDERR if debugging ===*/
DbgMsg: procedure expose (Globals)
level = arg(1)
if datatype(level, 'W') then
start = 2
else do
level = 1
start = 1
end
if level <= gDbgLvl then do
do i = start to arg()
msg = arg(i)
if msg \== '' then
msg = ' *' msg
call lineout 'STDERR', msg
end
end
return
/* end DbgMsg */
/*=== SockCloseX() SockClose wrapper ===*/
SockCloseX: procedure expose (Globals)
call DbgMsg 2, 'SockCloseX: closing' gSock.!Socket
gSock.!rc = SockClose(gSock.!Socket)
s = gSock.!Socket
drop gSock.!Socket /* Drop now to avoid recursion */
if gSock.!rc < 0 then
call SockError 'Close' s
return
if symbol('SIGL') == 'VAR' then
s = s 'at line' SIGL
s = s 'on' date() time('L') || crlf
s2 = s
if symbol('gSock.!HostName') == 'VAR' then
s = s || ' * HostName:' gSock.!HostName || crlf
if symbol('gSock.!Socket') == 'VAR' then
s = s || ' * Socket:' gSock.!Socket || crlf
if symbol('gSock.!ListenSocket') == 'VAR' then
s = s || ' * ListenSocket:' gSock.!ListenSocket || crlf
if symbol('gSock.!Host.!name') == 'VAR' then
s = s || ' * Host.!name:' gSock.!Host.!name || crlf
if symbol('gSock.!Host.!port') == 'VAR' then
s = s || ' * Host.!port:' gSock.!Host.!port || crlf
if symbol('gSock.!Host.!family') == 'VAR' then
s = s || ' * Host.!family:' gSock.!Host.!family || crlf
if symbol('gSock.!Host.!addr') == 'VAR' then
s = s || ' * Host.!addr:' gSock.!Host.!addr || crlf
/* If have useful data, show it */
if s \== s2 then
call lineout 'STDERR', s
return
/* end SockDump */
/*=== SockError(request) Report socket error and shutdown or return ===*/
/* Action depends on gSock.!ErrorAction setting
ABORT - errors are reported, sockets are closed and script exits
REPORT - errors are reported and the function returns to the caller
IGNORE - errors are not reported the function returns to the caller
the default action is abort
*/
SockError:
if symbol('gSock.!ErrorAction') == 'VAR' then
action = translate(gSock.!ErrorAction)
else
action = 'ABORT'
if action = 'IGNORE' then return
parse arg req
if req == '' then
req = 'Socket request'
else
req = 'Sock' || req
SockLoadRxSock:
if RxFuncQuery('SockLoadFuncs') then do
call RxFuncAdd 'SockLoadFuncs', 'RXSOCK', 'SockLoadFuncs'
if RESULT then
call Die 'Cannot load SockLoadFuncs'
call SockLoadFuncs 0
end
return
/* end SockLoadRxSock */
/*==========================================================================*/
/*=== SkelRexx standards - Delete unused - Move modified above this mark ===*/
/*==========================================================================*/
/*=== Error() Set gErrCondition; report to STDOUT; trace and exit or return if called ===*/
Error:
say
parse source . . cmd
gErrCondition = condition('C')
say gErrCondition 'signaled at line' SIGL 'of' cmd'.'
if condition('D') \= '' then
say 'REXX reason =' condition('D')'.'
if gErrCondition == 'SYNTAX' & symbol('RC') == 'VAR' then
say 'REXX error =' RC '-' errortext(RC)'.'
else if symbol('RC') == 'VAR' then
say 'RC =' RC'.'
say 'Source =' sourceline(SIGL)
if condition('I') \== 'CALL' | gErrCondition == 'NOVALUE' | gErrCondition == 'SYNTAX' then do
trace '?A'
say 'Enter REXX commands to debug failure. Press enter to exit script.'
nop
if symbol('RC') \== 'VAR' then
RC = 255
exit RC
end
return
/* end Error */
/*=== Die([message,...]) Write multi-line message to STDERR and die ===*/
Die:
call lineout 'STDERR', ''
do i = 1 to arg()
call lineout 'STDERR', arg(i)
end
call lineout 'STDERR', gCmdName 'aborting at script line' SIGL
call beep 200, 300
call SysSleep 2
exit 254
/* end Die */
/*=== GetCmdName() Get short script name and set gCmdName ===*/
GetCmdName: procedure expose (Globals)
parse source . . cmd
cmd = filespec('N', cmd) /* Chop path */
c = lastpos('.', cmd)
if c > 1 then
cmd = left(cmd, c - 1) /* Chop extension */
gCmdName = translate(cmd, xrange('a', 'z'), xrange('A', 'Z')) /* Lowercase */
return
/* end GetCmdName */
/*=== Halt() Report HALT condition to STDOUT and exit ===*/
Halt:
say
parse source . . cmd
say condition('C') 'signaled at' cmd 'line' SIGL'.'
say 'Source =' sourceline(SIGL)
say 'Sleeping for 2 seconds...'
call SysSleep 2
exit 253
LoadRexxUtil:
if RxFuncQuery('SysLoadFuncs') then do
call RxFuncAdd 'SysLoadFuncs', 'REXXUTIL', 'SysLoadFuncs'
if RESULT then
call Die 'Cannot load SysLoadFuncs'
call SysLoadFuncs
end
return
/* end LoadRexxUtil */
/*=== ScanArgs(cmdLine) Scan command line ===*/
ScanArgs: procedure expose (Globals)
/* Calls user exits to process arguments and switches */
parse arg cmdTail
cmdTail = strip(cmdTail)
call ScanArgsInit
/* Ensure optional settings initialized */
if symbol('SWCTL') \== 'VAR' then
swCtl = '' /* Switches that take args, append ? if optional */
if symbol('KEEPQUOTED') \== 'VAR' then
keepQuoted = 0 /* Set to 1 to keep arguments quoted */
/* Scan */
curArg = '' /* Current arg string */
curSwList = '' /* Current switch list */
/* curSwArg = '' */ /* Current switch argument, if needed */
noMoreSw = 0 /* End of switches */
do while cmdTail \== '' | curArg \== '' | curSwList \== ''
if curArg == '' then do
/* Buffer empty, refill */
qChar = left(cmdTail, 1) /* Remember quote */
if \ verify(qChar,'''"', 'M') then
parse var cmdTail curArg cmdTail /* Not quoted */
else do
/* Arg is quoted */
curArg = ''
do forever
/* Parse dropping quotes */
parse var cmdTail (qChar)quotedPart(qChar) cmdTail
curArg = curArg || quotedPart
/* Check for escaped quote within quoted string (i.e. "" or '') */
if left(cmdTail, 1) \== qChar then
leave /* No, done */
curArg = curArg || qChar /* Append quote */
if keepQuoted then
curArg = curArg || qChar /* Append escaped quote */
parse var cmdTail (qChar) cmdTail
end /* do */
if keepQuoted then
curArg = qChar || curArg || qChar /* requote */
end /* if quoted */
end
/* If switch buffer empty, refill */
if curSwList == '' then do
if left(curArg, 1) == '-' & curArg \== '-' then do
if noMoreSw then
call ScanArgsUsage 'switch '''curArg''' unexpected'
else if curArg == '--' then
noMoreSw = 1
else do
curSwList = substr(curArg, 2) /* Remember switch string */
curArg = '' /* Mark empty */
iterate /* Refill arg buffer */
end
parse var cmdTail curArg cmdTail
end
end
/* If switch in progress */
if curSwList \== '' then do
curSw = left(curSwList, 1) /* Next switch */
curSwList = substr(curSwList, 2) /* Drop from pending */
/* Check switch allows argument, avoid matching ? */
if pos(curSw, translate(swCtl,,'?')) \= 0 then do
if curSwList \== '' then do
curSwArg = curSwList /* Use rest of switch string for switch argument */
curSwList = ''
end
else if curArg \== '' & left(curArg, 1) \== '-' then do
curSwArg = curArg /* Arg string is switch argument */
curArg = '' /* Mark arg string empty */
end
else if pos(curSw'?', swCtl) = 0 then
call ScanArgsUsage 'Switch' curSw 'requires argument'
else
curSwArg = '' /* Optional arg omitted */
end
call ScanArgsSwitch /* Passing curSw and curSwArg */
drop curSwArg /* Must be used by now */
end /* if switch */
/* If arg */
else if curArg \== '' then do
noMoreSw = 1
call ScanArgsArg /* Passing curArg */
curArg = ''
end