@@ -358,7 +358,6 @@ void AsyncWebSocketClient::_onAck(size_t len, uint32_t time) {
358358
359359void AsyncWebSocketClient::_onPoll () {
360360 asyncsrv::unique_lock_type lock (_lock);
361-
362361 if (!_client) {
363362 return ;
364363 }
@@ -446,7 +445,6 @@ bool AsyncWebSocketClient::canSend() const {
446445
447446bool AsyncWebSocketClient::_queueControl (uint8_t opcode, const uint8_t *data, size_t len, bool mask) {
448447 asyncsrv::lock_guard_type lock (_lock);
449-
450448 if (!_client) {
451449 return false ;
452450 }
@@ -463,7 +461,6 @@ bool AsyncWebSocketClient::_queueControl(uint8_t opcode, const uint8_t *data, si
463461
464462bool AsyncWebSocketClient::_queueMessage (AsyncWebSocketSharedBuffer buffer, uint8_t opcode, bool mask) {
465463 asyncsrv::unique_lock_type lock (_lock);
466-
467464 if (!_client || !buffer || buffer->empty () || _status != WS_CONNECTED) {
468465 return false ;
469466 }
@@ -952,7 +949,6 @@ bool AsyncWebSocketClient::binary(const __FlashStringHelper *data, size_t len) {
952949
953950IPAddress AsyncWebSocketClient::remoteIP () const {
954951 asyncsrv::lock_guard_type lock (_lock);
955-
956952 if (!_client) {
957953 return IPAddress ((uint32_t )0U );
958954 }
@@ -962,7 +958,6 @@ IPAddress AsyncWebSocketClient::remoteIP() const {
962958
963959uint16_t AsyncWebSocketClient::remotePort () const {
964960 asyncsrv::lock_guard_type lock (_lock);
965-
966961 if (!_client) {
967962 return 0 ;
968963 }
@@ -991,14 +986,10 @@ AsyncWebSocketClient *AsyncWebSocket::_newClient(AsyncWebServerRequest *request)
991986}
992987
993988void AsyncWebSocket::_handleDisconnect (AsyncWebSocketClient *client) {
994- asyncsrv::lock_guard_type lock (_lock);
995- const auto client_id = client->id ();
996- const auto iter = std::find_if (std::begin (_clients), std::end (_clients), [client_id](const AsyncWebSocketClient &c) {
997- return c.id () == client_id;
998- });
999- if (iter != std::end (_clients)) {
1000- _clients.erase (iter);
1001- }
989+ (void )client;
990+ // Defer removal to cleanupClients(). Disconnect callbacks can fire while
991+ // iterating _clients for broadcast sends, and erasing here invalidates the
992+ // active iterator in the caller.
1002993}
1003994
1004995bool AsyncWebSocket::availableForWriteAll () {
@@ -1055,17 +1046,30 @@ void AsyncWebSocket::closeAll(uint16_t code, const char *message) {
10551046}
10561047
10571048void AsyncWebSocket::cleanupClients (uint16_t maxClients) {
1058- asyncsrv::lock_guard_type lock (_lock);
1059- const size_t c = count ();
1060- if (c > maxClients) {
1061- async_ws_log_v (" [%s] CLEANUP %" PRIu32 " (%u/%" PRIu16 " )" , _url.c_str (), _clients.front ().id (), c, maxClients);
1062- _clients.front ().close ();
1063- }
1049+ std::list<AsyncWebSocketClient> removed_clients;
1050+ {
1051+ asyncsrv::lock_guard_type lock (_lock);
1052+ const size_t connected = std::count_if (std::begin (_clients), std::end (_clients), [](const AsyncWebSocketClient &c) {
1053+ return c.status () == WS_CONNECTED;
1054+ });
1055+
1056+ if (connected > maxClients) {
1057+ const auto connected_iter = std::find_if (std::begin (_clients), std::end (_clients), [](const AsyncWebSocketClient &c) {
1058+ return c.status () == WS_CONNECTED;
1059+ });
1060+ if (connected_iter != std::end (_clients)) {
1061+ async_ws_log_v (" [%s] CLEANUP %" PRIu32 " (%u/%" PRIu16 " )" , _url.c_str (), connected_iter->id (), connected, maxClients);
1062+ connected_iter->close ();
1063+ }
1064+ }
10641065
1065- for (auto i = _clients.begin (); i != _clients.end (); ++i) {
1066- if (i->shouldBeDeleted ()) {
1067- _clients.erase (i);
1068- break ;
1066+ for (auto iter = _clients.begin (); iter != _clients.end ();) {
1067+ if (iter->shouldBeDeleted ()) {
1068+ auto current = iter++;
1069+ removed_clients.splice (removed_clients.end (), _clients, current);
1070+ } else {
1071+ ++iter;
1072+ }
10691073 }
10701074 }
10711075}
0 commit comments