Skip to content

Commit 96e5548

Browse files
committed
Add session open check at ws close to prevent ex
1 parent 88f09ba commit 96e5548

3 files changed

Lines changed: 46 additions & 24 deletions

File tree

server/src/main/java/org/red5/net/websocket/server/DefaultWebSocketEndpoint.java

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,7 @@
1111
import java.io.IOException;
1212
import java.io.UnsupportedEncodingException;
1313
import java.nio.ByteBuffer;
14-
15-
import jakarta.websocket.CloseReason;
16-
import jakarta.websocket.Endpoint;
17-
import jakarta.websocket.EndpointConfig;
18-
import jakarta.websocket.MessageHandler;
19-
import jakarta.websocket.PongMessage;
20-
import jakarta.websocket.Session;
14+
import java.util.Map;
2115

2216
import org.apache.mina.core.buffer.IoBuffer;
2317
import org.red5.net.websocket.WSConstants;
@@ -27,6 +21,13 @@
2721
import org.slf4j.Logger;
2822
import org.slf4j.LoggerFactory;
2923

24+
import jakarta.websocket.CloseReason;
25+
import jakarta.websocket.Endpoint;
26+
import jakarta.websocket.EndpointConfig;
27+
import jakarta.websocket.MessageHandler;
28+
import jakarta.websocket.PongMessage;
29+
import jakarta.websocket.Session;
30+
3031
/**
3132
* Default WebSocket endpoint.
3233
*
@@ -37,28 +38,34 @@ public class DefaultWebSocketEndpoint extends Endpoint {
3738
private final Logger log = LoggerFactory.getLogger(DefaultWebSocketEndpoint.class);
3839

3940
@SuppressWarnings("unused")
40-
private final boolean isDebug = log.isDebugEnabled();
41-
42-
private final boolean isTrace = log.isTraceEnabled();
41+
private final boolean isDebug = log.isDebugEnabled(), isTrace = log.isTraceEnabled();
4342

4443
// websocket scope where connections connect
4544
private WebSocketScope scope;
4645

4746
/**
48-
* TODO: Currently, Tomcat uses an Endpoint instance once - however the java doc of endpoint says: "Each instance of a websocket endpoint is guaranteed not to be called by more
49-
* than one thread at a time per active connection." This could mean that after calling onClose(), the instance could be reused for another connection so onOpen() will get
50-
* called (possibly from another thread).<br>
51-
* If this is the case, we would need a variable holder for the variables that are accessed by the Room thread, and read the reference to the holder at the beginning of onOpen,
47+
* TODO: Currently, Tomcat uses an Endpoint instance once - however the java doc of endpoint says: "Each instance
48+
* of a websocket endpoint is guaranteed not to be called by more than one thread at a time per active connection."
49+
* This could mean that after calling onClose(), the instance could be reused for another connection so onOpen()
50+
* will get called (possibly from another thread).<br>If this is the case, we would need a variable holder for the
51+
* variables that are accessed by the Room thread, and read the reference to the holder at the beginning of onOpen,
5252
* onMessage, onClose methods to ensure the room thread always gets the correct instance of the variable holder.
5353
*/
5454

5555
@Override
5656
public void onOpen(Session session, EndpointConfig config) {
57-
log.debug("Session opened: {}\n{}", session.getId(), session.getRequestParameterMap());
57+
if (isDebug) {
58+
log.debug("Session opened: {}\n{}", session.getId(), session.getRequestParameterMap());
59+
}
60+
Map<String, Object> confUserProps = config.getUserProperties();
61+
Map<String, Object> sessionUserProps = session.getUserProperties();
62+
if (isTrace) {
63+
log.trace("User conf props: {}\nsession props: {}", confUserProps, sessionUserProps);
64+
}
5865
// get ws scope from user props
59-
scope = (WebSocketScope) config.getUserProperties().get(WSConstants.WS_SCOPE);
66+
scope = (WebSocketScope) confUserProps.get(WSConstants.WS_SCOPE);
6067
// get ws connection from session user props
61-
WebSocketConnection conn = (WebSocketConnection) session.getUserProperties().get(WSConstants.WS_CONNECTION);
68+
WebSocketConnection conn = (WebSocketConnection) sessionUserProps.get(WSConstants.WS_CONNECTION);
6269
if (conn == null) {
6370
log.warn("WebSocketConnection null at onOpen for {}", session.getId());
6471
}
@@ -69,13 +76,24 @@ public void onOpen(Session session, EndpointConfig config) {
6976

7077
@Override
7178
public void onClose(Session session, CloseReason closeReason) {
72-
final String sessionId = session.getId();
73-
log.debug("Session closed: {}", sessionId);
7479
WebSocketConnection conn = null;
7580
// getting the sessions user properties on a closed connection will throw an exception when it checks state
7681
try {
82+
Map<String, Object> sessionUserProps = session.getUserProperties();
83+
if (isTrace) {
84+
log.trace("User session props: {}", sessionUserProps);
85+
}
86+
// ensure we grab the scope from the session if its null
87+
if (scope == null) {
88+
scope = (WebSocketScope) sessionUserProps.get(WSConstants.WS_SCOPE);
89+
log.trace("Scope pulled from session: {}", scope);
90+
}
91+
String sessionId = session.getId();
92+
if (isDebug) {
93+
log.debug("Session closed: {} on scope: {}", sessionId, scope);
94+
}
7795
// get ws connection from session user props
78-
conn = (WebSocketConnection) session.getUserProperties().get(WSConstants.WS_CONNECTION);
96+
conn = (WebSocketConnection) sessionUserProps.get(WSConstants.WS_CONNECTION);
7997
// if we don't get it from the session, try the scope lookup
8098
if (conn == null) {
8199
log.warn("Connection for id: {} was not found in the session onClose", sessionId);
@@ -88,10 +106,12 @@ public void onClose(Session session, CloseReason closeReason) {
88106
log.warn("Exception in onClose", e);
89107
} finally {
90108
if (conn != null) {
91-
// force remove on exception
92-
scope.removeConnection(conn);
93109
// fire close, to be sure
94110
conn.close();
111+
// force remove on exception
112+
if (scope != null) {
113+
scope.removeConnection(conn);
114+
}
95115
}
96116
}
97117
}

server/src/main/java/org/red5/net/websocket/server/DefaultWsServerContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ protected void registerSession(Object endpoint, WsSession wsSession) {
287287
*/
288288
@Override
289289
protected void unregisterSession(Object endpoint, WsSession wsSession) {
290-
if (wsSession.getUserPrincipal() != null && wsSession.getHttpSessionId() != null) {
290+
if (wsSession.isOpen() && wsSession.getHttpSessionId() != null && wsSession.getUserPrincipal() != null) {
291291
unregisterAuthenticatedSession(wsSession, wsSession.getHttpSessionId());
292292
log.debug("unregisterSession - unregisterAuthenticatedSession: {}", wsSession.getId());
293293
}

server/src/main/java/org/red5/server/net/rtmp/RTMPConnManager.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ public void destroy() throws Exception {
221221
if (checkerFuture != null && !checkerFuture.isDone()) {
222222
checkerFuture.cancel(true);
223223
}
224-
executor.shutdownNow();
224+
if (executor != null) {
225+
executor.shutdownNow();
226+
}
225227
}
226228

227229
}

0 commit comments

Comments
 (0)