Socket connect no longer synchronous and blocking
Summary: Never really liked this code. Before this change, calls to connect were blocking. Because of this, we had to make use of promises and a bit of really not that good-looking code. So, this change makes connect non-blocking meaning that we make full use of our event handler. These changes contain: - CSR is not getting generated after each failed attempt. - Connect is no longer blocking. - Do not report events via the handler when explicitly disconnecting. Reviewed By: jknoxville Differential Revision: D46853228 fbshipit-source-id: 00e6a9c7c039a756175fe14982959e078d92bacb
This commit is contained in:
committed by
Facebook GitHub Bot
parent
65e515bdaa
commit
e42db220ee
@@ -276,9 +276,9 @@ class JFlipperWebSocket : public facebook::flipper::FlipperSocket {
|
||||
messageHandler_ = std::move(messageHandler);
|
||||
}
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) override {
|
||||
virtual void connect(FlipperConnectionManager* manager) override {
|
||||
if (socket_ != nullptr) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string connectionURL = endpoint_.secure ? "wss://" : "ws://";
|
||||
@@ -297,38 +297,9 @@ class JFlipperWebSocket : public facebook::flipper::FlipperSocket {
|
||||
|
||||
auto secure = endpoint_.secure;
|
||||
|
||||
std::promise<bool> promise;
|
||||
auto connected = promise.get_future();
|
||||
|
||||
connecting_ = true;
|
||||
|
||||
socket_ = make_global(JFlipperSocketImpl::create(connectionURL));
|
||||
socket_->setEventHandler(JFlipperSocketEventHandlerImpl::newObjectCxxArgs(
|
||||
[this, &promise, eventHandler = eventHandler_](SocketEvent event) {
|
||||
/**
|
||||
Only fulfill the promise the first time the event handler is used.
|
||||
If the open event is received, then set the promise value to true.
|
||||
For any other event, consider a failure and set to false.
|
||||
*/
|
||||
if (this->connecting_) {
|
||||
this->connecting_ = false;
|
||||
if (event == SocketEvent::OPEN) {
|
||||
promise.set_value(true);
|
||||
} else if (event == SocketEvent::SSL_ERROR) {
|
||||
try {
|
||||
promise.set_exception(
|
||||
std::make_exception_ptr(folly::AsyncSocketException(
|
||||
folly::AsyncSocketException::SSL_ERROR,
|
||||
"SSL handshake failed")));
|
||||
} catch (...) {
|
||||
// set_exception() may throw an exception
|
||||
// In that case, just set the value to false.
|
||||
promise.set_value(false);
|
||||
}
|
||||
} else {
|
||||
promise.set_value(false);
|
||||
}
|
||||
}
|
||||
[eventHandler = eventHandler_](SocketEvent event) {
|
||||
eventHandler(event);
|
||||
},
|
||||
[messageHandler = messageHandler_](const std::string& message) {
|
||||
@@ -348,8 +319,6 @@ class JFlipperWebSocket : public facebook::flipper::FlipperSocket {
|
||||
return JFlipperObject::create(std::move(object_));
|
||||
}));
|
||||
socket_->connect();
|
||||
|
||||
return connected.get();
|
||||
}
|
||||
|
||||
virtual void disconnect() override {
|
||||
@@ -409,7 +378,6 @@ class JFlipperWebSocket : public facebook::flipper::FlipperSocket {
|
||||
facebook::flipper::SocketMessageHandler messageHandler_;
|
||||
|
||||
jni::global_ref<JFlipperSocketImpl> socket_;
|
||||
bool connecting_;
|
||||
};
|
||||
|
||||
class JFlipperSocketProvider : public facebook::flipper::FlipperSocketProvider {
|
||||
|
||||
@@ -117,7 +117,7 @@ class FlipperSocketImpl extends WebSocketClient implements FlipperSocket {
|
||||
|
||||
this.connect();
|
||||
} catch (Exception e) {
|
||||
Log.e("Flipper", "Failed to initialize the socket before connect. " + e.getMessage());
|
||||
Log.e("flipper", "Failed to initialize the socket before connect. Error: " + e.getMessage());
|
||||
this.mEventHandler.onConnectionEvent(FlipperSocketEventHandler.SocketEvent.ERROR);
|
||||
}
|
||||
}
|
||||
@@ -139,6 +139,13 @@ class FlipperSocketImpl extends WebSocketClient implements FlipperSocket {
|
||||
|
||||
@Override
|
||||
public void onClose(int code, String reason, boolean remote) {
|
||||
/**
|
||||
* If the socket is not yet open, don't report the close event. Usually, onError is invoked
|
||||
* instead which is the one that needs reporting.
|
||||
*/
|
||||
if (!this.isOpen()) {
|
||||
return;
|
||||
}
|
||||
this.mEventHandler.onConnectionEvent(FlipperSocketEventHandler.SocketEvent.CLOSE);
|
||||
}
|
||||
|
||||
@@ -162,7 +169,6 @@ class FlipperSocketImpl extends WebSocketClient implements FlipperSocket {
|
||||
|
||||
@Override
|
||||
public void flipperDisconnect() {
|
||||
this.mEventHandler.onConnectionEvent(FlipperSocketEventHandler.SocketEvent.CLOSE);
|
||||
this.mEventHandler =
|
||||
new FlipperSocketEventHandler() {
|
||||
@Override
|
||||
|
||||
@@ -181,11 +181,6 @@ static constexpr int connectionKeepaliveSeconds = 10;
|
||||
|
||||
[_dispatchQueue cancelAllOperations];
|
||||
[_dispatchQueue waitUntilAllOperationsAreFinished];
|
||||
|
||||
// Manually trigger a 'close' event as SocketRocket close method will
|
||||
// not notify the delegate. SocketRocket only triggers the close event
|
||||
// when the connection is closed from the server.
|
||||
_eventHandler(facebook::flipper::SocketEvent::CLOSE);
|
||||
}
|
||||
|
||||
- (void)send:(NSString*)message
|
||||
|
||||
@@ -39,7 +39,7 @@ class FlipperWebSocket : public FlipperSocket {
|
||||
virtual void setEventHandler(SocketEventHandler eventHandler) override;
|
||||
virtual void setMessageHandler(SocketMessageHandler messageHandler) override;
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||
virtual void connect(FlipperConnectionManager* manager) override;
|
||||
virtual void disconnect() override;
|
||||
|
||||
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||
|
||||
@@ -53,9 +53,9 @@ void FlipperWebSocket::setMessageHandler(SocketMessageHandler messageHandler) {
|
||||
messageHandler_ = std::move(messageHandler);
|
||||
}
|
||||
|
||||
bool FlipperWebSocket::connect(FlipperConnectionManager* manager) {
|
||||
void FlipperWebSocket::connect(FlipperConnectionManager* manager) {
|
||||
if (socket_ != NULL) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string connectionURL = endpoint_.secure ? "wss://" : "ws://";
|
||||
@@ -72,43 +72,16 @@ bool FlipperWebSocket::connect(FlipperConnectionManager* manager) {
|
||||
connectionURL += payload;
|
||||
}
|
||||
|
||||
__block bool fullfilled = false;
|
||||
__block std::promise<bool> promise;
|
||||
auto connected = promise.get_future();
|
||||
|
||||
NSURL* urlObjc = [NSURL
|
||||
URLWithString:[NSString stringWithUTF8String:connectionURL.c_str()]];
|
||||
|
||||
auto eventHandler = eventHandler_;
|
||||
socket_ = [[FlipperPlatformWebSocket alloc] initWithURL:urlObjc];
|
||||
socket_.eventHandler = ^(SocketEvent event) {
|
||||
/**
|
||||
Only fulfill the promise the first time the event handler is used. If the
|
||||
open event is received, then set the promise value to true. For any other
|
||||
event, consider a failure and set to false.
|
||||
*/
|
||||
if (!fullfilled) {
|
||||
fullfilled = true;
|
||||
if (event == SocketEvent::OPEN) {
|
||||
promise.set_value(true);
|
||||
} else if (event == SocketEvent::SSL_ERROR) {
|
||||
try {
|
||||
promise.set_exception(
|
||||
std::make_exception_ptr(SSLException("SSL handshake failed")));
|
||||
} catch (...) {
|
||||
// set_exception() may throw an exception
|
||||
// In that case, just set the value to false.
|
||||
promise.set_value(false);
|
||||
}
|
||||
} else {
|
||||
promise.set_value(false);
|
||||
}
|
||||
}
|
||||
eventHandler(event);
|
||||
eventHandler_(event);
|
||||
};
|
||||
auto messageHandler = messageHandler_;
|
||||
|
||||
socket_.messageHandler = ^(const std::string& message) {
|
||||
messageHandler(message);
|
||||
messageHandler_(message);
|
||||
};
|
||||
|
||||
if (endpoint_.secure) {
|
||||
@@ -124,8 +97,6 @@ bool FlipperWebSocket::connect(FlipperConnectionManager* manager) {
|
||||
}
|
||||
|
||||
[socket_ connect];
|
||||
|
||||
return connected.get();
|
||||
}
|
||||
|
||||
void FlipperWebSocket::disconnect() {
|
||||
@@ -157,9 +128,9 @@ void FlipperWebSocket::send(
|
||||
}
|
||||
|
||||
/**
|
||||
Only ever used for insecure connections to receive the device_id from a
|
||||
signCertificate request. If the intended usage ever changes, then a better
|
||||
approach needs to be put in place.
|
||||
* Only ever used for insecure connections to receive the device_id from a
|
||||
* signCertificate request. If the intended usage ever changes, then a better
|
||||
* approach needs to be put in place.
|
||||
*/
|
||||
void FlipperWebSocket::sendExpectResponse(
|
||||
const std::string& message,
|
||||
|
||||
@@ -65,7 +65,7 @@ class FlipperReactBaseSocket {
|
||||
messageHandler_ = std::move(messageHandler);
|
||||
}
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) = 0;
|
||||
virtual void connect(FlipperConnectionManager* manager) = 0;
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
virtual void send(
|
||||
|
||||
@@ -55,8 +55,8 @@ void FlipperReactSocket::setMessageHandler(
|
||||
socket_->setMessageHandler(messageHandler);
|
||||
}
|
||||
|
||||
bool FlipperReactSocket::connect(FlipperConnectionManager* manager) {
|
||||
return socket_->connect(manager);
|
||||
void FlipperReactSocket::connect(FlipperConnectionManager* manager) {
|
||||
socket_->connect(manager);
|
||||
}
|
||||
|
||||
void FlipperReactSocket::disconnect() {
|
||||
|
||||
@@ -37,7 +37,7 @@ class FlipperReactSocket : public FlipperSocket {
|
||||
virtual void setEventHandler(SocketEventHandler eventHandler) override;
|
||||
virtual void setMessageHandler(SocketMessageHandler messageHandler) override;
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||
virtual void connect(FlipperConnectionManager* manager) override;
|
||||
virtual void disconnect() override;
|
||||
|
||||
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||
|
||||
@@ -134,9 +134,9 @@ FlipperReactSocketClient::getClientCertificate() {
|
||||
return installClientCertificate();
|
||||
}
|
||||
|
||||
bool FlipperReactSocketClient::connect(FlipperConnectionManager* manager) {
|
||||
void FlipperReactSocketClient::connect(FlipperConnectionManager* manager) {
|
||||
if (status_ != Status::Unconnected) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
status_ = Status::Connecting;
|
||||
@@ -176,30 +176,34 @@ bool FlipperReactSocketClient::connect(FlipperConnectionManager* manager) {
|
||||
socket_.Closed({this, &FlipperReactSocketClient::OnWebSocketClosed});
|
||||
|
||||
try {
|
||||
this->socket_.ConnectAsync(winrt::Windows::Foundation::Uri(uri))
|
||||
.wait_for(std::chrono::seconds(10));
|
||||
|
||||
status_ = Status::Initializing;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::OPEN); });
|
||||
|
||||
return true;
|
||||
Windows::Foundation::IAsyncAction ^ connectAction;
|
||||
connectAction =
|
||||
this->socket_.ConnectAsync(winrt::Windows::Foundation::Uri(uri));
|
||||
connectAction->Completed = ref new AsyncActionCompletedHandler(
|
||||
[eventHandler = eventHandler_](
|
||||
Windows::Foundation::IAsyncAction ^ asyncAction,
|
||||
Windows::Foundation::AsyncStatus asyncStatus) {
|
||||
if (asyncStatus == Windows::Foundation::AsyncStatus::Completed) {
|
||||
eventHandler(SocketEvent::OPEN);
|
||||
} else {
|
||||
eventHandler(SocketEvent::ERROR);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (winrt::hresult_error const& ex) {
|
||||
winrt::Windows::Web::WebErrorStatus webErrorStatus{
|
||||
winrt::Windows::Networking::Sockets::WebSocketError::GetStatus(
|
||||
ex.to_abi())};
|
||||
socket_ = nullptr;
|
||||
status_ = Status::Unconnected;
|
||||
eventHandler(SocketEvent::ERROR);
|
||||
}
|
||||
|
||||
disconnect();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FlipperReactSocketClient::disconnect() {
|
||||
status_ = Status::Closed;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||
// socket_.Close();
|
||||
socket_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -269,14 +273,10 @@ void FlipperReactSocketClient::OnWebSocketMessageReceived(
|
||||
const std::string payload = winrt::to_string(message);
|
||||
|
||||
if (overrideHandler_ != nullptr) {
|
||||
scheduler_->schedule([payload, messageHandler = *overrideHandler_]() {
|
||||
messageHandler(payload, false);
|
||||
});
|
||||
messageHandler(payload, false);
|
||||
overrideHandler_ = nullptr;
|
||||
} else if (messageHandler_) {
|
||||
scheduler_->schedule([payload, messageHandler = messageHandler_]() {
|
||||
messageHandler(payload);
|
||||
});
|
||||
messageHandler(payload);
|
||||
}
|
||||
} catch (winrt::hresult_error const& ex) {
|
||||
// winrt::Windows::Web::WebErrorStatus webErrorStatus{
|
||||
@@ -291,8 +291,7 @@ void FlipperReactSocketClient::OnWebSocketClosed(
|
||||
return;
|
||||
}
|
||||
status_ = Status::Closed;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||
eventHandler(SocketEvent::CLOSE);
|
||||
}
|
||||
|
||||
} // namespace flipper
|
||||
|
||||
@@ -40,7 +40,7 @@ class FlipperReactSocketClient : public FlipperReactBaseSocket {
|
||||
|
||||
virtual ~FlipperReactSocketClient();
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||
virtual void connect(FlipperConnectionManager* manager) override;
|
||||
virtual void disconnect() override;
|
||||
|
||||
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||
@@ -61,7 +61,6 @@ class FlipperReactSocketClient : public FlipperReactBaseSocket {
|
||||
args);
|
||||
|
||||
private:
|
||||
std::promise<bool> connected_;
|
||||
winrt::Windows::Networking::Sockets::MessageWebSocket socket_;
|
||||
winrt::event_token messageReceivedEventToken_;
|
||||
winrt::event_token closedEventToken_;
|
||||
|
||||
@@ -48,7 +48,8 @@ bool ConnectionContextStore::hasRequiredFiles() {
|
||||
std::string config =
|
||||
loadStringFromFile(absoluteFilePath(CONNECTION_CONFIG_FILE));
|
||||
|
||||
if (caCert == "" || clientCert == "" || privateKey == "" || config == "") {
|
||||
if (caCert.empty() || clientCert.empty() || privateKey.empty() ||
|
||||
config.empty()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -56,14 +57,14 @@ bool ConnectionContextStore::hasRequiredFiles() {
|
||||
|
||||
std::string ConnectionContextStore::getCertificateSigningRequest() {
|
||||
// Use in-memory CSR if already loaded
|
||||
if (csr != "") {
|
||||
return csr;
|
||||
if (!csr_.empty()) {
|
||||
return csr_;
|
||||
}
|
||||
|
||||
// Attempt to load existing CSR from previous run of the app
|
||||
csr = loadStringFromFile(absoluteFilePath(CSR_FILE_NAME));
|
||||
if (csr != "") {
|
||||
return csr;
|
||||
csr_ = loadStringFromFile(absoluteFilePath(CSR_FILE_NAME));
|
||||
if (!csr_.empty()) {
|
||||
return csr_;
|
||||
}
|
||||
|
||||
// Clean all state and generate a new one
|
||||
@@ -75,9 +76,9 @@ std::string ConnectionContextStore::getCertificateSigningRequest() {
|
||||
if (!success) {
|
||||
throw new std::runtime_error("Failed to generate CSR");
|
||||
}
|
||||
csr = loadStringFromFile(absoluteFilePath(CSR_FILE_NAME));
|
||||
csr_ = loadStringFromFile(absoluteFilePath(CSR_FILE_NAME));
|
||||
|
||||
return csr;
|
||||
return csr_;
|
||||
}
|
||||
|
||||
std::string ConnectionContextStore::getDeviceId() {
|
||||
@@ -124,7 +125,8 @@ void ConnectionContextStore::storeConnectionConfig(folly::dynamic& config) {
|
||||
writeStringToFile(json, absoluteFilePath(CONNECTION_CONFIG_FILE));
|
||||
}
|
||||
|
||||
std::string ConnectionContextStore::absoluteFilePath(const char* filename) {
|
||||
std::string ConnectionContextStore::absoluteFilePath(
|
||||
const char* filename) const {
|
||||
#ifndef WIN32
|
||||
return std::string(deviceData_.privateAppDirectory + "/sonar/" + filename);
|
||||
#else
|
||||
@@ -159,7 +161,7 @@ std::string ConnectionContextStore::getPath(StoreItem storeItem) {
|
||||
|
||||
bool ConnectionContextStore::resetState() {
|
||||
// Clear in-memory state
|
||||
csr = "";
|
||||
csr_ = "";
|
||||
|
||||
// Delete state from disk
|
||||
std::string dirPath = absoluteFilePath("");
|
||||
@@ -208,6 +210,18 @@ std::pair<std::string, std::string> ConnectionContextStore::getCertificate() {
|
||||
return std::make_pair(certificate_path, std::string(CERTIFICATE_PASSWORD));
|
||||
}
|
||||
|
||||
bool ConnectionContextStore::hasCertificateSigningRequest() const {
|
||||
std::string csr = loadStringFromFile(absoluteFilePath(CSR_FILE_NAME));
|
||||
return !csr.empty();
|
||||
}
|
||||
|
||||
bool ConnectionContextStore::hasClientCertificate() const {
|
||||
std::string clientCertificate =
|
||||
loadStringFromFile(absoluteFilePath(CLIENT_CERT_FILE_NAME));
|
||||
|
||||
return !clientCertificate.empty();
|
||||
}
|
||||
|
||||
std::string loadStringFromFile(std::string fileName) {
|
||||
if (!fileExists(fileName)) {
|
||||
return "";
|
||||
|
||||
@@ -57,11 +57,18 @@ class ConnectionContextStore {
|
||||
*/
|
||||
std::pair<std::string, std::string> getCertificate();
|
||||
|
||||
/** Is there a CSR present.
|
||||
*/
|
||||
bool hasCertificateSigningRequest() const;
|
||||
/** Is there a client certificate present.
|
||||
*/
|
||||
bool hasClientCertificate() const;
|
||||
|
||||
private:
|
||||
DeviceData deviceData_;
|
||||
std::string csr = "";
|
||||
std::string csr_ = "";
|
||||
|
||||
std::string absoluteFilePath(const char* filename);
|
||||
std::string absoluteFilePath(const char* filename) const;
|
||||
};
|
||||
|
||||
} // namespace flipper
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
#define WRONG_THREAD_EXIT_MSG \
|
||||
"ERROR: Aborting flipper initialization because it's not running in the flipper thread."
|
||||
|
||||
static constexpr int reconnectIntervalSeconds = 2;
|
||||
static constexpr int RECONNECT_INTERVAL_SECONDS = 3;
|
||||
|
||||
// Not a public-facing version number.
|
||||
// Used for compatibility checking with desktop flipper.
|
||||
// To be bumped for every core platform interface change.
|
||||
static constexpr int sdkVersion = 4;
|
||||
static constexpr int SDK_VERSION = 4;
|
||||
|
||||
using namespace folly;
|
||||
|
||||
@@ -66,14 +66,14 @@ FlipperConnectionManagerImpl::FlipperConnectionManagerImpl(
|
||||
std::shared_ptr<FlipperState> state,
|
||||
std::shared_ptr<ConnectionContextStore> contextStore)
|
||||
: deviceData_(config.deviceData),
|
||||
flipperState_(state),
|
||||
state_(state),
|
||||
insecurePort(config.insecurePort),
|
||||
securePort(config.securePort),
|
||||
altInsecurePort(config.altInsecurePort),
|
||||
altSecurePort(config.altSecurePort),
|
||||
flipperScheduler_(config.callbackWorker),
|
||||
scheduler_(config.callbackWorker),
|
||||
connectionScheduler_(config.connectionWorker),
|
||||
contextStore_(contextStore),
|
||||
store_(contextStore),
|
||||
implWrapper_(std::make_shared<FlipperConnectionManagerWrapper>(this)) {
|
||||
CHECK_THROW(config.callbackWorker, std::invalid_argument);
|
||||
CHECK_THROW(config.connectionWorker, std::invalid_argument);
|
||||
@@ -85,39 +85,52 @@ FlipperConnectionManagerImpl::~FlipperConnectionManagerImpl() {
|
||||
|
||||
void FlipperConnectionManagerImpl::setCertificateProvider(
|
||||
const std::shared_ptr<FlipperCertificateProvider> provider) {
|
||||
certProvider_ = provider;
|
||||
certificateProvider_ = provider;
|
||||
};
|
||||
|
||||
std::shared_ptr<FlipperCertificateProvider>
|
||||
FlipperConnectionManagerImpl::getCertificateProvider() {
|
||||
return certProvider_;
|
||||
return certificateProvider_;
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::handleSocketEvent(SocketEvent event) {
|
||||
switch (event) {
|
||||
case SocketEvent::OPEN:
|
||||
isConnected_ = true;
|
||||
if (connectionIsTrusted_) {
|
||||
callbacks_->onConnected();
|
||||
}
|
||||
break;
|
||||
case SocketEvent::SSL_ERROR:
|
||||
// SSL errors are not handled as a connection event
|
||||
// on this handler.
|
||||
break;
|
||||
case SocketEvent::CLOSE:
|
||||
case SocketEvent::ERROR:
|
||||
if (!isConnected_) {
|
||||
return;
|
||||
}
|
||||
isConnected_ = false;
|
||||
if (connectionIsTrusted_) {
|
||||
connectionIsTrusted_ = false;
|
||||
callbacks_->onDisconnected();
|
||||
}
|
||||
reconnect();
|
||||
break;
|
||||
}
|
||||
// Ensure that the event is handled on the correct thread i.e. scheduler.
|
||||
scheduler_->schedule([this, event]() {
|
||||
switch (event) {
|
||||
case SocketEvent::OPEN:
|
||||
isConnected_ = true;
|
||||
if (isConnectionTrusted_) {
|
||||
failedConnectionAttempts_ = 0;
|
||||
callbacks_->onConnected();
|
||||
} else {
|
||||
requestSignedCertificate();
|
||||
}
|
||||
break;
|
||||
case SocketEvent::SSL_ERROR:
|
||||
log("[conn] handleSocketEvent(SSL_ERROR)");
|
||||
failedConnectionAttempts_++;
|
||||
reconnect();
|
||||
break;
|
||||
case SocketEvent::CLOSE:
|
||||
case SocketEvent::ERROR:
|
||||
log("[conn] handleSocketEvent(CLOSE_ERROR)");
|
||||
if (!isConnected_) {
|
||||
reconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
failedConnectionAttempts_++;
|
||||
isConnected_ = false;
|
||||
|
||||
if (isConnectionTrusted_) {
|
||||
isConnectionTrusted_ = false;
|
||||
callbacks_->onDisconnected();
|
||||
}
|
||||
|
||||
reconnect();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::start() {
|
||||
@@ -126,22 +139,22 @@ void FlipperConnectionManagerImpl::start() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isStarted_) {
|
||||
if (started_) {
|
||||
log("Already started");
|
||||
return;
|
||||
}
|
||||
isStarted_ = true;
|
||||
started_ = true;
|
||||
|
||||
auto step = flipperState_->start("Start connection thread");
|
||||
auto step = state_->start("Start connection thread");
|
||||
|
||||
flipperScheduler_->schedule([this, step]() {
|
||||
scheduler_->schedule([this, step]() {
|
||||
step->complete();
|
||||
startSync();
|
||||
});
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::startSync() {
|
||||
if (!isStarted_) {
|
||||
if (!started_) {
|
||||
log("Not started");
|
||||
return;
|
||||
}
|
||||
@@ -153,52 +166,28 @@ void FlipperConnectionManagerImpl::startSync() {
|
||||
log("Already connected");
|
||||
return;
|
||||
}
|
||||
|
||||
socket_ = nullptr;
|
||||
|
||||
bool isClientSetupStep = isCertificateExchangeNeeded();
|
||||
auto step = flipperState_->start(
|
||||
isClientSetupStep ? "Establish pre-setup connection"
|
||||
auto step = state_->start(
|
||||
isClientSetupStep ? "Establish certificate exchange connection"
|
||||
: "Establish main connection");
|
||||
try {
|
||||
if (isClientSetupStep) {
|
||||
bool success = connectAndExchangeCertificate();
|
||||
if (!success) {
|
||||
reconnect();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!connectSecurely()) {
|
||||
// The expected code path when flipper desktop is not running.
|
||||
// Don't count as a failed attempt, or it would invalidate the
|
||||
// connection files for no reason. On iOS devices, we can always connect
|
||||
// to the local port forwarding server even when it can't connect to
|
||||
// flipper. In that case we get a Network error instead of a Port not
|
||||
// open error, so we treat them the same.
|
||||
step->fail(
|
||||
"No route to flipper found. Is flipper desktop running? Retrying...");
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
step->complete();
|
||||
} catch (const SSLException& e) {
|
||||
auto message = std::string(e.what()) +
|
||||
"\nMake sure the date and time of your device is up to date.";
|
||||
log(message);
|
||||
step->fail(message);
|
||||
failedConnectionAttempts_++;
|
||||
reconnect();
|
||||
} catch (const std::exception& e) {
|
||||
log(e.what());
|
||||
step->fail(e.what());
|
||||
failedConnectionAttempts_++;
|
||||
reconnect();
|
||||
if (isClientSetupStep) {
|
||||
connectAndExchangeCertificate();
|
||||
} else {
|
||||
connectSecurely();
|
||||
}
|
||||
step->complete();
|
||||
}
|
||||
|
||||
bool FlipperConnectionManagerImpl::connectAndExchangeCertificate() {
|
||||
void FlipperConnectionManagerImpl::connectAndExchangeCertificate() {
|
||||
log("[conn] connectAndExchangeCertificate()");
|
||||
auto port = insecurePort;
|
||||
auto endpoint = FlipperConnectionEndpoint(deviceData_.host, port, false);
|
||||
|
||||
int medium = certProvider_ != nullptr
|
||||
? certProvider_->getCertificateExchangeMedium()
|
||||
int medium = certificateProvider_ != nullptr
|
||||
? certificateProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
|
||||
auto payload = std::make_unique<FlipperSocketBasePayload>();
|
||||
@@ -206,47 +195,31 @@ bool FlipperConnectionManagerImpl::connectAndExchangeCertificate() {
|
||||
payload->device = deviceData_.device;
|
||||
payload->device_id = "unknown";
|
||||
payload->app = deviceData_.app;
|
||||
payload->sdk_version = sdkVersion;
|
||||
payload->sdk_version = SDK_VERSION;
|
||||
payload->medium = medium;
|
||||
|
||||
client_ = FlipperSocketProvider::socketCreate(
|
||||
endpoint, std::move(payload), flipperScheduler_);
|
||||
client_->setEventHandler(ConnectionEvents(implWrapper_));
|
||||
socket_ = FlipperSocketProvider::socketCreate(
|
||||
endpoint, std::move(payload), scheduler_);
|
||||
socket_->setEventHandler(ConnectionEvents(implWrapper_));
|
||||
|
||||
connectionIsTrusted_ = false;
|
||||
|
||||
auto step =
|
||||
flipperState_->start("Attempt to connect for certificate exchange");
|
||||
isConnectionTrusted_ = false;
|
||||
|
||||
auto step = state_->start("Attempt to connect for certificate exchange");
|
||||
step->complete();
|
||||
|
||||
// NON-TLS:
|
||||
// On failure: clear the client.
|
||||
// On success: proceed to request the client certificate.
|
||||
|
||||
// Connect is just handled here, move this elsewhere.
|
||||
if (!client_->connect(this)) {
|
||||
client_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
requestSignedCertificate();
|
||||
|
||||
return true;
|
||||
socket_->connect(this);
|
||||
}
|
||||
|
||||
bool FlipperConnectionManagerImpl::connectSecurely() {
|
||||
client_ = nullptr;
|
||||
|
||||
void FlipperConnectionManagerImpl::connectSecurely() {
|
||||
auto port = securePort;
|
||||
auto endpoint = FlipperConnectionEndpoint(deviceData_.host, port, true);
|
||||
|
||||
int medium = certProvider_ != nullptr
|
||||
? certProvider_->getCertificateExchangeMedium()
|
||||
int medium = certificateProvider_ != nullptr
|
||||
? certificateProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
|
||||
auto loadingDeviceId = flipperState_->start("Load Device Id");
|
||||
auto deviceId = contextStore_->getDeviceId();
|
||||
auto loadingDeviceId = state_->start("Load Device Id");
|
||||
auto deviceId = store_->getDeviceId();
|
||||
if (deviceId.compare("unknown")) {
|
||||
loadingDeviceId->complete();
|
||||
}
|
||||
@@ -256,15 +229,15 @@ bool FlipperConnectionManagerImpl::connectSecurely() {
|
||||
payload->device = deviceData_.device;
|
||||
payload->device_id = deviceId;
|
||||
payload->app = deviceData_.app;
|
||||
payload->sdk_version = sdkVersion;
|
||||
payload->sdk_version = SDK_VERSION;
|
||||
payload->medium = medium;
|
||||
payload->csr = contextStore_->getCertificateSigningRequest().c_str();
|
||||
payload->csr_path = contextStore_->getCertificateDirectoryPath().c_str();
|
||||
payload->csr = store_->getCertificateSigningRequest().c_str();
|
||||
payload->csr_path = store_->getCertificateDirectoryPath().c_str();
|
||||
|
||||
client_ = FlipperSocketProvider::socketCreate(
|
||||
endpoint, std::move(payload), connectionScheduler_, contextStore_.get());
|
||||
client_->setEventHandler(ConnectionEvents(implWrapper_));
|
||||
client_->setMessageHandler([this](const std::string& msg) {
|
||||
socket_ = FlipperSocketProvider::socketCreate(
|
||||
endpoint, std::move(payload), connectionScheduler_, store_.get());
|
||||
socket_->setEventHandler(ConnectionEvents(implWrapper_));
|
||||
socket_->setMessageHandler([this](const std::string& msg) {
|
||||
std::unique_ptr<FireAndForgetBasedFlipperResponder> responder;
|
||||
auto message = folly::parseJson(msg);
|
||||
auto idItr = message.find("id");
|
||||
@@ -278,54 +251,41 @@ bool FlipperConnectionManagerImpl::connectSecurely() {
|
||||
this->onMessageReceived(folly::parseJson(msg), std::move(responder));
|
||||
});
|
||||
|
||||
connectionIsTrusted_ = true;
|
||||
|
||||
auto step = flipperState_->start(
|
||||
"Attempt to connect with existing client certificate");
|
||||
isConnectionTrusted_ = true;
|
||||
|
||||
auto step =
|
||||
state_->start("Attempt to connect with existing client certificate");
|
||||
step->complete();
|
||||
|
||||
// TLS:
|
||||
// On failure: clear the client.
|
||||
// On success: clear number of failed attempts.
|
||||
|
||||
// Connect is just handled here, move this elsewhere.
|
||||
if (!client_->connect(this)) {
|
||||
client_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
failedConnectionAttempts_ = 0;
|
||||
return true;
|
||||
socket_->connect(this);
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::reconnect() {
|
||||
if (!isStarted_) {
|
||||
if (!started_) {
|
||||
log("Not started");
|
||||
return;
|
||||
}
|
||||
flipperScheduler_->scheduleAfter(
|
||||
[this]() { startSync(); }, reconnectIntervalSeconds * 1000.0f);
|
||||
log("[conn] reconnect()");
|
||||
scheduler_->scheduleAfter(
|
||||
[this]() { startSync(); }, RECONNECT_INTERVAL_SECONDS * 1000.0f);
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::stop() {
|
||||
if (certProvider_ && certProvider_->shouldResetCertificateFolder()) {
|
||||
contextStore_->resetState();
|
||||
if (certificateProvider_ &&
|
||||
certificateProvider_->shouldResetCertificateFolder()) {
|
||||
store_->resetState();
|
||||
}
|
||||
if (!isStarted_) {
|
||||
if (!started_) {
|
||||
log("Not started");
|
||||
return;
|
||||
}
|
||||
isStarted_ = false;
|
||||
started_ = false;
|
||||
|
||||
std::shared_ptr<std::promise<void>> joinPromise =
|
||||
std::make_shared<std::promise<void>>();
|
||||
std::future<void> join = joinPromise->get_future();
|
||||
flipperScheduler_->schedule([this, joinPromise]() {
|
||||
if (client_) {
|
||||
client_->disconnect();
|
||||
}
|
||||
client_ = nullptr;
|
||||
scheduler_->schedule([this, joinPromise]() {
|
||||
socket_ = nullptr;
|
||||
joinPromise->set_value();
|
||||
});
|
||||
|
||||
@@ -333,7 +293,7 @@ void FlipperConnectionManagerImpl::stop() {
|
||||
}
|
||||
|
||||
bool FlipperConnectionManagerImpl::isConnected() const {
|
||||
return isConnected_ && connectionIsTrusted_;
|
||||
return isConnected_ && isConnectionTrusted_;
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::setCallbacks(Callbacks* callbacks) {
|
||||
@@ -341,10 +301,10 @@ void FlipperConnectionManagerImpl::setCallbacks(Callbacks* callbacks) {
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::sendMessage(const folly::dynamic& message) {
|
||||
flipperScheduler_->schedule([this, message]() {
|
||||
scheduler_->schedule([this, message]() {
|
||||
try {
|
||||
if (client_) {
|
||||
client_->send(message, []() {});
|
||||
if (socket_) {
|
||||
socket_->send(message, []() {});
|
||||
}
|
||||
} catch (std::length_error& e) {
|
||||
// Skip sending messages that are too large.
|
||||
@@ -355,10 +315,10 @@ void FlipperConnectionManagerImpl::sendMessage(const folly::dynamic& message) {
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::sendMessageRaw(const std::string& message) {
|
||||
flipperScheduler_->schedule([this, message]() {
|
||||
scheduler_->schedule([this, message]() {
|
||||
try {
|
||||
if (client_) {
|
||||
client_->send(message, []() {});
|
||||
if (socket_) {
|
||||
socket_->send(message, []() {});
|
||||
}
|
||||
} catch (std::length_error& e) {
|
||||
// Skip sending messages that are too large.
|
||||
@@ -379,7 +339,7 @@ bool FlipperConnectionManagerImpl::isCertificateExchangeNeeded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto last_known_medium = contextStore_->getLastKnownMedium();
|
||||
auto last_known_medium = store_->getLastKnownMedium();
|
||||
if (!last_known_medium) {
|
||||
return true;
|
||||
}
|
||||
@@ -387,15 +347,15 @@ bool FlipperConnectionManagerImpl::isCertificateExchangeNeeded() {
|
||||
// When we exchange certs over WWW, we use a fake generated serial number and
|
||||
// a virtual device. If medium changes to FS_ACCESS at some point, we should
|
||||
// restart the exchange process to get the device ID of the real device.
|
||||
int medium = certProvider_ != nullptr
|
||||
? certProvider_->getCertificateExchangeMedium()
|
||||
int medium = certificateProvider_ != nullptr
|
||||
? certificateProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
if (last_known_medium != medium) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto step = flipperState_->start("Check required certificates are present");
|
||||
bool hasRequiredFiles = contextStore_->hasRequiredFiles();
|
||||
auto step = state_->start("Check required certificates are present");
|
||||
bool hasRequiredFiles = store_->hasRequiredFiles();
|
||||
if (hasRequiredFiles) {
|
||||
step->complete();
|
||||
}
|
||||
@@ -406,109 +366,88 @@ void FlipperConnectionManagerImpl::processSignedCertificateResponse(
|
||||
std::shared_ptr<FlipperStep> gettingCert,
|
||||
std::string response,
|
||||
bool isError) {
|
||||
/**
|
||||
Need to keep track of whether the response has been
|
||||
handled. On success, the completion handler deallocates the socket which in
|
||||
turn triggers a disconnect. A disconnect is called within
|
||||
the context of a subscription handler. This means that the completion
|
||||
handler can be called again to notify that the stream has
|
||||
been interrupted because we are effectively still handing the response
|
||||
read. So, if already handled, ignore and return;
|
||||
*/
|
||||
if (certificateExchangeCompleted_)
|
||||
return;
|
||||
certificateExchangeCompleted_ = true;
|
||||
if (isError) {
|
||||
auto error =
|
||||
"Desktop failed to provide certificates. Error from flipper desktop:\n" +
|
||||
"Flipper failed to provide certificates. Error from Flipper Desktop:\n" +
|
||||
response;
|
||||
log(error);
|
||||
gettingCert->fail(error);
|
||||
client_ = nullptr;
|
||||
return;
|
||||
}
|
||||
int medium = certProvider_ != nullptr
|
||||
? certProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
|
||||
if (!response.empty()) {
|
||||
folly::dynamic config = folly::parseJson(response);
|
||||
config["medium"] = medium;
|
||||
contextStore_->storeConnectionConfig(config);
|
||||
}
|
||||
if (certProvider_) {
|
||||
certProvider_->setFlipperState(flipperState_);
|
||||
auto gettingCertFromProvider =
|
||||
flipperState_->start("Getting cert from Cert Provider");
|
||||
} else {
|
||||
int medium = certificateProvider_ != nullptr
|
||||
? certificateProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
|
||||
try {
|
||||
// Certificates should be present in app's sandbox after it is
|
||||
// returned. The reason we can't have a completion block here
|
||||
// is because if the certs are not present after it returns
|
||||
// then the flipper tries to reconnect on insecured channel
|
||||
// and recreates the app.csr. By the time completion block is
|
||||
// called the DeviceCA cert doesn't match app's csr and it
|
||||
// throws an SSL error.
|
||||
certProvider_->getCertificates(
|
||||
contextStore_->getCertificateDirectoryPath(),
|
||||
contextStore_->getDeviceId());
|
||||
gettingCertFromProvider->complete();
|
||||
} catch (std::exception& e) {
|
||||
gettingCertFromProvider->fail(e.what());
|
||||
gettingCert->fail(e.what());
|
||||
} catch (...) {
|
||||
gettingCertFromProvider->fail("Exception from certProvider");
|
||||
gettingCert->fail("Exception from certProvider");
|
||||
if (!response.empty()) {
|
||||
folly::dynamic config = folly::parseJson(response);
|
||||
config["medium"] = medium;
|
||||
store_->storeConnectionConfig(config);
|
||||
}
|
||||
}
|
||||
log("Certificate exchange complete.");
|
||||
gettingCert->complete();
|
||||
if (certificateProvider_) {
|
||||
certificateProvider_->setFlipperState(state_);
|
||||
auto gettingCertFromProvider =
|
||||
state_->start("Getting client certificate from Certificate Provider");
|
||||
|
||||
// Disconnect after message sending is complete.
|
||||
// The client destructor will send a disconnected event
|
||||
// which will be handled by Flipper which will initiate
|
||||
// a reconnect sequence.
|
||||
client_ = nullptr;
|
||||
try {
|
||||
// Certificates should be present in app's sandbox after it is
|
||||
// returned. The reason we can't have a completion block here
|
||||
// is because if the certs are not present after it returns
|
||||
// then the flipper tries to reconnect on insecured channel
|
||||
// and recreates the app.csr. By the time completion block is
|
||||
// called the DeviceCA cert doesn't match app's csr and it
|
||||
// throws an SSL error.
|
||||
certificateProvider_->getCertificates(
|
||||
store_->getCertificateDirectoryPath(), store_->getDeviceId());
|
||||
gettingCertFromProvider->complete();
|
||||
} catch (std::exception& e) {
|
||||
gettingCertFromProvider->fail(e.what());
|
||||
gettingCert->fail(e.what());
|
||||
} catch (...) {
|
||||
gettingCertFromProvider->fail(
|
||||
"Exception thrown from Certificate Provider");
|
||||
gettingCert->fail("Exception thrown from Certificate Provider");
|
||||
}
|
||||
}
|
||||
log("Certificate exchange complete.");
|
||||
gettingCert->complete();
|
||||
}
|
||||
|
||||
socket_ = nullptr;
|
||||
reconnect();
|
||||
}
|
||||
|
||||
void FlipperConnectionManagerImpl::requestSignedCertificate() {
|
||||
auto resettingState = flipperState_->start("Reset connection store state");
|
||||
contextStore_->resetState();
|
||||
auto resettingState = state_->start("Reset connection store state");
|
||||
store_->resetState();
|
||||
resettingState->complete();
|
||||
|
||||
auto generatingCSR = flipperState_->start("Generate CSR");
|
||||
std::string csr = contextStore_->getCertificateSigningRequest();
|
||||
auto generatingCSR = state_->start("Generate CSR");
|
||||
std::string csr = store_->getCertificateSigningRequest();
|
||||
generatingCSR->complete();
|
||||
|
||||
int medium = certProvider_ != nullptr
|
||||
? certProvider_->getCertificateExchangeMedium()
|
||||
int medium = certificateProvider_ != nullptr
|
||||
? certificateProvider_->getCertificateExchangeMedium()
|
||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||
folly::dynamic message = folly::dynamic::object("method", "signCertificate")(
|
||||
"csr", csr.c_str())(
|
||||
"destination",
|
||||
contextStore_->getCertificateDirectoryPath().c_str())("medium", medium);
|
||||
folly::dynamic message =
|
||||
folly::dynamic::object("method", "signCertificate")("csr", csr.c_str())(
|
||||
"destination",
|
||||
store_->getCertificateDirectoryPath().c_str())("medium", medium);
|
||||
|
||||
auto gettingCert = flipperState_->start("Getting cert from desktop");
|
||||
auto gettingCert = state_->start("Getting cert from desktop");
|
||||
|
||||
certificateExchangeCompleted_ = false;
|
||||
flipperScheduler_->schedule([this, message, gettingCert]() {
|
||||
if (!client_) {
|
||||
return;
|
||||
}
|
||||
client_->sendExpectResponse(
|
||||
folly::toJson(message),
|
||||
[this, gettingCert](const std::string& response, bool isError) {
|
||||
flipperScheduler_->schedule([this, gettingCert, response, isError]() {
|
||||
this->processSignedCertificateResponse(
|
||||
gettingCert, response, isError);
|
||||
});
|
||||
socket_->sendExpectResponse(
|
||||
folly::toJson(message),
|
||||
[this, gettingCert](const std::string& response, bool isError) {
|
||||
scheduler_->schedule([this, gettingCert, response, isError]() {
|
||||
this->processSignedCertificateResponse(
|
||||
gettingCert, response, isError);
|
||||
});
|
||||
});
|
||||
});
|
||||
failedConnectionAttempts_ = 0;
|
||||
}
|
||||
|
||||
bool FlipperConnectionManagerImpl::isRunningInOwnThread() {
|
||||
return flipperScheduler_->isRunningInOwnThread();
|
||||
return scheduler_->isRunningInOwnThread();
|
||||
}
|
||||
|
||||
} // namespace flipper
|
||||
|
||||
@@ -55,33 +55,35 @@ class FlipperConnectionManagerImpl : public FlipperConnectionManager {
|
||||
|
||||
private:
|
||||
bool isConnected_ = false;
|
||||
bool isStarted_ = false;
|
||||
std::shared_ptr<FlipperCertificateProvider> certProvider_ = nullptr;
|
||||
bool started_ = false;
|
||||
bool isConnectionTrusted_ = false;
|
||||
|
||||
std::shared_ptr<FlipperCertificateProvider> certificateProvider_ = nullptr;
|
||||
|
||||
Callbacks* callbacks_;
|
||||
|
||||
DeviceData deviceData_;
|
||||
std::shared_ptr<FlipperState> flipperState_;
|
||||
|
||||
std::shared_ptr<FlipperState> state_;
|
||||
|
||||
int insecurePort;
|
||||
int securePort;
|
||||
int altInsecurePort;
|
||||
int altSecurePort;
|
||||
|
||||
Scheduler* flipperScheduler_;
|
||||
Scheduler* scheduler_;
|
||||
Scheduler* connectionScheduler_;
|
||||
|
||||
std::unique_ptr<FlipperSocket> client_;
|
||||
|
||||
bool connectionIsTrusted_;
|
||||
bool certificateExchangeCompleted_ = false;
|
||||
std::unique_ptr<FlipperSocket> socket_;
|
||||
|
||||
int failedConnectionAttempts_ = 0;
|
||||
int failedSocketConnectionAttempts = 0;
|
||||
|
||||
std::shared_ptr<ConnectionContextStore> contextStore_;
|
||||
std::shared_ptr<ConnectionContextStore> store_;
|
||||
std::shared_ptr<FlipperConnectionManagerWrapper> implWrapper_;
|
||||
|
||||
void startSync();
|
||||
bool connectAndExchangeCertificate();
|
||||
bool connectSecurely();
|
||||
void connectAndExchangeCertificate();
|
||||
void connectSecurely();
|
||||
void handleSocketEvent(const SocketEvent event);
|
||||
bool isCertificateExchangeNeeded();
|
||||
void requestSignedCertificate();
|
||||
|
||||
@@ -37,7 +37,7 @@ class FlipperSocket {
|
||||
used or error.
|
||||
@param manager An instance of FlipperConnectionManager.
|
||||
*/
|
||||
virtual bool connect(FlipperConnectionManager* manager) = 0;
|
||||
virtual void connect(FlipperConnectionManager* manager) = 0;
|
||||
/**
|
||||
Disconnect from the endpoint.
|
||||
*/
|
||||
|
||||
@@ -68,7 +68,7 @@ class BaseClient {
|
||||
messageHandler_ = std::move(messageHandler);
|
||||
}
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) = 0;
|
||||
virtual void connect(FlipperConnectionManager* manager) = 0;
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
virtual void send(
|
||||
|
||||
@@ -60,8 +60,8 @@ void FlipperWebSocket::setMessageHandler(SocketMessageHandler messageHandler) {
|
||||
socket_->setMessageHandler(messageHandler);
|
||||
}
|
||||
|
||||
bool FlipperWebSocket::connect(FlipperConnectionManager* manager) {
|
||||
return socket_->connect(manager);
|
||||
void FlipperWebSocket::connect(FlipperConnectionManager* manager) {
|
||||
socket_->connect(manager);
|
||||
}
|
||||
|
||||
void FlipperWebSocket::disconnect() {
|
||||
|
||||
@@ -41,7 +41,7 @@ class FlipperWebSocket : public FlipperSocket {
|
||||
virtual void setEventHandler(SocketEventHandler eventHandler) override;
|
||||
virtual void setMessageHandler(SocketMessageHandler messageHandler) override;
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||
virtual void connect(FlipperConnectionManager* manager) override;
|
||||
virtual void disconnect() override;
|
||||
|
||||
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||
|
||||
@@ -62,9 +62,9 @@ WebSocketClient::~WebSocketClient() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
bool WebSocketClient::connect(FlipperConnectionManager* manager) {
|
||||
void WebSocketClient::connect(FlipperConnectionManager*) {
|
||||
if (status_ != Status::Unconnected) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
status_ = Status::Connecting;
|
||||
@@ -89,7 +89,8 @@ bool WebSocketClient::connect(FlipperConnectionManager* manager) {
|
||||
|
||||
if (ec) {
|
||||
status_ = Status::Failed;
|
||||
return false;
|
||||
eventHandler_(SocketEvent::ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
handle_ = connection_->get_handle();
|
||||
@@ -119,18 +120,7 @@ bool WebSocketClient::connect(FlipperConnectionManager* manager) {
|
||||
&socket_,
|
||||
websocketpp::lib::placeholders::_1));
|
||||
|
||||
auto connected = connected_.get_future();
|
||||
|
||||
socket_.connect(connection_);
|
||||
|
||||
auto state = connected.wait_for(std::chrono::seconds(10));
|
||||
if (state == std::future_status::ready) {
|
||||
return connected.get();
|
||||
}
|
||||
|
||||
disconnect();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebSocketClient::disconnect() {
|
||||
@@ -147,8 +137,6 @@ void WebSocketClient::disconnect() {
|
||||
thread_->join();
|
||||
}
|
||||
thread_ = nullptr;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||
}
|
||||
|
||||
void WebSocketClient::send(
|
||||
@@ -204,8 +192,7 @@ void WebSocketClient::onOpen(SocketClient* c, websocketpp::connection_hdl hdl) {
|
||||
}
|
||||
|
||||
status_ = Status::Initializing;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::OPEN); });
|
||||
eventHandler_(SocketEvent::OPEN);
|
||||
}
|
||||
|
||||
void WebSocketClient::onMessage(
|
||||
@@ -229,16 +216,14 @@ void WebSocketClient::onFail(SocketClient* c, websocketpp::connection_hdl hdl) {
|
||||
connected_.set_value(false);
|
||||
}
|
||||
status_ = Status::Failed;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::ERROR); });
|
||||
eventHandler_(SocketEvent::ERROR);
|
||||
}
|
||||
|
||||
void WebSocketClient::onClose(
|
||||
SocketClient* c,
|
||||
websocketpp::connection_hdl hdl) {
|
||||
status_ = Status::Closed;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||
eventHandler_(SocketEvent::CLOSE);
|
||||
}
|
||||
|
||||
} // namespace flipper
|
||||
|
||||
@@ -47,7 +47,7 @@ class WebSocketClient : public BaseClient {
|
||||
|
||||
virtual ~WebSocketClient();
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||
virtual void connect(FlipperConnectionManager* manager) override;
|
||||
virtual void disconnect() override;
|
||||
|
||||
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||
|
||||
@@ -65,9 +65,9 @@ WebSocketTLSClient::~WebSocketTLSClient() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
bool WebSocketTLSClient::connect(FlipperConnectionManager* manager) {
|
||||
void WebSocketTLSClient::connect(FlipperConnectionManager*) {
|
||||
if (status_ != Status::Unconnected) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
status_ = Status::Connecting;
|
||||
@@ -98,7 +98,8 @@ bool WebSocketTLSClient::connect(FlipperConnectionManager* manager) {
|
||||
|
||||
if (ec) {
|
||||
status_ = Status::Failed;
|
||||
return false;
|
||||
eventHandler_(SocketEvent::ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
handle_ = connection_->get_handle();
|
||||
@@ -128,18 +129,7 @@ bool WebSocketTLSClient::connect(FlipperConnectionManager* manager) {
|
||||
&socket_,
|
||||
websocketpp::lib::placeholders::_1));
|
||||
|
||||
auto connected = connected_.get_future();
|
||||
|
||||
socket_.connect(connection_);
|
||||
|
||||
auto state = connected.wait_for(std::chrono::seconds(10));
|
||||
if (state == std::future_status::ready) {
|
||||
return connected.get();
|
||||
}
|
||||
|
||||
disconnect();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebSocketTLSClient::disconnect() {
|
||||
@@ -157,8 +147,6 @@ void WebSocketTLSClient::disconnect() {
|
||||
}
|
||||
|
||||
thread_ = nullptr;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||
}
|
||||
|
||||
void WebSocketTLSClient::send(
|
||||
@@ -211,13 +199,8 @@ void WebSocketTLSClient::sendExpectResponse(
|
||||
void WebSocketTLSClient::onOpen(
|
||||
SocketTLSClient* c,
|
||||
websocketpp::connection_hdl hdl) {
|
||||
if (status_ == Status::Connecting) {
|
||||
connected_.set_value(true);
|
||||
}
|
||||
|
||||
status_ = Status::Initializing;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::OPEN); });
|
||||
eventHandler_(SocketEvent::OPEN);
|
||||
}
|
||||
|
||||
void WebSocketTLSClient::onMessage(
|
||||
@@ -242,36 +225,19 @@ void WebSocketTLSClient::onFail(
|
||||
(reason.find("TLS handshake failed") != std::string::npos ||
|
||||
reason.find("Generic TLS related error") != std::string::npos);
|
||||
|
||||
if (status_ == Status::Connecting) {
|
||||
if (sslError) {
|
||||
try {
|
||||
connected_.set_exception(
|
||||
std::make_exception_ptr(SSLException("SSL handshake failed")));
|
||||
} catch (...) {
|
||||
// set_exception() may throw an exception
|
||||
// In that case, just set the value to false.
|
||||
connected_.set_value(false);
|
||||
}
|
||||
} else {
|
||||
connected_.set_value(false);
|
||||
}
|
||||
}
|
||||
status_ = Status::Failed;
|
||||
scheduler_->schedule([eventHandler = eventHandler_, sslError]() {
|
||||
if (sslError) {
|
||||
eventHandler(SocketEvent::SSL_ERROR);
|
||||
} else {
|
||||
eventHandler(SocketEvent::ERROR);
|
||||
}
|
||||
});
|
||||
if (sslError) {
|
||||
eventHandler_(SocketEvent::SSL_ERROR);
|
||||
} else {
|
||||
eventHandler_(SocketEvent::ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketTLSClient::onClose(
|
||||
SocketTLSClient* c,
|
||||
websocketpp::connection_hdl hdl) {
|
||||
status_ = Status::Closed;
|
||||
scheduler_->schedule(
|
||||
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||
eventHandler_(SocketEvent::CLOSE);
|
||||
}
|
||||
|
||||
SocketTLSContext WebSocketTLSClient::onTLSInit(
|
||||
|
||||
@@ -50,7 +50,7 @@ class WebSocketTLSClient : public BaseClient {
|
||||
|
||||
virtual ~WebSocketTLSClient();
|
||||
|
||||
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||
virtual void connect(FlipperConnectionManager* manager) override;
|
||||
virtual void disconnect() override;
|
||||
|
||||
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||
@@ -76,7 +76,6 @@ class WebSocketTLSClient : public BaseClient {
|
||||
|
||||
SocketTLSThread thread_;
|
||||
websocketpp::connection_hdl handle_;
|
||||
std::promise<bool> connected_;
|
||||
};
|
||||
|
||||
} // namespace flipper
|
||||
|
||||
Reference in New Issue
Block a user