https://bz.apache.org/bugzilla/show_bug.cgi?id=65763
Bug ID: 65763 Summary: WsRemoteEndpointImplBase#sendMessageBlock cannot close session properly when have TimeoutException Product: Tomcat 9 Version: 9.0.44 Hardware: PC OS: Mac OS X 10.1 Status: NEW Severity: normal Priority: P2 Component: WebSocket Assignee: dev@tomcat.apache.org Reporter: qintai....@oceanbase.com Target Milestone: ----- Firstly, I found this exception: #### java.io.IOException: java.util.concurrent.TimeoutException at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:324) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:259) at #### It happens in org.apache.tomcat.websocket.WsRemoteEndpointImplBase#sendMessageBlock(byte, java.nio.ByteBuffer, boolean, long): ###java if (!bsh.getSendResult().isOK()) { messagePartInProgress.release(); Throwable t = bsh.getSendResult().getException(); wsSession.doClose(new CloseReason(CloseCodes.GOING_AWAY, t.getMessage()), new CloseReason(CloseCodes.CLOSED_ABNORMALLY, t.getMessage()), true); throw new IOException (t); } ### Actually, it is caused by org.apache.tomcat.websocket.WsRemoteEndpointImplClient#doWrite which has a LongToIntegerFuture.get timeout exception: ###java try { channel.write(byteBuffer).get(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { handler.onResult(new SendResult(e)); return; } ### But "writing" value is not set to "false" which has been set "true" in org.apache.tomcat.websocket.AsyncChannelWrapperSecure#write(java.nio.ByteBuffer). Only in org.apache.tomcat.websocket.AsyncChannelWrapperSecure.WriteTask, "writing" will be reset to "false", but WriteTask may not finish when LongToIntegerFuture.get timeout happens. This problem may like https://bz.apache.org/bugzilla/show_bug.cgi?id=61003, but writing.set(false) doesn't work in this timeout situation. When WsRemoteEndpointImplBase#sendMessageBlock get TimeoutException, it will try to close session, see "wsSession.doClose(new CloseReason(CloseCodes.GOING_AWAY, t.getMessage())". This method "wsSession.doClose" will set state = State.OUTPUT_CLOSED and send a close message (org.apache.tomcat.websocket.WsSession#sendCloseMessage). But it will case exception, because "writing" value is still "true": ### Caused by: java.lang.IllegalStateException: Concurrent write operations are not permitted at org.apache.tomcat.websocket.AsyncChannelWrapperSecure.write(AsyncChannelWrapperSecure.java:117) at org.apache.tomcat.websocket.WsRemoteEndpointImplClient.doWrite(WsRemoteEndpointImplClient.java:62) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase$OutputBufferSendHandler.write(WsRemoteEndpointImplBase.java:893) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.writeMessagePart(WsRemoteEndpointImplBase.java:506) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:311) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:259) at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:613) at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:498) at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendMessageBlock(WsRemoteEndpointImplBase.java:322) ### In org.apache.tomcat.websocket.WsSession#sendCloseMessage, it doesn't catch IllegalStateException and close websocket channel: ###java try { wsRemoteEndpoint.sendMessageBlock(Constants.OPCODE_CLOSE, msg, true); } catch (IOException | WritePendingException e) { // Failed to send close message. Close the socket and let the caller // deal with the Exception if (log.isDebugEnabled()) { log.debug(sm.getString("wsSession.sendCloseFail", id), e); } wsRemoteEndpoint.close(); ### And this session may cannot be closed again because state has been set to "OUTPUT_CLOSED". I think IllegalStateException should be caught in org.apache.tomcat.websocket.WsSession#sendCloseMessage or a better way to close session when timeout happens. -- You are receiving this mail because: You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org