From fd2d7bc1a48174e5507e325e21f845d602000fe4 Mon Sep 17 00:00:00 2001 From: Lorenzo Blasa Date: Mon, 11 Apr 2022 07:03:51 -0700 Subject: [PATCH] Attempt to socket connect before establishing websocket connection Summary: ^ Changelog: Check if there's a process listening at the specified port before attempting to establish a websocket connection on iOS Reviewed By: fabiomassimo Differential Revision: D35546817 fbshipit-source-id: 92ccca9afd8bcdc6d79205cc277ac813e0999166 --- iOS/FlipperKit/FlipperPlatformWebSocket.mm | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/iOS/FlipperKit/FlipperPlatformWebSocket.mm b/iOS/FlipperKit/FlipperPlatformWebSocket.mm index 39d09a7a1..3f88ebb9b 100644 --- a/iOS/FlipperKit/FlipperPlatformWebSocket.mm +++ b/iOS/FlipperKit/FlipperPlatformWebSocket.mm @@ -10,6 +10,10 @@ #import "FlipperPlatformWebSocket.h" #import #import +#include +#include +#include +#include static constexpr int connectionKeepaliveSeconds = 10; @@ -140,6 +144,57 @@ static constexpr int connectionKeepaliveSeconds = 10; return; } + // Before attempting to establish a connection, check if + // there is a process listening at the specified port. + // CFNetwork seems to be quite verbose when the host cannot be reached + // causing unnecessary and annoying logs to be printed to the console. + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + struct addrinfo* address; + getaddrinfo( + _url.host.UTF8String, _url.port.stringValue.UTF8String, &hints, &address); + + int sfd = + socket(address->ai_family, address->ai_socktype, address->ai_protocol); + + fcntl(sfd, F_SETFL, O_NONBLOCK); + connect(sfd, address->ai_addr, address->ai_addrlen); + + fd_set fdset; + struct timeval tv; + + FD_ZERO(&fdset); + FD_SET(sfd, &fdset); + // Set a timeout of 3 seconds. + tv.tv_sec = 3; + tv.tv_usec = 0; + + bool listening = false; + if (select(sfd + 1, NULL, &fdset, NULL, &tv) == 1) { + int so_error; + socklen_t len = sizeof so_error; + + getsockopt(sfd, SOL_SOCKET, SO_ERROR, &so_error, &len); + + if (so_error == 0) { + listening = true; + } + // If there's an error, most likely there is no process + // listening at the specified host/port (ECONNREFUSED). + } + + freeaddrinfo(address); + close(sfd); + + if (!listening) { + _eventHandler(facebook::flipper::SocketEvent::ERROR); + return; + } + self.socket = [[SRWebSocket alloc] initWithURL:_url securityPolicy:_policy]; [_socket setDelegate:self]; [_socket open];