Commit 5f13f843 authored by Guillaume Roguez's avatar Guillaume Roguez Committed by Anthony Léonard

datatransfer: provide account/peer information

Fill AccountId and Peer field of outgoing and incoming data transfers.

Change-Id: I772e9c4560fb63c30e33c341cd296cacd6a45df6
Reviewed-by: default avatarAnthony Léonard <anthony.leonard@savoirfairelinux.com>
parent 1b68da64
......@@ -104,7 +104,7 @@ DataTransfer::emit(DRing::DataTransferEventCode code) const
class FileTransfer final : public DataTransfer
{
public:
FileTransfer(DRing::DataTransferId id, const std::string&, const std::string&);
FileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info);
bool start() override;
......@@ -121,18 +121,15 @@ private:
const std::string peerUri_;
};
FileTransfer::FileTransfer(DRing::DataTransferId id,
const std::string& file_path,
const std::string& display_name)
: DataTransfer(id)
FileTransfer::FileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info)
: DataTransfer(tid)
{
input_.open(file_path, std::ios::binary);
input_.open(info.path, std::ios::binary);
if (!input_)
throw std::runtime_error("input file open failed");
info_ = info;
info_.isOutgoing = true;
info_.displayName = display_name;
info_.path = file_path;
// File size?
input_.seekg(0, std::ios_base::end);
......@@ -205,7 +202,7 @@ FileTransfer::read(std::vector<uint8_t>& buf) const
class IncomingFileTransfer final : public DataTransfer
{
public:
IncomingFileTransfer(DRing::DataTransferId, const std::string&, std::size_t, std::size_t,
IncomingFileTransfer(DRing::DataTransferId, const DRing::DataTransferInfo&,
std::atomic<std::size_t>&);
bool start() override;
......@@ -225,21 +222,16 @@ private:
std::promise<void> filenamePromise_;
};
IncomingFileTransfer::IncomingFileTransfer(DRing::DataTransferId id,
const std::string& display_name,
std::size_t total_size,
std::size_t offset,
IncomingFileTransfer::IncomingFileTransfer(DRing::DataTransferId tid,
const DRing::DataTransferInfo& info,
std::atomic<std::size_t>& progress_storage)
: DataTransfer(id)
: DataTransfer(tid)
, progressStorage_ {progress_storage}
{
RING_WARN() << "[FTP] incoming transfert of " << total_size << " byte(s): " << display_name;
(void)offset;
RING_WARN() << "[FTP] incoming transfert of " << info.totalSize << " byte(s): " << info.displayName;
info_ = info;
info_.isOutgoing = false;
info_.displayName = display_name;
info_.totalSize = total_size;
// TODO: use offset?
emit(DRing::DataTransferEventCode::created);
}
......@@ -257,7 +249,7 @@ IncomingFileTransfer::requestFilename()
{
emit(DRing::DataTransferEventCode::wait_host_acceptance);
#if 1
#if 0
// Now wait for DataTransferFacade::acceptFileTransfer() call
filenamePromise_.get_future().wait();
return info_.path;
......@@ -305,11 +297,8 @@ public:
mutable std::mutex mapMutex_;
std::unordered_map<DRing::DataTransferId, std::shared_ptr<DataTransfer>> map_;
std::shared_ptr<DataTransfer> createFileTransfer(const std::string& file_path,
const std::string& display_name);
std::shared_ptr<IncomingFileTransfer> createIncomingFileTransfer(const std::string& display_name,
std::size_t total_size,
std::size_t offset,
std::shared_ptr<DataTransfer> createFileTransfer(const DRing::DataTransferInfo& info);
std::shared_ptr<IncomingFileTransfer> createIncomingFileTransfer(const DRing::DataTransferInfo& info,
std::atomic<std::size_t>& progress_storage);
std::shared_ptr<DataTransfer> getTransfer(const DRing::DataTransferId& id);
......@@ -336,27 +325,23 @@ DataTransferFacade::Impl::getTransfer(const DRing::DataTransferId& id)
}
std::shared_ptr<DataTransfer>
DataTransferFacade::Impl::createFileTransfer(const std::string& file_path,
const std::string& display_name)
DataTransferFacade::Impl::createFileTransfer(const DRing::DataTransferInfo& info)
{
auto id = generateUID();
auto transfer = std::make_shared<FileTransfer>(id, file_path, display_name);
auto tid = generateUID();
auto transfer = std::make_shared<FileTransfer>(tid, info);
std::lock_guard<std::mutex> lk {mapMutex_};
map_.emplace(id, transfer);
map_.emplace(tid, transfer);
return transfer;
}
std::shared_ptr<IncomingFileTransfer>
DataTransferFacade::Impl::createIncomingFileTransfer(const std::string& display_name,
std::size_t total_size,
std::size_t offset,
DataTransferFacade::Impl::createIncomingFileTransfer(const DRing::DataTransferInfo& info,
std::atomic<std::size_t>& progress_storage)
{
auto id = generateUID();
auto transfer = std::make_shared<IncomingFileTransfer>(id, display_name, total_size, offset,
progress_storage);
auto tid = generateUID();
auto transfer = std::make_shared<IncomingFileTransfer>(tid, info, progress_storage);
std::lock_guard<std::mutex> lk {mapMutex_};
map_.emplace(id, transfer);
map_.emplace(tid, transfer);
return transfer;
}
......@@ -406,18 +391,25 @@ DataTransferFacade::sendFile(const std::string& account_id, const std::string& p
if (!fileutils::isFile(file_path))
throw std::invalid_argument("invalid input file");
auto transfer = pimpl_->createFileTransfer(file_path, display_name);
auto id = transfer->getId();
DRing::DataTransferInfo info;
info.accountId = account_id;
info.peer = peer_uri;
info.displayName = display_name;
info.path = file_path;
// remaining fields are overwritten
auto transfer = pimpl_->createFileTransfer(info);
auto tid = transfer->getId();
// IMPLEMENTATION NOTE: requestPeerConnection() may call the given callback a multiple time.
// This happen when multiple agents handle communications of the given peer for the given account.
// Example: Ring account supports multi-devices, each can answer to the request.
account->requestPeerConnection(
peer_uri,
[this, id] (PeerConnection* connection) {
pimpl_->onConnectionRequestReply(id, connection);
[this, tid] (PeerConnection* connection) {
pimpl_->onConnectionRequestReply(tid, connection);
});
return id;
return tid;
}
void
......@@ -459,12 +451,22 @@ DataTransferFacade::info(const DRing::DataTransferId& id) const
}
std::string
DataTransferFacade::onIncomingFileRequest(const std::string& display_name,
DataTransferFacade::onIncomingFileRequest(const std::string& account_id,
const std::string& peer_uri,
const std::string& display_name,
std::size_t total_size,
std::size_t offset,
std::atomic<std::size_t>& progress_storage)
{
auto transfer = pimpl_->createIncomingFileTransfer(display_name, total_size, offset, progress_storage);
DRing::DataTransferInfo info;
info.accountId = account_id;
info.peer = peer_uri;
info.displayName = display_name;
info.totalSize = total_size;
info.bytesProgress = offset;
// remaining fields are overwritten
auto transfer = pimpl_->createIncomingFileTransfer(info, progress_storage);
auto filename = transfer->requestFilename();
if (!filename.empty())
transfer->start(); // TODO: bad place, call only if file can be open
......
......@@ -70,7 +70,9 @@ public:
/// Create an IncomingFileTransfer object.
/// \return a filename to open where incoming data will be written or an empty string
/// in case of refusal.
std::string onIncomingFileRequest(const std::string& display_name, std::size_t total_size,
std::string onIncomingFileRequest(const std::string& account_id,
const std::string& peer_uri,
const std::string& display_name, std::size_t total_size,
std::size_t offset,
std::atomic<std::size_t>& progress_storage);
......
......@@ -35,8 +35,11 @@ namespace ring {
//==============================================================================
FtpServer::FtpServer()
FtpServer::FtpServer(const std::string& account_id,
const std::string& peer_uri)
: Stream()
, accountId_ {account_id}
, peerUri_ {peer_uri}
{}
DRing::DataTransferId
......@@ -56,7 +59,9 @@ bool
FtpServer::startNewFile()
{
// Request filename from client (WARNING: synchrone call!)
auto filename = Manager::instance().dataTransfers->onIncomingFileRequest(displayName_,
auto filename = Manager::instance().dataTransfers->onIncomingFileRequest(accountId_,
peerUri_,
displayName_,
fileSize_,
0 /* TODO: offset */,
rx_);
......
......@@ -33,7 +33,7 @@ namespace ring {
class FtpServer final : public Stream
{
public:
FtpServer();
FtpServer(const std::string& account_id, const std::string& peer_uri);
bool write(const std::vector<uint8_t>& buffer) override;
DRing::DataTransferId getId() const override;
......@@ -51,6 +51,8 @@ private:
READ_DATA,
};
const std::string accountId_;
const std::string peerUri_;
std::ofstream out_;
std::size_t fileSize_ {0};
std::atomic<std::size_t> rx_ {0};
......
......@@ -203,6 +203,7 @@ public:
private:
std::unique_ptr<ConnectedTurnTransport> turn_ep_;
std::unique_ptr<TurnTransport> turn_;
std::map<std::shared_ptr<dht::crypto::Certificate>, dht::InfoHash> certMap_;
dht::crypto::TrustList trustedPeers_;
protected:
......@@ -213,7 +214,8 @@ private:
void onTurnPeerConnection(const IpAddr&);
void onTurnPeerDisconnection(const IpAddr&);
void onRequestMsg(PeerConnectionMsg&&);
void onTrustedRequestMsg(PeerConnectionMsg&&, const std::shared_ptr<dht::crypto::Certificate>&);
void onTrustedRequestMsg(PeerConnectionMsg&&, const std::shared_ptr<dht::crypto::Certificate>&,
const dht::InfoHash&);
void onResponseMsg(PeerConnectionMsg&&);
void onAddDevice(const dht::InfoHash&,
const std::shared_ptr<dht::crypto::Certificate>&,
......@@ -401,8 +403,26 @@ DhtPeerConnector::Impl::onTurnPeerConnection(const IpAddr& peer_addr)
auto tls_ep = std::make_unique<TlsTurnEndpoint>(*turn_ep, account.identity(),
account.dhParams(), trustedPeers_);
tls_ep->connect(); // block until TLS negotiated (throw in case of error)
// Find who is connected by using connection certificate
dht::InfoHash peer_h;
auto& connected_cert = tls_ep->peerCertificate();
for (const auto& item : certMap_) {
if (item.first->getPacked() == connected_cert.getPacked()) {
peer_h = item.second;
break;
}
}
// Not found? Considering this case as an attack!
if (!peer_h) {
RING_WARN() << "[CNX] unknown certificate from ip " << peer_addr.toString(true, true);
return;
}
RING_DBG() << account << "[CNX] Accepted TLS-TURN connection from RingID " << peer_h;
auto connection = std::make_unique<PeerConnection>(account, peer_addr.toString(), std::move(tls_ep));
connection->attachOutputStream(std::make_shared<FtpServer>());
connection->attachOutputStream(std::make_shared<FtpServer>(account.getAccountID(), peer_h.toString()));
servers_.emplace(peer_addr, std::move(connection));
// note: operating this way let endpoint to be deleted safely in case of exceptions
......@@ -428,18 +448,24 @@ DhtPeerConnector::Impl::onRequestMsg(PeerConnectionMsg&& request)
account.findCertificate(
request.from,
[this, request=std::move(request)] (const std::shared_ptr<dht::crypto::Certificate>& cert) mutable {
/* TODO: certificate trusted? */
onTrustedRequestMsg(std::move(request), cert);
dht::InfoHash peer_h;
if (account.foundPeerDevice(cert, peer_h))
onTrustedRequestMsg(std::move(request), cert, peer_h);
else
RING_WARN() << account << "[CNX] rejected untrusted connection request from "
<< request.from;
});
}
void
DhtPeerConnector::Impl::onTrustedRequestMsg(PeerConnectionMsg&& request,
const std::shared_ptr<dht::crypto::Certificate>& cert)
const std::shared_ptr<dht::crypto::Certificate>& cert,
const dht::InfoHash& peer_h)
{
turnConnect(); // start a TURN client connection on first pass, next ones just add new peer cnx handlers
// Save peer certificate for later TLS session (MUST BE DONE BEFORE TURN PEER AUTHORIZATION)
certMap_.insert(std::make_pair(cert, peer_h));
trustedPeers_.add(*cert);
for (auto& ip: request.addresses) {
......
......@@ -341,6 +341,14 @@ class RingAccount : public SIPAccountBase {
std::function<void(const std::shared_ptr<RingAccount>&,
const dht::InfoHash&)> op,
std::function<void(bool)> end = {});
/**
* Inform that a potential peer device have been found.
* Returns true only if the device certificate is a valid Ring device certificate.
* In that case (true is returned) the account_id parameter is set to the peer account ID.
*/
static bool foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, dht::InfoHash& account_id);
private:
NON_COPYABLE(RingAccount);
......@@ -417,13 +425,6 @@ class RingAccount : public SIPAccountBase {
*/
bool foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, const std::string& name = {}, const time_point& last_sync = time_point::min());
/**
* Inform that a potential peer device have been found.
* Returns true only if the device certificate is a valid Ring device certificate.
* In that case (true is returned) the account_id parameter is set to the peer account ID.
*/
static bool foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& crt, dht::InfoHash& account_id);
/**
* For a call with (from_device, from_account), check the peer certificate chain (cert_list, cert_num)
* with session check status.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment