Repository navigation
fix(websocket): prevent reconnect timer multiplication and port exhaustion in RCTReconnectingWebSocket (#58988) - #59055
Conversation
|
Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
Summary:
Fixes #58988
In development mode on iOS,
RCTReconnectingWebSocketmanages the WebSocket connection between the app and the Metro packager (/message?role=ios).When the target port answers with an HTTP error (e.g. 404/500 from a non-Metro service) instead of refusing the TCP connection ($2^N$ ):
ECONNREFUSED), reconnect timers previously multiplied exponentially (reconnect,startwas scheduled viadispatch_after.startcalledstop, releasing_socket.if (!socket)evaluated totrue(becausesocketwas captured as a__weakpointer to_socket), scheduling a second reconnect timer.SocketRocketdelivers viawebSocket:didFailWithError:.didFailWithError:re-armed for every error code other thanECONNREFUSED, scheduling another timer.Within minutes, ~15,000 TCP sockets entered
TIME_WAIT, completely exhausting the host's ephemeral ports and breaking all local network connections on macOS withcan't assign requested address.Solution:
if (!socket) { [weakSelf reconnect]; }._reconnectPendingguard: Guarantees at most one reconnect timer is queued at any time.InspectorPackagerConnection.cpp. Resets to 2.0s upon successful connection (webSocketDidOpen:).[error code] != ECONNREFUSEDexception; all failures are handled cleanly with backoff._reconnectToken): Invalidates pending timers ifstopor manualstartoccurs.webSocket != _socket.Changelog:
[IOS] [FIXED] - Prevent reconnect timer multiplication and host ephemeral port exhaustion in RCTReconnectingWebSocket
Test Plan:
State Machine & Invariant Simulation:
Simulated rapid reconnection failure cycles under HTTP 404 responses.
webSocketDidOpen:.reconnect()is rejected when_stoppedisYES.iOS Dev Client Verification:
python3 -m http.server 8081).netstat -an | grep ':8081 .*TIME_WAIT'