Problem
TomcatAcceptFixConfig.FixedServerSocketChannel successfully detects TCP/IP stack restarts on z/OS and rebinds the Tomcat accept() socket. However, it does nothing for existing client connections that were already accepted before the disruption.
Root cause
FixedServerSocketChannel.accept() at line 277 returns a bare socket.accept() — an unwrapped SocketChannel. This is the accept socket only. Client connections accepted through it are plain JDK SocketChannel instances managed by Tomcat's NIO poller, with no TCP stack restart awareness.
Impact
When the z/OS TCP/IP stack restarts:
| Concern |
Behavior |
Accept socket (ServerSocketChannel) |
accept() throws EDC5122I/NetworkRecycledException → rebind() creates new socket ✅ |
Existing client connections (SocketChannel) |
fd invalid at kernel level, but no detection on read/write ❌ |
| Listening port |
Stays in LISTEN (kernel artifact, not fd-based) → netstat shows LISTEN |
| Client experience |
ETIMEDOUT rather than ECONNREFUSED (because new connections are accepted on the rebound port) |
This is the trigger of production incidents where Discovery Service registration connections hang indefinitely after a z/OS TCP/IP stack hiccup.
Affected code
apiml-tomcat-common/src/main/java/org/zowe/apiml/product/web/TomcatAcceptFixConfig.java — FixedServerSocketChannel.accept() (line 273–287)
- No other class in the entire
api-layer codebase handles TCP stack recovery for client connections
Javadoc limitation acknowledged
Lines 40–43 of the Javadoc state: "It tries accepting new request, and it fails until the service is restarted" — the word "new" implicitly acknowledges that only the accept socket is covered.
Problem
TomcatAcceptFixConfig.FixedServerSocketChannelsuccessfully detects TCP/IP stack restarts on z/OS and rebinds the Tomcataccept()socket. However, it does nothing for existing client connections that were already accepted before the disruption.Root cause
FixedServerSocketChannel.accept()at line 277 returns a baresocket.accept()— an unwrappedSocketChannel. This is the accept socket only. Client connections accepted through it are plain JDKSocketChannelinstances managed by Tomcat's NIO poller, with no TCP stack restart awareness.Impact
When the z/OS TCP/IP stack restarts:
ServerSocketChannel)accept()throwsEDC5122I/NetworkRecycledException→rebind()creates new socket ✅SocketChannel)LISTEN(kernel artifact, not fd-based) →netstatshows LISTENETIMEDOUTrather thanECONNREFUSED(because new connections are accepted on the rebound port)This is the trigger of production incidents where Discovery Service registration connections hang indefinitely after a z/OS TCP/IP stack hiccup.
Affected code
apiml-tomcat-common/src/main/java/org/zowe/apiml/product/web/TomcatAcceptFixConfig.java—FixedServerSocketChannel.accept()(line 273–287)api-layercodebase handles TCP stack recovery for client connectionsJavadoc limitation acknowledged
Lines 40–43 of the Javadoc state: "It tries accepting new request, and it fails until the service is restarted" — the word "new" implicitly acknowledges that only the accept socket is covered.