Trasferimento di file
THIS PAGE IS DEPRECATED: READ File transfer
Come usarlo?
Android
Quando parli con qualcuno su Android, hai la possibilità di inviare una foto sul tuo dispositivo o scattare una foto con questi pulsanti:
! [botoni di file di Android]
Nota: quando inviate un file, l’altro deve accettarlo. In questo momento vedrete “peer in attesa”:
Come funziona?
Come funziona
Introduzione
Jami è un’applicazione distribuita e deve funzionare senza alcuna connessione internet. Quindi, anche il trasferimento di file! in pratica, usiamo lo stesso metodo per eseguire il trasferimento di file e le chiamate, ma in TCP. Per riassumere come funziona, possiamo immaginare una situazione in cui Alice (A) vuole trasferire un file a Bob (B).
Per farlo, Jami sta usando ICE (RFC 6544), un protocollo utilizzato per negoziare i collegamenti tra pari. Alice invierà, in un pacchetto crittografato tramite il DHT l’ip del suo dispositivo. Quindi, quando Bob riceverà gli ips di Alice, saranno in grado di negoziare un trasporto in cui Bob sarà in grado di inviare i pacchetti ad Alice. Il negoziato può essere successo, ma se fallirà, un server TURN sarà utilizzato (quello configurato nelle impostazioni) per eseguire il trasferimento. Se il negoziato riesce, Bob invierà i suoi ips ad Alice per eseguire la negoziazione nell’altra direzione.
Ora che il collegamento TCP bidirezionale è qui, il passo successivo sarà quello di negoziare un TLS 1.3 (generalmente un (TLS1.3)-DHE-FFDHE8192)-RSA-PSS-RSAE-SHA384)-AES-256-GCM) quando scrivo queste righe) tra Alice e Bob, poi Alice inizierà a trasferire il file.
La prima parte sarà un piccolo intestazione per descrivere il contenuto del file.
Processo
Invio di un file
Si utilizza il seguente metodo:
1. Un cliente chiamera” DataTransferFacade::sendFile()
. DataTransferFacade
è la classe corrispondente all’API esposta per i clienti. È utilizzato per gestire una vista dei trasferimenti di file (le classi corrispondenti sono DataTransfer
, IncomingFileTransfer
, OutgoingFileTransfer
e SubOutgoingFileTransfer
). Questo metodo chiederà al collegato JamiAccount
di richiedere una connessione.
![Diagramma: Diagramma di classe di trasferimento dati]images/file-transfer-dataatransfer-class-diagram.png)
2. Il metodo DhtPeerConnector: requestConnection()
viene attivato e crea una connessione tra tutti i dispositivi collegati del peer (trovati sul DHT). DhtPeerConnector
viene utilizzato per gestire il loop di evento principale che gestisce le connessioni. Quando viene trovato un dispositivo, il event loop creerà un ClientConnector
(che gestisce la connessione per un dispositivo) e lancerà il metodo process)
.
3. Questo metodo viene utilizzato per avviare il trasporto ICE e inserire un PeerConnectionMsg (che contiene il messaggio SDP, vedere sotto) sul DHT e attendere una risposta (DhtPeerConnector::Impl::onResponseMsg
).
4. Poi viene ricevuta una risposta dal DHT, che contiene indirizzi pubblici del dispositivo peer. Ora possiamo negoziare un collegamento TLS (direttamente tramite ICE, o tramite TURN come fallback). Questo TlsSocketEndpoint
viene dato all’oggetto PeerConnection
come output e il trasferimento può iniziare.
Quando la presa TLS è pronta, viene chiamata la callback DataTransferFacade::Impl::onConnectionRequestReply
, e un OutgoingFileTransfer
è collegato alla PeerConnection
come input. Questo OutgoingFileTransfer
contiene un elenco di SubOutgoingFileTransfer
(uno per dispositivo) in cui ogni sotto-trasferimento è un trasferimento a un dispositivo. Lo facciamo per poter fornire la visione più ottimista del trasferimento (se un contatto come 3 dispositivi, in cui il contatto annulla il trasferimento su un dispositivo, ma ha accettato il trasferimento su gli altri due, verrà mostrato il trasferimento più avanzato).
6. Il SubOutgoingFileTransfer
trasferirà prima l’intestazione del file, attenderà l’accettazione da parte dei colleghi (un messaggio «GO\n» sul socket) e poi invierà il file.
7. Se viene ricevuta una cancellazione dal peer o dal cliente o se il trasferimento di file termina, la connessione verrà chiusa tramite un messaggio CANCEL
sul DhtPeerConnector::eventLoop()
e le risorse saranno rilasciate.
Ricezione di un file
La stessa struttura viene utilizzata per ricevere file, ma il metodo cambia un po”:
La classe
JamiAccount
viene utilizzata per ricevere i messaggi dal DHT, perché la prima cosa ricevuta sarà la richiesta DHT.In seguito, questo messaggio viene trasmesso a
DhtPeerConnector: onRequestMessage()
attraverso l’eventLoop.Il
DhtPeerConnector::Impl::answerToRequest
cercherà di connettersi al server TURN (se non collegato) e inizializzarà il trasporto ICE. Questo metodo aprirà 2 connessioni di controllo a un server TURN (uno per autorizzare i colleghi IPv4, un altro per i colleghi IPv6, a causa di RFC 6156) se non è già aperto e consentirà agli indirizzi pubblici Peer di connettersi. Quindi, se l’SDP ricevuto non contiene candidati ICE, utilizzerà il TURN e elaborerà la risposta SDP per aspettare il collegamento. Se l’SDP contiene i candidati ICE, il metodo cercherà di negoziare il collegamento (o di tornare indietro sul TURN) e quindi rispondere allo SDP (con i candidati ICE o meno).Una volta che i collegamenti sono pronti, come il mittente, un collegamento TLS viene negoziato e dato alla
PeerConnection
dato allaIncomingFileTransfer
come input.
Richiedere un trasferimento di file precedente
As specified in Other mime types, the data-transfer interactions are now synced and stored into conversations. So, a device can easily detects if a file was downloaded or not. If not, it can asks all members in the conversation to transmits the file again.
Per questo, il dispositivo invierà un json con il tipo di mime: applicazione/chiesta di trasferimento dati+json
contenente conversazione
(id della conversazione), interazione
(interazione correlata), deviceId
il dispositivo che riceve il file.
Il mittente verifica ora se il dispositivo è un dispositivo del pari annunciato e che il dispositivo è un membro della conversazione, e può inviare il file tramite un trasferimento di file classico.
Il ricevitore può ora accettare il primo trasferimento in entrata, scaricare il file e verificare che la sha3sum sia corretta.
Schema
! [Diagramma: schema principale]
SDP inviato attraverso il DHT
0d04b932
7c33834e7cf944bf0e367b47
H6e6ca682 1 TCP 2130706431 2607:fad8:4:6:9eb6:d0ff:dead:c0de 50693 typ host tcptype passive
H6e6ca682 1 TCP 2130706431 2607:fad8:4:6:9eb6:d0ff:dead:c0de 9 typ host tcptype active
H42c1b577 1 TCP 2130706431 fe80::9eb6:d0ff:fee7:1412 50693 typ host tcptype passive
H42c1b577 1 TCP 2130706431 fe80::9eb6:d0ff:fee7:1412 9 typ host tcptype active
Hc0a8007e 1 TCP 2130706431 192.168.0.123 42751 typ host tcptype passive
Hc0a8007e 1 TCP 2130706431 192.168.0.123 9 typ host tcptype active
Sc0a8007e 1 TCP 1694498815 X.X.X.X 42751 typ srflx tcptype passive
Z.Z.Z.Z:YYYY
A.A.A.A:YYYY
Dove 0d04b932
è l’ufrag e 7c33834e7cf944bf0e367b47
la password della sessione ICE. 2130706431
e 1694498815
sono la priorità dei candidati. 192.168.0.126 42751 tipo di ospite tcptype passivo
è un candidato ospite passivo e 1694498815 X.X.X.X 42751 tipo srflx tcptype passivo
un ospite passivo che riflette l’ip pubblico (immaginato tramite UPnP).
Dispositivi multi
A user can link its account to several devices. So, we need to implement the transfer when a user send a file to a contact who have multiple devices linked to this account.
Primo approccio
Il primo approccio era quello di inviare una richiesta attraverso il DHT a tutti i dispositivi e i primi dispositivi che rispondono ottengono il file da trasferire.
Approccio attuale
Ora, inviamo ancora una richiesta a tutti i dispositivi. La differenza è che tutti i dispositivi avranno la notifica per ricevere un file e possono accettare / rifiutare il trasferimento.
Now (since https://review.jami.net/c/jami-daemon/+/9327), when a user send a file, it will request a PeerConnection with all peer devices. And for all connections, we attach a new input stream to have the ability to accept/refuse/cancel each transfer separately.
In data_transfer.cpp definiamo la classe OptimisticMetaOutgoingInfo che rappresenta la vista ottimista da mostrare al cliente. È ottimista perché se un contatto accetta un trasferimento su un dispositivo e rifiuta su altri, questa classe mostrerà il trasferimento di file in corso. E mostrerà un errore solo se tutti i dispositivi rifiutano il trasferimento.
Questa classe è collegata a SubOutgoingFileTransfer che rappresentano lo stato di un trasferimento con un dispositivo. I clienti avranno la possibilità di mostrare un trasferimento sotto in seguito (vedi lista TODO).
Utilizzando un altro server TURN
Actually the default TURN server is turn.jami.net. But you can host your own TURN server. For example by running a coturn server.
sudo turnserver -a -v -n -u utente:password -r "realm"
Then, you can configure the TURN server in the advanced settings of the app.
Nota: questo richiede alcune conoscenze tecniche. Inoltre, il server TURN dovrebbe vedere lo stesso indirizzo IP del nodo come il nodo di destinazione o la connessione di pari fallirà (perché l’autorizzazione sarà errata)
Lista TODO
Use libtorrent?
Mostra lo stato dei trasferimenti di sotto-connessione per i file in uscita