Skip to content

Commit e0926e9

Browse files
committed
New version 1.2.26; fixes mostly around WebSocket handling
1 parent fed1648 commit e0926e9

File tree

15 files changed

+141
-60
lines changed

15 files changed

+141
-60
lines changed

client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>org.red5</groupId>
55
<artifactId>red5-parent</artifactId>
6-
<version>1.2.25</version>
6+
<version>1.2.26</version>
77
</parent>
88
<modelVersion>4.0.0</modelVersion>
99
<artifactId>red5-client</artifactId>

client/src/main/java/org/red5/client/Red5Client.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public final class Red5Client {
1818
/**
1919
* Current server version with revision
2020
*/
21-
public static final String VERSION = "Red5 Client 1.2.25";
21+
public static final String VERSION = "Red5 Client 1.2.26";
2222

2323
/**
2424
* Create a new Red5Client object using the connection local to the current thread A bit of magic that lets you access the red5 scope

common/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>org.red5</groupId>
55
<artifactId>red5-parent</artifactId>
6-
<version>1.2.25</version>
6+
<version>1.2.26</version>
77
</parent>
88
<modelVersion>4.0.0</modelVersion>
99
<artifactId>red5-server-common</artifactId>

common/src/main/java/org/red5/server/api/Red5.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ public final class Red5 {
5555
/**
5656
* Server version with revision
5757
*/
58-
public static final String VERSION = "Red5 Server 1.2.25";
58+
public static final String VERSION = "Red5 Server 1.2.26";
5959

6060
/**
6161
* Server version for fmsVer requests
6262
*/
63-
public static final String FMS_VERSION = "RED5/1,2,25,0";
63+
public static final String FMS_VERSION = "RED5/1,2,26,0";
6464

6565
/**
6666
* Server capabilities

io/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>org.red5</groupId>
55
<artifactId>red5-parent</artifactId>
6-
<version>1.2.25</version>
6+
<version>1.2.26</version>
77
</parent>
88
<modelVersion>4.0.0</modelVersion>
99
<artifactId>red5-io</artifactId>

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<name>Red5</name>
2424
<description>The Red5 server</description>
2525
<groupId>org.red5</groupId>
26-
<version>1.2.25</version>
26+
<version>1.2.26</version>
2727
<url>https://github.com/Red5/red5-server</url>
2828
<inceptionYear>2005</inceptionYear>
2929
<organization>

server/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<parent>
44
<groupId>org.red5</groupId>
55
<artifactId>red5-parent</artifactId>
6-
<version>1.2.25</version>
6+
<version>1.2.26</version>
77
</parent>
88
<modelVersion>4.0.0</modelVersion>
99
<artifactId>red5-server</artifactId>

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

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import java.util.HashMap;
1616
import java.util.List;
1717
import java.util.Map;
18-
import java.util.Objects;
1918
import java.util.Optional;
2019
import java.util.concurrent.ConcurrentHashMap;
2120
import java.util.concurrent.Future;
@@ -60,7 +59,13 @@ public class WebSocketConnection extends AttributeStore {
6059
// associated websocket session
6160
private final WsSession wsSession;
6261

63-
private String httpSessionId;
62+
private final WebSocketScope scope;
63+
64+
// unique identifier for the session
65+
private final String wsSessionId;
66+
67+
// unique identifier for this instance based upon the websocket session id
68+
private final int hashCode;
6469

6570
private String host;
6671

@@ -96,12 +101,16 @@ public class WebSocketConnection extends AttributeStore {
96101
private final static AtomicLongFieldUpdater<WebSocketConnection> writeUpdater = AtomicLongFieldUpdater.newUpdater(WebSocketConnection.class, "writtenBytes");
97102

98103
public WebSocketConnection(WebSocketScope scope, Session session) {
104+
// set the scope for ease of use later
105+
this.scope = scope;
99106
// set our path
100107
path = scope.getPath();
101108
// cast ws session
102109
this.wsSession = (WsSession) session;
103-
// set the local session id
104-
httpSessionId = Optional.ofNullable(wsSession.getHttpSessionId()).orElse(wsSession.getId());
110+
// the websocket session id will be used for hash code comparison, its the only usable value currently
111+
wsSessionId = wsSession.getId();
112+
hashCode = Integer.valueOf(wsSessionId);
113+
log.info("wsSessionId: {}", wsSessionId);
105114
// get extensions
106115
wsSession.getNegotiatedExtensions().forEach(extension -> {
107116
if (extensions == null) {
@@ -259,26 +268,24 @@ public void sendPong(byte[] buf) throws IllegalArgumentException, IOException {
259268
public void close() {
260269
if (connected.compareAndSet(true, false)) {
261270
// TODO disconnect from scope etc...
271+
scope.removeConnection(this);
262272
// normal close
263273
if (wsSession.isOpen()) {
264274
try {
265275
wsSession.close();
266-
} catch (IOException e) {
276+
} catch (Exception e) {
267277
}
268278
}
269279
}
270280
}
271281

272-
public long getReadBytes() {
273-
return readBytes;
274-
}
275-
276-
public void updateReadBytes(long read) {
277-
readUpdater.addAndGet(this, read);
278-
}
279-
280-
public long getWrittenBytes() {
281-
return writtenBytes;
282+
/**
283+
* Return the WebSocketScope to which we're connected/connecting.
284+
*
285+
* @return WebSocketScope
286+
*/
287+
public WebSocketScope getScope() {
288+
return scope;
282289
}
283290

284291
/**
@@ -357,25 +364,29 @@ public void setPath(String path) {
357364
* @return sessionId
358365
*/
359366
public String getSessionId() {
360-
return wsSession.getId();
367+
return wsSessionId;
361368
}
362369

363370
/**
364371
* Sets / overrides this connections HttpSession id.
365372
*
366373
* @param httpSessionId
374+
* @deprecated Session id read from WSSession
367375
*/
376+
@Deprecated(since = "1.2.26")
368377
public void setHttpSessionId(String httpSessionId) {
369-
this.httpSessionId = httpSessionId;
378+
//this.httpSessionId = httpSessionId;
370379
}
371380

372381
/**
373382
* Returns the HttpSession id associated with this connection.
374383
*
375384
* @return sessionId
385+
* @deprecated Session id read from WSSession
376386
*/
387+
@Deprecated(since = "1.2.26")
377388
public String getHttpSessionId() {
378-
return httpSessionId;
389+
return wsSessionId;
379390
}
380391

381392
/**
@@ -526,9 +537,21 @@ public WsSession getWsSession() {
526537
return wsSession;
527538
}
528539

540+
public long getReadBytes() {
541+
return readBytes;
542+
}
543+
544+
public void updateReadBytes(long read) {
545+
readUpdater.addAndGet(this, read);
546+
}
547+
548+
public long getWrittenBytes() {
549+
return writtenBytes;
550+
}
551+
529552
@Override
530553
public int hashCode() {
531-
return Objects.hash(httpSessionId);
554+
return hashCode;
532555
}
533556

534557
@Override
@@ -540,16 +563,16 @@ public boolean equals(Object obj) {
540563
if (getClass() != obj.getClass())
541564
return false;
542565
WebSocketConnection other = (WebSocketConnection) obj;
543-
return Objects.equals(httpSessionId, other.httpSessionId);
566+
return hashCode == other.hashCode();
544567
}
545568

546569
@Override
547570
public String toString() {
548-
if (wsSession != null && connected.get()) {
549-
return "WebSocketConnection [wsId=" + wsSession.getId() + ", sessionId=" + httpSessionId + ", host=" + host + ", origin=" + origin + ", path=" + path + ", secure=" + isSecure() + ", connected=" + connected + "]";
571+
if (wsSessionId != null) {
572+
return "WebSocketConnection [wsId=" + wsSessionId + ", host=" + host + ", origin=" + origin + ", path=" + path + ", secure=" + isSecure() + ", connected=" + connected + "]";
550573
}
551574
if (wsSession == null) {
552-
return "WebSocketConnection [wsId=not-set, sessionId=not-set, host=" + host + ", origin=" + origin + ", path=" + path + ", secure=not-set, connected=" + connected + "]";
575+
return "WebSocketConnection [wsId=not-set, host=" + host + ", origin=" + origin + ", path=" + path + ", secure=not-set, connected=" + connected + "]";
553576
}
554577
return "WebSocketConnection [host=" + host + ", origin=" + origin + ", path=" + path + " connected=false]";
555578
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.red5.server.api.listeners.IScopeListener;
3838
import org.red5.server.api.scope.IScope;
3939
import org.red5.server.api.scope.ScopeType;
40+
import org.red5.server.plugin.PluginRegistry;
4041
import org.red5.server.plugin.Red5Plugin;
4142
import org.red5.server.util.ScopeUtils;
4243
import org.slf4j.Logger;
@@ -129,6 +130,7 @@ public void notifyScopeRemoved(IScope scope) {
129130
@Override
130131
public void doStop() throws Exception {
131132
log.trace("WebSocketPlugin stop");
133+
PluginRegistry.unregister(this);
132134
managerMap.entrySet().forEach(entry -> {
133135
entry.getValue().stop();
134136
});
@@ -264,8 +266,8 @@ public WebSocketScopeManager getManager(String path) {
264266
if (parts.length > 1) {
265267
// skip default in a path if it exists in slot #1
266268
String name = !"default".equals(parts[1]) ? parts[1] : ((parts.length >= 3) ? parts[2] : parts[1]);
267-
if (log.isDebugEnabled()) {
268-
log.debug("Managers: {}", managerMap.entrySet());
269+
if (log.isTraceEnabled()) {
270+
log.trace("Managers: {}", managerMap.entrySet());
269271
}
270272
for (Entry<IScope, WebSocketScopeManager> entry : managerMap.entrySet()) {
271273
IScope appScope = entry.getKey();
@@ -410,7 +412,7 @@ public static ServerContainer getWsServerContainerInstance(ServletContext servle
410412
try {
411413
// locate the endpoint class
412414
Class<?> endpointClass = Class.forName(wsEndpointClass);
413-
log.debug("startWebSocket - endpointPath: {} endpointClass: {}", path, endpointClass);
415+
log.debug("startWebSocket - endpointPath: {} endpointClass: {}", path, wsEndpointClass);
414416
// build an endpoint config
415417
ServerEndpointConfig serverEndpointConfig = ServerEndpointConfig.Builder.create(endpointClass, path).configurator(configurator).subprotocols(subProtocols).build();
416418
// set the endpoint on the server container

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

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.red5.net.websocket.model.WSMessage;
1818
import org.red5.server.api.scope.IScope;
1919
import org.red5.server.plugin.PluginRegistry;
20+
import org.red5.server.util.ScopeUtils;
2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
2223
import org.springframework.beans.factory.DisposableBean;
@@ -31,6 +32,8 @@ public class WebSocketScope implements InitializingBean, DisposableBean {
3132

3233
private static Logger log = LoggerFactory.getLogger(WebSocketScope.class);
3334

35+
private WebSocketScopeManager manager;
36+
3437
protected CopyOnWriteArraySet<WebSocketConnection> conns = new CopyOnWriteArraySet<>();
3538

3639
protected CopyOnWriteArraySet<IWebSocketDataListener> listeners = new CopyOnWriteArraySet<>();
@@ -63,7 +66,8 @@ public void destroy() throws Exception {
6366
*/
6467
public void register() {
6568
log.info("Application scope: {}", scope);
66-
WebSocketScopeManager manager = ((WebSocketPlugin) PluginRegistry.getPlugin(WebSocketPlugin.NAME)).getManager(scope);
69+
// get the manager on registration and keep a reference locally
70+
manager = ((WebSocketPlugin) PluginRegistry.getPlugin(WebSocketPlugin.NAME)).getManager(scope);
6771
if (manager.setApplication(scope)) {
6872
log.info("WebSocket app added: {}", scope.getName());
6973
}
@@ -76,6 +80,12 @@ public void register() {
7680
* Un-registers from the WebSocketScopeManager.
7781
*/
7882
public void unregister() {
83+
// remove app scope registration only if we're an app scope
84+
if (ScopeUtils.isApp(scope)) {
85+
manager.removeApplication(scope);
86+
}
87+
// remove ourself
88+
manager.removeWebSocketScope(this);
7989
// clean up the connections by first closing them
8090
conns.forEach(conn -> {
8191
conn.close();
@@ -95,7 +105,8 @@ public void unregister() {
95105
* @return WebSocketConnection for the given id or null if not found
96106
*/
97107
public WebSocketConnection getConnectionBySessionId(String id) {
98-
Optional<WebSocketConnection> opt = conns.stream().filter(conn -> id.equals(conn.getHttpSessionId())).findFirst();
108+
log.debug("getConnectionBySessionId: {}", id);
109+
Optional<WebSocketConnection> opt = conns.stream().filter(conn -> id.equals(conn.getSessionId())).findFirst();
99110
if (opt.isPresent()) {
100111
return opt.get();
101112
}
@@ -155,12 +166,18 @@ public String getPath() {
155166
* @param conn WebSocketConnection
156167
*/
157168
public void addConnection(WebSocketConnection conn) {
158-
if (conns.add(conn)) {
159-
for (IWebSocketDataListener listener : listeners) {
160-
listener.onWSConnect(conn);
169+
// prevent false failed logging when a connection is already registered
170+
if (!conns.contains(conn)) {
171+
if (conns.add(conn)) {
172+
log.debug("Added connection: {}", conn);
173+
for (IWebSocketDataListener listener : listeners) {
174+
listener.onWSConnect(conn);
175+
}
176+
} else {
177+
log.warn("Add connection failed for: {}", conn);
161178
}
162179
} else {
163-
log.warn("Add connection failed for: {}", conn);
180+
log.debug("Add connection skipped, already registered: {}", conn);
164181
}
165182
}
166183

@@ -170,12 +187,18 @@ public void addConnection(WebSocketConnection conn) {
170187
* @param conn WebSocketConnection
171188
*/
172189
public void removeConnection(WebSocketConnection conn) {
173-
if (conns.remove(conn)) {
174-
for (IWebSocketDataListener listener : listeners) {
175-
listener.onWSDisconnect(conn);
190+
// prevent false failed logging when a connection isnt registered
191+
if (conns.contains(conn)) {
192+
if (conns.remove(conn)) {
193+
log.debug("Removed connection: {}", conn);
194+
for (IWebSocketDataListener listener : listeners) {
195+
listener.onWSDisconnect(conn);
196+
}
197+
} else {
198+
log.warn("Remove connection failed for: {}", conn);
176199
}
177200
} else {
178-
log.warn("Remove connection failed for: {}", conn);
201+
log.debug("Remove connection skipped, not registered: {}", conn);
179202
}
180203
}
181204

@@ -185,7 +208,7 @@ public void removeConnection(WebSocketConnection conn) {
185208
* @param listener IWebSocketDataListener
186209
*/
187210
public void addListener(IWebSocketDataListener listener) {
188-
log.info("addListener: {}", listener);
211+
log.debug("addListener to {}: {}", path, listener);
189212
listeners.add(listener);
190213
}
191214

@@ -195,7 +218,7 @@ public void addListener(IWebSocketDataListener listener) {
195218
* @param listener IWebSocketDataListener
196219
*/
197220
public void removeListener(IWebSocketDataListener listener) {
198-
log.info("removeListener: {}", listener);
221+
log.debug("removeListener from {}: {}", path, listener);
199222
listeners.remove(listener);
200223
}
201224

@@ -206,7 +229,7 @@ public void removeListener(IWebSocketDataListener listener) {
206229
* list of IWebSocketDataListener
207230
*/
208231
public void setListeners(Collection<IWebSocketDataListener> listeners) {
209-
log.trace("setListeners: {}", listeners);
232+
log.trace("setListeners on {}: {}", path, listeners);
210233
this.listeners.addAll(listeners);
211234
}
212235

0 commit comments

Comments
 (0)