浏览代码

fix: use a reentrant lock when accessing active connections (#11256)

Claus Vium 1 年之前
父节点
当前提交
4201079b34

+ 11 - 9
Emby.Server.Implementations/HttpServer/WebSocketManager.cs

@@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.HttpServer
 
                 WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false);
 
-                using var connection = new WebSocketConnection(
+                var connection = new WebSocketConnection(
                     _loggerFactory.CreateLogger<WebSocketConnection>(),
                     webSocket,
                     authorizationInfo,
@@ -56,17 +56,19 @@ namespace Emby.Server.Implementations.HttpServer
                 {
                     OnReceive = ProcessWebSocketMessageReceived
                 };
-
-                var tasks = new Task[_webSocketListeners.Length];
-                for (var i = 0; i < _webSocketListeners.Length; ++i)
+                await using (connection.ConfigureAwait(false))
                 {
-                    tasks[i] = _webSocketListeners[i].ProcessWebSocketConnectedAsync(connection, context);
-                }
+                    var tasks = new Task[_webSocketListeners.Length];
+                    for (var i = 0; i < _webSocketListeners.Length; ++i)
+                    {
+                        tasks[i] = _webSocketListeners[i].ProcessWebSocketConnectedAsync(connection, context);
+                    }
 
-                await Task.WhenAll(tasks).ConfigureAwait(false);
+                    await Task.WhenAll(tasks).ConfigureAwait(false);
 
-                await connection.ReceiveAsync().ConfigureAwait(false);
-                _logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress);
+                    await connection.ReceiveAsync().ConfigureAwait(false);
+                    _logger.LogInformation("WS {IP} closed", context.Connection.RemoteIpAddress);
+                }
             }
             catch (Exception ex) // Otherwise ASP.Net will ignore the exception
             {

+ 6 - 31
MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs

@@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Net
             SingleWriter = false
         });
 
-        private readonly SemaphoreSlim _lock = new(1, 1);
+        private readonly object _activeConnectionsLock = new();
 
         /// <summary>
         /// The _active connections.
@@ -126,15 +126,10 @@ namespace MediaBrowser.Controller.Net
                 InitialDelayMs = dueTimeMs
             };
 
-            _lock.Wait();
-            try
+            lock (_activeConnectionsLock)
             {
                 _activeConnections.Add((message.Connection, cancellationTokenSource, state));
             }
-            finally
-            {
-                _lock.Release();
-            }
         }
 
         protected void SendData(bool force)
@@ -153,8 +148,7 @@ namespace MediaBrowser.Controller.Net
                         (IWebSocketConnection Connection, CancellationTokenSource CancellationTokenSource, TStateType State)[] tuples;
 
                         var now = DateTime.UtcNow;
-                        await _lock.WaitAsync().ConfigureAwait(false);
-                        try
+                        lock (_activeConnectionsLock)
                         {
                             if (_activeConnections.Count == 0)
                             {
@@ -174,10 +168,6 @@ namespace MediaBrowser.Controller.Net
                                 })
                                 .ToArray();
                         }
-                        finally
-                        {
-                            _lock.Release();
-                        }
 
                         if (tuples.Length == 0)
                         {
@@ -240,8 +230,7 @@ namespace MediaBrowser.Controller.Net
         /// <param name="message">The message.</param>
         private void Stop(WebSocketMessageInfo message)
         {
-            _lock.Wait();
-            try
+            lock (_activeConnectionsLock)
             {
                 var connection = _activeConnections.FirstOrDefault(c => c.Connection == message.Connection);
 
@@ -250,10 +239,6 @@ namespace MediaBrowser.Controller.Net
                     DisposeConnection(connection);
                 }
             }
-            finally
-            {
-                _lock.Release();
-            }
         }
 
         /// <summary>
@@ -283,15 +268,10 @@ namespace MediaBrowser.Controller.Net
                 Logger.LogError(ex, "Error disposing websocket");
             }
 
-            _lock.Wait();
-            try
+            lock (_activeConnectionsLock)
             {
                 _activeConnections.Remove(connection);
             }
-            finally
-            {
-                _lock.Release();
-            }
         }
 
         protected virtual async ValueTask DisposeAsyncCore()
@@ -306,18 +286,13 @@ namespace MediaBrowser.Controller.Net
                 Logger.LogError(ex, "Disposing the message consumer failed");
             }
 
-            await _lock.WaitAsync().ConfigureAwait(false);
-            try
+            lock (_activeConnectionsLock)
             {
                 foreach (var connection in _activeConnections.ToArray())
                 {
                     DisposeConnection(connection);
                 }
             }
-            finally
-            {
-                _lock.Release();
-            }
         }
 
         /// <inheritdoc />