Define boundaries between FlipperConnectionManager and RSocket on the client side
Summary: These changes abstract RSocket from FlipperConnectionManagerImpl. This is achieved by defining FlipperSocket. FlipperConnectionManagerImpl uses instances of FlipperSocket and RSocket is now contained within FlipperRSocket which implements FlipperSocket. On the changes to follow, FlipperConnectionManagerImpl will no longer reference FlipperRSocket directly thus fully abstracting the socket implementation in use. For reviewers: - All of the RSocket code now lives in FlipperRSocket. - Main changes are in FlipperConnectionManagerImpl. Lambdas are used to deal with events and message handling. - There's some very minimal serialisation additions for payloads. Reviewed By: jknoxville Differential Revision: D30341076 fbshipit-source-id: 54bb4878967378490710c05f729cdd7f4cf08bb8
This commit is contained in:
committed by
Facebook GitHub Bot
parent
4ae7d9c42b
commit
a9c6351cf0
@@ -11,14 +11,11 @@
|
|||||||
#include <folly/io/async/AsyncSocketException.h>
|
#include <folly/io/async/AsyncSocketException.h>
|
||||||
#include <folly/io/async/SSLContext.h>
|
#include <folly/io/async/SSLContext.h>
|
||||||
#include <folly/json.h>
|
#include <folly/json.h>
|
||||||
#include <rsocket/Payload.h>
|
|
||||||
#include <rsocket/RSocket.h>
|
|
||||||
#include <rsocket/transports/tcp/TcpConnectionFactory.h>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "ConnectionContextStore.h"
|
#include "ConnectionContextStore.h"
|
||||||
#include "FireAndForgetBasedFlipperResponder.h"
|
#include "FireAndForgetBasedFlipperResponder.h"
|
||||||
#include "FlipperRSocketResponder.h"
|
#include "FlipperRSocket.h"
|
||||||
#include "FlipperResponderImpl.h"
|
#include "FlipperResponderImpl.h"
|
||||||
#include "FlipperStep.h"
|
#include "FlipperStep.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
@@ -28,9 +25,6 @@
|
|||||||
"ERROR: Aborting flipper initialization because it's not running in the flipper thread."
|
"ERROR: Aborting flipper initialization because it's not running in the flipper thread."
|
||||||
|
|
||||||
static constexpr int reconnectIntervalSeconds = 2;
|
static constexpr int reconnectIntervalSeconds = 2;
|
||||||
static constexpr int connectionKeepaliveSeconds = 10;
|
|
||||||
|
|
||||||
static constexpr int maxPayloadSize = 0xFFFFFF;
|
|
||||||
|
|
||||||
// Not a public-facing version number.
|
// Not a public-facing version number.
|
||||||
// Used for compatibility checking with desktop flipper.
|
// Used for compatibility checking with desktop flipper.
|
||||||
@@ -42,35 +36,33 @@ using namespace folly;
|
|||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace flipper {
|
namespace flipper {
|
||||||
|
|
||||||
class ConnectionEvents : public rsocket::RSocketConnectionEvents {
|
class ConnectionEvents {
|
||||||
private:
|
|
||||||
FlipperConnectionManagerImpl* websocket_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConnectionEvents(FlipperConnectionManagerImpl* websocket)
|
ConnectionEvents(FlipperConnectionManagerImpl* impl) : impl_(impl) {}
|
||||||
: websocket_(websocket) {}
|
void operator()(const SocketEvent event) {
|
||||||
|
switch (event) {
|
||||||
void onConnected() {
|
case SocketEvent::OPEN:
|
||||||
websocket_->isOpen_ = true;
|
impl_->isOpen_ = true;
|
||||||
if (websocket_->connectionIsTrusted_) {
|
if (impl_->connectionIsTrusted_) {
|
||||||
websocket_->callbacks_->onConnected();
|
impl_->callbacks_->onConnected();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SocketEvent::CLOSE:
|
||||||
|
case SocketEvent::ERROR:
|
||||||
|
if (!impl_->isOpen_)
|
||||||
|
return;
|
||||||
|
impl_->isOpen_ = false;
|
||||||
|
if (impl_->connectionIsTrusted_) {
|
||||||
|
impl_->connectionIsTrusted_ = false;
|
||||||
|
impl_->callbacks_->onDisconnected();
|
||||||
|
}
|
||||||
|
impl_->reconnect();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDisconnected(const folly::exception_wrapper&) {
|
private:
|
||||||
if (!websocket_->isOpen_)
|
FlipperConnectionManagerImpl* impl_;
|
||||||
return;
|
|
||||||
websocket_->isOpen_ = false;
|
|
||||||
if (websocket_->connectionIsTrusted_) {
|
|
||||||
websocket_->connectionIsTrusted_ = false;
|
|
||||||
websocket_->callbacks_->onDisconnected();
|
|
||||||
}
|
|
||||||
websocket_->reconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onClosed(const folly::exception_wrapper& e) {
|
|
||||||
onDisconnected(e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FlipperConnectionManagerImpl::FlipperConnectionManagerImpl(
|
FlipperConnectionManagerImpl::FlipperConnectionManagerImpl(
|
||||||
@@ -139,7 +131,7 @@ void FlipperConnectionManagerImpl::startSync() {
|
|||||||
: "Establish main connection");
|
: "Establish main connection");
|
||||||
try {
|
try {
|
||||||
if (isClientSetupStep) {
|
if (isClientSetupStep) {
|
||||||
bool success = doCertificateExchange();
|
bool success = connectAndExchangeCertificate();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
reconnect();
|
reconnect();
|
||||||
return;
|
return;
|
||||||
@@ -178,41 +170,30 @@ void FlipperConnectionManagerImpl::startSync() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlipperConnectionManagerImpl::doCertificateExchange() {
|
bool FlipperConnectionManagerImpl::connectAndExchangeCertificate() {
|
||||||
rsocket::SetupParameters parameters;
|
auto endpoint =
|
||||||
folly::SocketAddress address;
|
FlipperConnectionEndpoint(deviceData_.host, insecurePort, false);
|
||||||
|
|
||||||
int medium = certProvider_ != nullptr
|
int medium = certProvider_ != nullptr
|
||||||
? certProvider_->getCertificateExchangeMedium()
|
? certProvider_->getCertificateExchangeMedium()
|
||||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||||
|
|
||||||
parameters.payload = rsocket::Payload(folly::toJson(folly::dynamic::object(
|
auto payload = std::make_unique<FlipperSocketBasePayload>();
|
||||||
"os", deviceData_.os)("device", deviceData_.device)(
|
payload->os = deviceData_.os;
|
||||||
"app", deviceData_.app)("sdk_version", sdkVersion)("medium", medium)));
|
payload->device = deviceData_.device;
|
||||||
address.setFromHostPort(deviceData_.host, insecurePort);
|
payload->device_id = "unknown";
|
||||||
|
payload->app = deviceData_.app;
|
||||||
|
payload->sdk_version = sdkVersion;
|
||||||
|
payload->medium = medium;
|
||||||
|
|
||||||
|
auto newClient = std::make_unique<FlipperRSocket>(
|
||||||
|
endpoint, std::move(payload), connectionEventBase_);
|
||||||
|
newClient->setEventHandler(ConnectionEvents(this));
|
||||||
|
|
||||||
auto connectingInsecurely = flipperState_->start("Connect insecurely");
|
auto connectingInsecurely = flipperState_->start("Connect insecurely");
|
||||||
connectionIsTrusted_ = false;
|
connectionIsTrusted_ = false;
|
||||||
auto newClient =
|
|
||||||
rsocket::RSocket::createConnectedClient(
|
|
||||||
std::make_unique<rsocket::TcpConnectionFactory>(
|
|
||||||
*connectionEventBase_->getEventBase(), std::move(address)),
|
|
||||||
std::move(parameters),
|
|
||||||
nullptr,
|
|
||||||
std::chrono::seconds(connectionKeepaliveSeconds), // keepaliveInterval
|
|
||||||
nullptr, // stats
|
|
||||||
std::make_shared<ConnectionEvents>(this))
|
|
||||||
.thenError<folly::AsyncSocketException>([](const auto& e) {
|
|
||||||
if (e.getType() == folly::AsyncSocketException::NOT_OPEN ||
|
|
||||||
e.getType() == folly::AsyncSocketException::NETWORK_ERROR) {
|
|
||||||
// This is the state where no Flipper desktop client is connected.
|
|
||||||
// We don't want an exception thrown here.
|
|
||||||
return std::unique_ptr<rsocket::RSocketClient>(nullptr);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
|
|
||||||
if (newClient.get() == nullptr) {
|
if (!newClient->connect(this)) {
|
||||||
connectingInsecurely->fail("Failed to connect");
|
connectingInsecurely->fail("Failed to connect");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -229,53 +210,36 @@ bool FlipperConnectionManagerImpl::doCertificateExchange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FlipperConnectionManagerImpl::connectSecurely() {
|
bool FlipperConnectionManagerImpl::connectSecurely() {
|
||||||
rsocket::SetupParameters parameters;
|
auto endpoint = FlipperConnectionEndpoint(deviceData_.host, securePort, true);
|
||||||
folly::SocketAddress address;
|
|
||||||
|
int medium = certProvider_ != nullptr
|
||||||
|
? certProvider_->getCertificateExchangeMedium()
|
||||||
|
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
||||||
|
|
||||||
auto loadingDeviceId = flipperState_->start("Load Device Id");
|
auto loadingDeviceId = flipperState_->start("Load Device Id");
|
||||||
auto deviceId = contextStore_->getDeviceId();
|
auto deviceId = contextStore_->getDeviceId();
|
||||||
if (deviceId.compare("unknown")) {
|
if (deviceId.compare("unknown")) {
|
||||||
loadingDeviceId->complete();
|
loadingDeviceId->complete();
|
||||||
}
|
}
|
||||||
int medium = certProvider_ != nullptr
|
|
||||||
? certProvider_->getCertificateExchangeMedium()
|
|
||||||
: FlipperCertificateExchangeMedium::FS_ACCESS;
|
|
||||||
|
|
||||||
parameters.payload = rsocket::Payload(folly::toJson(folly::dynamic::object(
|
auto payload = std::make_unique<FlipperSocketSecurePayload>();
|
||||||
"csr", contextStore_->getCertificateSigningRequest().c_str())(
|
payload->os = deviceData_.os;
|
||||||
"csr_path", contextStore_->getCertificateDirectoryPath().c_str())(
|
payload->device = deviceData_.device;
|
||||||
"os", deviceData_.os)("device", deviceData_.device)(
|
payload->device_id = deviceId;
|
||||||
"device_id", deviceId)("app", deviceData_.app)("medium", medium)(
|
payload->app = deviceData_.app;
|
||||||
"sdk_version", sdkVersion)));
|
payload->sdk_version = sdkVersion;
|
||||||
address.setFromHostPort(deviceData_.host, securePort);
|
payload->medium = medium;
|
||||||
|
payload->csr = contextStore_->getCertificateSigningRequest().c_str();
|
||||||
|
payload->csr_path = contextStore_->getCertificateDirectoryPath().c_str();
|
||||||
|
|
||||||
|
auto newClient = std::make_unique<FlipperRSocket>(
|
||||||
|
endpoint, std::move(payload), connectionEventBase_, contextStore_.get());
|
||||||
|
newClient->setEventHandler(ConnectionEvents(this));
|
||||||
|
|
||||||
std::shared_ptr<folly::SSLContext> sslContext =
|
|
||||||
contextStore_->getSSLContext();
|
|
||||||
auto connectingSecurely = flipperState_->start("Connect securely");
|
auto connectingSecurely = flipperState_->start("Connect securely");
|
||||||
connectionIsTrusted_ = true;
|
connectionIsTrusted_ = true;
|
||||||
|
|
||||||
auto newClient =
|
if (!newClient->connect(this)) {
|
||||||
rsocket::RSocket::createConnectedClient(
|
|
||||||
std::make_unique<rsocket::TcpConnectionFactory>(
|
|
||||||
*connectionEventBase_->getEventBase(),
|
|
||||||
std::move(address),
|
|
||||||
std::move(sslContext)),
|
|
||||||
std::move(parameters),
|
|
||||||
std::make_shared<FlipperRSocketResponder>(this, connectionEventBase_),
|
|
||||||
std::chrono::seconds(connectionKeepaliveSeconds), // keepaliveInterval
|
|
||||||
nullptr, // stats
|
|
||||||
std::make_shared<ConnectionEvents>(this))
|
|
||||||
.thenError<folly::AsyncSocketException>([](const auto& e) {
|
|
||||||
if (e.getType() == folly::AsyncSocketException::NOT_OPEN ||
|
|
||||||
e.getType() == folly::AsyncSocketException::NETWORK_ERROR) {
|
|
||||||
// This is the state where no Flipper desktop client is connected.
|
|
||||||
// We don't want an exception thrown here.
|
|
||||||
return std::unique_ptr<rsocket::RSocketClient>(nullptr);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
})
|
|
||||||
.get();
|
|
||||||
if (newClient.get() == nullptr) {
|
|
||||||
connectingSecurely->fail("Failed to connect");
|
connectingSecurely->fail("Failed to connect");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -324,11 +288,8 @@ void FlipperConnectionManagerImpl::setCallbacks(Callbacks* callbacks) {
|
|||||||
void FlipperConnectionManagerImpl::sendMessage(const folly::dynamic& message) {
|
void FlipperConnectionManagerImpl::sendMessage(const folly::dynamic& message) {
|
||||||
flipperEventBase_->add([this, message]() {
|
flipperEventBase_->add([this, message]() {
|
||||||
try {
|
try {
|
||||||
rsocket::Payload payload = toRSocketPayload(message);
|
|
||||||
if (client_) {
|
if (client_) {
|
||||||
client_->getRequester()
|
client_->send(message, []() {});
|
||||||
->fireAndForget(std::move(payload))
|
|
||||||
->subscribe([]() {});
|
|
||||||
}
|
}
|
||||||
} catch (std::length_error& e) {
|
} catch (std::length_error& e) {
|
||||||
// Skip sending messages that are too large.
|
// Skip sending messages that are too large.
|
||||||
@@ -369,72 +330,76 @@ void FlipperConnectionManagerImpl::requestSignedCertFromFlipper() {
|
|||||||
"destination",
|
"destination",
|
||||||
contextStore_->getCertificateDirectoryPath().c_str())("medium", medium);
|
contextStore_->getCertificateDirectoryPath().c_str())("medium", medium);
|
||||||
auto gettingCert = flipperState_->start("Getting cert from desktop");
|
auto gettingCert = flipperState_->start("Getting cert from desktop");
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
flipperEventBase_->add([this, message, gettingCert]() {
|
flipperEventBase_->add([this, &handled, message, gettingCert]() {
|
||||||
client_->getRequester()
|
client_->sendExpectResponse(
|
||||||
->requestResponse(rsocket::Payload(folly::toJson(message)))
|
folly::toJson(message),
|
||||||
->subscribe(
|
[this, &handled, message, gettingCert](
|
||||||
[this, gettingCert](rsocket::Payload p) {
|
const std::string& response, bool isError) {
|
||||||
auto response = p.moveDataToString();
|
/**
|
||||||
if (!response.empty()) {
|
Need to keep track of whether the response has been handled.
|
||||||
folly::dynamic config = folly::parseJson(response);
|
On success, the completion handler deallocates the socket which in
|
||||||
contextStore_->storeConnectionConfig(config);
|
turn triggers a disconnect. A disconnect is called within the
|
||||||
}
|
context of a subscription handler. This means that the completion
|
||||||
if (certProvider_) {
|
handler can be called again to notify that the stream has been
|
||||||
certProvider_->setFlipperState(flipperState_);
|
interrupted because we are effectively still handing the response
|
||||||
auto gettingCertFromProvider =
|
read. So, if already handled, ignore and return;
|
||||||
flipperState_->start("Getting cert from Cert Provider");
|
*/
|
||||||
|
if (handled)
|
||||||
try {
|
return;
|
||||||
// Certificates should be present in app's sandbox after it is
|
handled = true;
|
||||||
// returned. The reason we can't have a completion block here
|
if (isError) {
|
||||||
// is because if the certs are not present after it returns
|
if (response.compare("not implemented")) {
|
||||||
// then the flipper tries to reconnect on insecured channel
|
auto error =
|
||||||
// and recreates the app.csr. By the time completion block is
|
"Desktop failed to provide certificates. Error from flipper desktop:\n" +
|
||||||
// called the DeviceCA cert doesn't match app's csr and it
|
response;
|
||||||
// throws an SSL error.
|
log(error);
|
||||||
certProvider_->getCertificates(
|
gettingCert->fail(error);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log("Certificate exchange complete.");
|
|
||||||
gettingCert->complete();
|
|
||||||
|
|
||||||
// Disconnect after message sending is complete.
|
|
||||||
// This will trigger a reconnect which should use the secure
|
|
||||||
// channel.
|
|
||||||
// TODO: Connect immediately, without waiting for reconnect
|
|
||||||
client_ = nullptr;
|
client_ = nullptr;
|
||||||
},
|
} else {
|
||||||
[this, message, gettingCert](folly::exception_wrapper e) {
|
sendLegacyCertificateRequest(message);
|
||||||
e.handle(
|
}
|
||||||
[&](rsocket::ErrorWithPayload& errorWithPayload) {
|
return;
|
||||||
std::string errorMessage =
|
}
|
||||||
errorWithPayload.payload.moveDataToString();
|
if (!response.empty()) {
|
||||||
|
folly::dynamic config = folly::parseJson(response);
|
||||||
|
contextStore_->storeConnectionConfig(config);
|
||||||
|
}
|
||||||
|
if (certProvider_) {
|
||||||
|
certProvider_->setFlipperState(flipperState_);
|
||||||
|
auto gettingCertFromProvider =
|
||||||
|
flipperState_->start("Getting cert from Cert Provider");
|
||||||
|
|
||||||
if (errorMessage.compare("not implemented")) {
|
try {
|
||||||
auto error =
|
// Certificates should be present in app's sandbox after it is
|
||||||
"Desktop failed to provide certificates. Error from flipper desktop:\n" +
|
// returned. The reason we can't have a completion block here
|
||||||
errorMessage;
|
// is because if the certs are not present after it returns
|
||||||
log(error);
|
// then the flipper tries to reconnect on insecured channel
|
||||||
gettingCert->fail(error);
|
// and recreates the app.csr. By the time completion block is
|
||||||
client_ = nullptr;
|
// called the DeviceCA cert doesn't match app's csr and it
|
||||||
} else {
|
// throws an SSL error.
|
||||||
sendLegacyCertificateRequest(message);
|
certProvider_->getCertificates(
|
||||||
}
|
contextStore_->getCertificateDirectoryPath(),
|
||||||
},
|
contextStore_->getDeviceId());
|
||||||
[e, gettingCert](...) {
|
gettingCertFromProvider->complete();
|
||||||
gettingCert->fail(e.what().c_str());
|
} catch (std::exception& e) {
|
||||||
});
|
gettingCertFromProvider->fail(e.what());
|
||||||
});
|
gettingCert->fail(e.what());
|
||||||
|
} catch (...) {
|
||||||
|
gettingCertFromProvider->fail("Exception from certProvider");
|
||||||
|
gettingCert->fail("Exception from certProvider");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log("Certificate exchange complete.");
|
||||||
|
gettingCert->complete();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
failedConnectionAttempts_ = 0;
|
failedConnectionAttempts_ = 0;
|
||||||
}
|
}
|
||||||
@@ -445,35 +410,18 @@ void FlipperConnectionManagerImpl::sendLegacyCertificateRequest(
|
|||||||
// Fall back to fireAndForget, instead of requestResponse.
|
// Fall back to fireAndForget, instead of requestResponse.
|
||||||
auto sendingRequest =
|
auto sendingRequest =
|
||||||
flipperState_->start("Sending fallback certificate request");
|
flipperState_->start("Sending fallback certificate request");
|
||||||
client_->getRequester()
|
|
||||||
->fireAndForget(rsocket::Payload(folly::toJson(message)))
|
client_->send(message, [this, sendingRequest]() {
|
||||||
->subscribe([this, sendingRequest]() {
|
sendingRequest->complete();
|
||||||
sendingRequest->complete();
|
folly::dynamic config = folly::dynamic::object();
|
||||||
folly::dynamic config = folly::dynamic::object();
|
contextStore_->storeConnectionConfig(config);
|
||||||
contextStore_->storeConnectionConfig(config);
|
client_ = nullptr;
|
||||||
client_ = nullptr;
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlipperConnectionManagerImpl::isRunningInOwnThread() {
|
bool FlipperConnectionManagerImpl::isRunningInOwnThread() {
|
||||||
return flipperEventBase_->isInEventBaseThread();
|
return flipperEventBase_->isInEventBaseThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
rsocket::Payload toRSocketPayload(dynamic data) {
|
|
||||||
std::string json = folly::toJson(data);
|
|
||||||
rsocket::Payload payload = rsocket::Payload(json);
|
|
||||||
auto payloadLength = payload.data->computeChainDataLength();
|
|
||||||
if (payloadLength > maxPayloadSize) {
|
|
||||||
auto logMessage =
|
|
||||||
std::string(
|
|
||||||
"Error: Skipping sending message larger than max rsocket payload: ") +
|
|
||||||
json.substr(0, 100) + "...";
|
|
||||||
log(logMessage);
|
|
||||||
throw std::length_error(logMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace flipper
|
} // namespace flipper
|
||||||
} // namespace facebook
|
} // namespace facebook
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
#include <folly/Executor.h>
|
#include <folly/Executor.h>
|
||||||
#include <folly/io/async/EventBase.h>
|
#include <folly/io/async/EventBase.h>
|
||||||
#include <rsocket/RSocket.h>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "FlipperConnectionManager.h"
|
#include "FlipperConnectionManager.h"
|
||||||
#include "FlipperInitConfig.h"
|
#include "FlipperInitConfig.h"
|
||||||
|
#include "FlipperSocket.h"
|
||||||
#include "FlipperState.h"
|
#include "FlipperState.h"
|
||||||
|
|
||||||
namespace facebook {
|
namespace facebook {
|
||||||
@@ -22,8 +22,6 @@ class ConnectionEvents;
|
|||||||
class ConnectionContextStore;
|
class ConnectionContextStore;
|
||||||
class FlipperRSocketResponder;
|
class FlipperRSocketResponder;
|
||||||
|
|
||||||
rsocket::Payload toRSocketPayload(folly::dynamic data);
|
|
||||||
|
|
||||||
class FlipperConnectionManagerImpl : public FlipperConnectionManager {
|
class FlipperConnectionManagerImpl : public FlipperConnectionManager {
|
||||||
friend ConnectionEvents;
|
friend ConnectionEvents;
|
||||||
|
|
||||||
@@ -66,13 +64,15 @@ class FlipperConnectionManagerImpl : public FlipperConnectionManager {
|
|||||||
|
|
||||||
folly::EventBase* flipperEventBase_;
|
folly::EventBase* flipperEventBase_;
|
||||||
folly::EventBase* connectionEventBase_;
|
folly::EventBase* connectionEventBase_;
|
||||||
std::unique_ptr<rsocket::RSocketClient> client_;
|
|
||||||
|
std::unique_ptr<FlipperSocket> client_;
|
||||||
|
|
||||||
bool connectionIsTrusted_;
|
bool connectionIsTrusted_;
|
||||||
int failedConnectionAttempts_ = 0;
|
int failedConnectionAttempts_ = 0;
|
||||||
std::shared_ptr<ConnectionContextStore> contextStore_;
|
std::shared_ptr<ConnectionContextStore> contextStore_;
|
||||||
|
|
||||||
void startSync();
|
void startSync();
|
||||||
bool doCertificateExchange();
|
bool connectAndExchangeCertificate();
|
||||||
bool connectSecurely();
|
bool connectSecurely();
|
||||||
bool isCertificateExchangeNeeded();
|
bool isCertificateExchangeNeeded();
|
||||||
void requestSignedCertFromFlipper();
|
void requestSignedCertFromFlipper();
|
||||||
|
|||||||
217
xplat/Flipper/FlipperRSocket.cpp
Normal file
217
xplat/Flipper/FlipperRSocket.cpp
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FlipperRSocket.h"
|
||||||
|
#include <folly/String.h>
|
||||||
|
#include <folly/futures/Future.h>
|
||||||
|
#include <folly/io/async/AsyncSocketException.h>
|
||||||
|
#include <folly/io/async/SSLContext.h>
|
||||||
|
#include <folly/json.h>
|
||||||
|
#include <rsocket/Payload.h>
|
||||||
|
#include <rsocket/RSocket.h>
|
||||||
|
#include <rsocket/transports/tcp/TcpConnectionFactory.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include "ConnectionContextStore.h"
|
||||||
|
#include "FireAndForgetBasedFlipperResponder.h"
|
||||||
|
#include "FlipperRSocketResponder.h"
|
||||||
|
#include "FlipperResponderImpl.h"
|
||||||
|
#include "FlipperTransportTypes.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "yarpl/Single.h"
|
||||||
|
|
||||||
|
static constexpr int connectionKeepaliveSeconds = 10;
|
||||||
|
static constexpr int maxPayloadSize = 0xFFFFFF;
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
rsocket::Payload toRSocketPayload(folly::dynamic data);
|
||||||
|
|
||||||
|
class RSocketEvents : public rsocket::RSocketConnectionEvents {
|
||||||
|
private:
|
||||||
|
const SocketEventHandler& handler_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RSocketEvents(const SocketEventHandler& eventHandler)
|
||||||
|
: handler_(eventHandler) {}
|
||||||
|
|
||||||
|
void onConnected() {
|
||||||
|
handler_(SocketEvent::OPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDisconnected(const folly::exception_wrapper&) {
|
||||||
|
handler_(SocketEvent::CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onClosed(const folly::exception_wrapper& e) {
|
||||||
|
handler_(SocketEvent::CLOSE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RSocketSerializer : public FlipperPayloadSerializer {
|
||||||
|
public:
|
||||||
|
void put(std::string key, std::string value) override {
|
||||||
|
object_[key] = value;
|
||||||
|
}
|
||||||
|
void put(std::string key, int value) override {
|
||||||
|
object_[key] = value;
|
||||||
|
}
|
||||||
|
std::string serialize() override {
|
||||||
|
return folly::toJson(object_);
|
||||||
|
}
|
||||||
|
~RSocketSerializer() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
folly::dynamic object_ = folly::dynamic::object();
|
||||||
|
};
|
||||||
|
|
||||||
|
rsocket::Payload toRSocketPayload(folly::dynamic data) {
|
||||||
|
std::string json = folly::toJson(data);
|
||||||
|
rsocket::Payload payload = rsocket::Payload(json);
|
||||||
|
auto payloadLength = payload.data->computeChainDataLength();
|
||||||
|
if (payloadLength > maxPayloadSize) {
|
||||||
|
auto logMessage =
|
||||||
|
std::string(
|
||||||
|
"Error: Skipping sending message larger than max rsocket payload: ") +
|
||||||
|
json.substr(0, 100) + "...";
|
||||||
|
log(logMessage);
|
||||||
|
throw std::length_error(logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlipperRSocket::FlipperRSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
folly::EventBase* eventBase)
|
||||||
|
: endpoint_(std::move(endpoint)),
|
||||||
|
payload_(std::move(payload)),
|
||||||
|
eventBase_(eventBase) {}
|
||||||
|
|
||||||
|
FlipperRSocket::FlipperRSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
folly::EventBase* eventBase,
|
||||||
|
ConnectionContextStore* connectionContextStore)
|
||||||
|
: endpoint_(std::move(endpoint)),
|
||||||
|
payload_(std::move(payload)),
|
||||||
|
eventBase_(eventBase),
|
||||||
|
connectionContextStore_(connectionContextStore) {}
|
||||||
|
|
||||||
|
void FlipperRSocket::setEventHandler(SocketEventHandler eventHandler) {
|
||||||
|
eventHandler_ = std::move(eventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperRSocket::setMessageHandler(SocketMessageHandler messageHandler) {
|
||||||
|
messageHandler_ = std::move(messageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlipperRSocket::connect(FlipperConnectionManager* manager) {
|
||||||
|
folly::SocketAddress address;
|
||||||
|
address.setFromHostPort(endpoint_.host, endpoint_.port);
|
||||||
|
|
||||||
|
auto serializer = RSocketSerializer{};
|
||||||
|
payload_->serialize(serializer);
|
||||||
|
auto payload = serializer.serialize();
|
||||||
|
|
||||||
|
rsocket::SetupParameters parameters;
|
||||||
|
parameters.payload = rsocket::Payload(payload);
|
||||||
|
|
||||||
|
std::unique_ptr<rsocket::TcpConnectionFactory> tcpConnectionFactory = nullptr;
|
||||||
|
if (endpoint_.secure) {
|
||||||
|
tcpConnectionFactory = std::make_unique<rsocket::TcpConnectionFactory>(
|
||||||
|
*eventBase_->getEventBase(),
|
||||||
|
std::move(address),
|
||||||
|
connectionContextStore_->getSSLContext());
|
||||||
|
} else {
|
||||||
|
tcpConnectionFactory = std::make_unique<rsocket::TcpConnectionFactory>(
|
||||||
|
*eventBase_->getEventBase(), std::move(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto newClient =
|
||||||
|
rsocket::RSocket::createConnectedClient(
|
||||||
|
std::move(tcpConnectionFactory),
|
||||||
|
std::move(parameters),
|
||||||
|
endpoint_.secure
|
||||||
|
? std::make_shared<FlipperRSocketResponder>(manager, eventBase_)
|
||||||
|
: nullptr,
|
||||||
|
std::chrono::seconds(connectionKeepaliveSeconds), // keepaliveInterval
|
||||||
|
nullptr, // stats
|
||||||
|
std::make_shared<RSocketEvents>(eventHandler_))
|
||||||
|
.thenError<folly::AsyncSocketException>([](const auto& e) {
|
||||||
|
if (e.getType() == folly::AsyncSocketException::NOT_OPEN ||
|
||||||
|
e.getType() == folly::AsyncSocketException::NETWORK_ERROR) {
|
||||||
|
// This is the state where no Flipper desktop client is connected.
|
||||||
|
// We don't want an exception thrown here.
|
||||||
|
return std::unique_ptr<rsocket::RSocketClient>(nullptr);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
if (newClient.get() == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_ = std::move(newClient);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperRSocket::disconnect() {
|
||||||
|
if (client_.get() == nullptr)
|
||||||
|
return;
|
||||||
|
client_->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperRSocket::send(
|
||||||
|
const folly::dynamic& message,
|
||||||
|
SocketSendHandler completion) {
|
||||||
|
if (client_.get() == nullptr)
|
||||||
|
return;
|
||||||
|
rsocket::Payload payload = toRSocketPayload(message);
|
||||||
|
client_->getRequester()
|
||||||
|
->fireAndForget(std::move(payload))
|
||||||
|
->subscribe(completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperRSocket::send(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendHandler completion) {
|
||||||
|
if (client_.get() == nullptr)
|
||||||
|
return;
|
||||||
|
client_->getRequester()
|
||||||
|
->fireAndForget(rsocket::Payload(message))
|
||||||
|
->subscribe(completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperRSocket::sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) {
|
||||||
|
if (client_.get() == nullptr)
|
||||||
|
return;
|
||||||
|
client_->getRequester()
|
||||||
|
->requestResponse(rsocket::Payload(message))
|
||||||
|
->subscribe(
|
||||||
|
[completion](rsocket::Payload payload) {
|
||||||
|
auto response = payload.moveDataToString();
|
||||||
|
completion(response, false);
|
||||||
|
},
|
||||||
|
[completion](folly::exception_wrapper e) {
|
||||||
|
e.handle(
|
||||||
|
[&](rsocket::ErrorWithPayload& errorWithPayload) {
|
||||||
|
auto error = errorWithPayload.payload.moveDataToString();
|
||||||
|
completion(error, true);
|
||||||
|
},
|
||||||
|
[e, completion](...) { completion(e.what().c_str(), true); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
63
xplat/Flipper/FlipperRSocket.h
Normal file
63
xplat/Flipper/FlipperRSocket.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <folly/dynamic.h>
|
||||||
|
#include <rsocket/RSocket.h>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include "FlipperSocket.h"
|
||||||
|
#include "FlipperTransportTypes.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
class FlipperConnectionManager;
|
||||||
|
class ConnectionContextStore;
|
||||||
|
class FlipperRSocket : public FlipperSocket {
|
||||||
|
public:
|
||||||
|
FlipperRSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
folly::EventBase* eventBase);
|
||||||
|
FlipperRSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
folly::EventBase* eventBase,
|
||||||
|
ConnectionContextStore* connectionContextStore);
|
||||||
|
|
||||||
|
virtual ~FlipperRSocket() {}
|
||||||
|
|
||||||
|
virtual void setEventHandler(SocketEventHandler eventHandler) override;
|
||||||
|
virtual void setMessageHandler(SocketMessageHandler messageHandler) override;
|
||||||
|
|
||||||
|
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||||
|
virtual void disconnect() override;
|
||||||
|
|
||||||
|
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||||
|
override;
|
||||||
|
virtual void send(const std::string& message, SocketSendHandler completion)
|
||||||
|
override;
|
||||||
|
virtual void sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FlipperConnectionEndpoint endpoint_;
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload_;
|
||||||
|
folly::EventBase* eventBase_;
|
||||||
|
ConnectionContextStore* connectionContextStore_;
|
||||||
|
|
||||||
|
std::unique_ptr<rsocket::RSocketClient> client_;
|
||||||
|
|
||||||
|
SocketEventHandler eventHandler_;
|
||||||
|
SocketMessageHandler messageHandler_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
76
xplat/Flipper/FlipperSocket.h
Normal file
76
xplat/Flipper/FlipperSocket.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <folly/dynamic.h>
|
||||||
|
#include <rsocket/RSocket.h>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include "FlipperTransportTypes.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
class FlipperConnectionManager;
|
||||||
|
class ConnectionContextStore;
|
||||||
|
class FlipperSocket {
|
||||||
|
public:
|
||||||
|
virtual ~FlipperSocket() {}
|
||||||
|
/**
|
||||||
|
Sets the socket event handler. Used to observe underlying socket state
|
||||||
|
changes.
|
||||||
|
@param eventHandler Observer to be notified of state changes.
|
||||||
|
*/
|
||||||
|
virtual void setEventHandler(SocketEventHandler eventHandler) = 0;
|
||||||
|
/**
|
||||||
|
Sets the socket message handler. Used to handle received messages.
|
||||||
|
@param messageHandler Received messages handler.
|
||||||
|
*/
|
||||||
|
virtual void setMessageHandler(SocketMessageHandler messageHandler) = 0;
|
||||||
|
/**
|
||||||
|
Connect the socket to the specified endpoint. This is a blocking call
|
||||||
|
meaning that it will return once the socket is connected and ready to be
|
||||||
|
used or error.
|
||||||
|
@param manager An instance of FlipperConnectionManager.
|
||||||
|
*/
|
||||||
|
virtual bool connect(FlipperConnectionManager* manager) = 0;
|
||||||
|
/**
|
||||||
|
Disconnect from the endpoint.
|
||||||
|
*/
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
/**
|
||||||
|
Send a message to the receiving end.
|
||||||
|
@param message A message to be sent.
|
||||||
|
@param completion A completion handler to be invoked when the message has
|
||||||
|
been sent.
|
||||||
|
*/
|
||||||
|
virtual void send(
|
||||||
|
const folly::dynamic& message,
|
||||||
|
SocketSendHandler completion) = 0;
|
||||||
|
/**
|
||||||
|
Send a message to the receiving end.
|
||||||
|
@param message A message to be sent.
|
||||||
|
@param completion A completion handler to be invoked when the message has
|
||||||
|
been sent.
|
||||||
|
*/
|
||||||
|
virtual void send(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendHandler completion) = 0;
|
||||||
|
/**
|
||||||
|
Send a message and expect a response.
|
||||||
|
@param message A message to be sent.
|
||||||
|
@param completion A completion handler to be invoked when a response is
|
||||||
|
received.
|
||||||
|
*/
|
||||||
|
virtual void sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
136
xplat/Flipper/FlipperTransportTypes.h
Normal file
136
xplat/Flipper/FlipperTransportTypes.h
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
SocketEvent defines the socket states used by Flipper.
|
||||||
|
*/
|
||||||
|
enum class SocketEvent : int {
|
||||||
|
OPEN,
|
||||||
|
CLOSE,
|
||||||
|
ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines a socket event handler. Used to notify changes in socket state.
|
||||||
|
Possible events are but not limited to: open, close, error.
|
||||||
|
*/
|
||||||
|
typedef std::function<void(SocketEvent)> SocketEventHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines a socket message received handler.
|
||||||
|
*/
|
||||||
|
typedef std::function<void(const std::string& message)> SocketMessageHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines a socket certificate provider. The provider is responsible of returning
|
||||||
|
the necessary client certificate used to establish a valid secure connection.
|
||||||
|
@param password Empty buffer which will be set by the provider with the
|
||||||
|
certificate password.
|
||||||
|
@param length Length of the password buffer.
|
||||||
|
*/
|
||||||
|
typedef std::function<std::string(char* password, size_t length)>
|
||||||
|
SocketCertificateProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines a socket send completion handler. This is used to notify the caller
|
||||||
|
that data has been sent to the receiving end.
|
||||||
|
*/
|
||||||
|
typedef std::function<void()> SocketSendHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines a socket send completion handler for the cases where a response is
|
||||||
|
expected. This is used to notify the caller when a response has been received.
|
||||||
|
@param response Received response.
|
||||||
|
@param isError Indicates whether an error has taken place in which case the
|
||||||
|
response will contain text describing the error.
|
||||||
|
*/
|
||||||
|
typedef std::function<void(std::string response, bool isError)>
|
||||||
|
SocketSendExpectResponseHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines a serializer than can be used to serialize socket payloads.
|
||||||
|
*/
|
||||||
|
struct FlipperPayloadSerializer {
|
||||||
|
virtual ~FlipperPayloadSerializer() {}
|
||||||
|
virtual void put(std::string key, std::string value) = 0;
|
||||||
|
virtual void put(std::string key, int value) = 0;
|
||||||
|
virtual std::string serialize() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines the base payload used to establish a connection in Flipper.
|
||||||
|
*/
|
||||||
|
struct FlipperSocketBasePayload {
|
||||||
|
std::string os;
|
||||||
|
std::string device;
|
||||||
|
std::string device_id;
|
||||||
|
std::string app;
|
||||||
|
int sdk_version;
|
||||||
|
int medium;
|
||||||
|
FlipperSocketBasePayload() {}
|
||||||
|
FlipperSocketBasePayload(
|
||||||
|
std::string os,
|
||||||
|
std::string device,
|
||||||
|
std::string device_id,
|
||||||
|
std::string app)
|
||||||
|
: os(std::move(os)),
|
||||||
|
device(std::move(device)),
|
||||||
|
device_id(std::move(device_id)),
|
||||||
|
app(std::move(app)) {}
|
||||||
|
virtual ~FlipperSocketBasePayload() {}
|
||||||
|
virtual void serialize(FlipperPayloadSerializer& serializer) {
|
||||||
|
serializer.put("os", os);
|
||||||
|
serializer.put("device", device);
|
||||||
|
serializer.put("device_id", device_id);
|
||||||
|
serializer.put("app", app);
|
||||||
|
serializer.put("sdk_version", sdk_version);
|
||||||
|
serializer.put("medium", medium);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines the secure payload used to establish a secure connection in Flipper.
|
||||||
|
*/
|
||||||
|
struct FlipperSocketSecurePayload : public FlipperSocketBasePayload {
|
||||||
|
std::string csr;
|
||||||
|
std::string csr_path;
|
||||||
|
FlipperSocketSecurePayload() {}
|
||||||
|
FlipperSocketSecurePayload(
|
||||||
|
std::string os,
|
||||||
|
std::string device,
|
||||||
|
std::string device_id,
|
||||||
|
std::string app)
|
||||||
|
: FlipperSocketBasePayload(os, device, device_id, app) {}
|
||||||
|
virtual ~FlipperSocketSecurePayload() {}
|
||||||
|
virtual void serialize(FlipperPayloadSerializer& serializer) {
|
||||||
|
FlipperSocketBasePayload::serialize(serializer);
|
||||||
|
serializer.put("csr", csr);
|
||||||
|
serializer.put("csr_path", csr_path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines a connection endpoint used by Flipper.
|
||||||
|
*/
|
||||||
|
struct FlipperConnectionEndpoint {
|
||||||
|
std::string host;
|
||||||
|
int port;
|
||||||
|
bool secure;
|
||||||
|
|
||||||
|
FlipperConnectionEndpoint(std::string host, int port, bool secure)
|
||||||
|
: host(std::move(host)), port(port), secure(secure) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
Reference in New Issue
Block a user