Transferência de arquivos

THIS PAGE IS DEPRECATED: READ File transfer

Como é que o usamos?

Android

Quando você está falando com alguém no Android, você tem a possibilidade de enviar uma foto no seu dispositivo ou tirar uma foto com estes botões:

Botões_de_arquivo_do_Android

Nota

When you send a file, the other has to accept it. At this moment you will see ‘awaiting peer’:

Android_esperando_par

Como funciona? (técnico)

Como funciona

Introdução

Jami é um aplicativo distribuído e tem que funcionar sem qualquer conexão com a internet. Então, transferência de arquivos também! Basicamente, usamos o mesmo método para realizar transferência de arquivos e chamadas, mas no TCP. Para resumir como funciona, podemos imaginar uma situação em que Alice (A) quer transferir um arquivo para Bob (B).

First, Alice will request a connection to Bob. To do that, Jami is using ICE (RFC 6544), a protocol used to negotiate links between peers. Alice will send, into an encrypted packet via the DHT the IP address of its device. So, when Bob receives the IP addresses of Alice, they will be able to negotiate a transport where Bob will be able to send packets to Alice. The negotiation can be successful, but if it fails, a TURN server will be used (the one configured into the settings) to perform the transfer. If the negotiation succeeds, Bob will send its IP addresses to Alice to perform the negotiation in the other direction. Note that the link is still not secure, so Bob will send the IP addresses through the DHT network in an encrypted message. If the second negotiation fails, the TURN will be used as a fallback.

Agora que o link TCP bidirecional está aqui, a próxima etapa será negociar um TLS 1.3 (geralmente um (TLS1.3)-(DHE-FFDHE8192)-(RSA-PSS-RSAE-SHA384)-(AES-256-GCM) quando escrevo estas linhas) entre Alice e Bob, e então Alice começará a transferir o arquivo.

A primeira parte será um pequeno cabeçalho para descrever o conteúdo do arquivo.

Processo

Envio de um arquivo

O método a seguir utilizado:

  1. A client will call DataTransferFacade::sendFile(). DataTransferFacade is the class corresponding to the API exposed for the clients. It is used to manage a view of the file transfers (the corresponding classes are DataTransfer, IncomingFileTransfer, OutgoingFileTransfer and SubOutgoingFileTransfer). This method will ask the linked JamiAccount to request a connection. Diagram: DataTransfer class diagram

  2. The method DhtPeerConnector: requestConnection() is triggered and creates a connection between all connected devices of the peer (found on the DHT). DhtPeerConnector is used to manage the main event loop which manage connections. When a device is found, the event loop will create a ClientConnector (which manage the connection for one device) and launch the process() method.

  3. This method is used to initialize the ICE transport and put a PeerConnectionMsg (which contains the SDP message, see below) on the DHT and waits for a response (DhtPeerConnector::Impl::onResponseMsg).

  4. Then a response is received from the DHT, which contains public addresses of the peer device. We can now negotiate a TLS link (directly via ICE, or via TURN as a fallback). This TlsSocketEndpoint is given to the PeerConnection object as an output and the transfer can start.

  5. When the TLS socket is ready, the callback DataTransferFacade::Impl::onConnectionRequestReply is called, and a OutgoingFileTransfer is linked to the PeerConnection as an input. This OutgoingFileTransfer contains a list of SubOutgoingFileTransfer (one per device) where each sub transfer is a transfer to one device. We do that to be able to furnish the most optimistic view of the transfer (if a contact as 3 devices, where the contact cancel the transfer on one device, but accepted the transfer on the two others, the most advanced transfer will be shown).

  6. The SubOutgoingFileTransfer will first transfer the header of the file, wait the peer acceptance (A “GO\n” message on the socket) and then will send the file.

  7. If a cancel is received from the peer or the client or if the file transfer finish, the connection will be closed via a CANCEL message on the DhtPeerConnector::eventLoop() and the resources will be released.

TLSsocketEndpoint

Recebimento de um arquivo

A mesma estrutura é usada para receber arquivos, mas o método muda um pouco:

  1. A classe JamiAccount é usada para receber mensagens do DHT, porque a primeira coisa recebida será a solicitação do DHT.

  2. Em seguida, esta mensagem é dada ao DhtPeerConnector: onRequestMessage() através do eventLoop.

  3. O DhtPeerConnector::Impl::answerToRequest tentará se conectar ao servidor TURN (se não estiver conectado) e inicializará o transporte ICE. Esse método abre 2 conexões de controle para um servidor TURN (uma para autorizar pares IPv4 e outra para pares IPv6, devido à RFC 6156) se ainda não estiver aberta e permite que os endereços públicos de pares se conectem. Em seguida, se o SDP recebido não contiver candidatos a ICE, usará o TURN e criará a resposta SDP para aguardar o par. Se o SDP contiver candidatos a ICE, o método tentará negociar o link (ou fallback no TURN) e, em seguida, responderá ao SDP (com candidatos a ICE ou não).

  4. Uma vez que os links estiverem prontos, como o remetente, um link TLS é negociado e dado à PeerConnection dada ao IncomingFileTransfer como entrada.

Re-pedir uma transferência de arquivo anterior

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.

Para isso, o dispositivo enviará um json com o tipo de mime: application/data-transfer-request+json contendo conversation (id da conversa), interaction (interação relacionada), deviceId o dispositivo que recebe o arquivo.

O remetente agora verifica se o dispositivo é um dispositivo do peer anunciado e que o dispositivo é um membro da conversa, e pode enviar o arquivo através de uma transferência de arquivo clássica.

O receptor pode agora aceitar a primeira transferência de entrada, baixar o arquivo e verificar que o sha3sum é correto.

Esquema

Diagrama: diagrama do esquema principal

SDP enviado através do 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

Where 0d04b932 is the ufrag and 7c33834e7cf944bf0e367b47 the password of the ICE session. 2130706431 and 1694498815 are the priority of the candidates. 192.168.0.126 42751 typ host tcptype passive is a passive host candidate and 1694498815 X.X.X.X 42751 typ srflx tcptype passive a passive host reflecting the public IP address (mapped via UPnP for example).

Dispositivos múltiplos

Um usuário pode vincular sua conta a vários dispositivos. Portanto, precisamos implementar a transferência quando um usuário envia um arquivo para um contato que tem vários dispositivos vinculados a essa conta.

Primeira abordagem

A primeira abordagem foi enviar uma solicitação através do DHT para todos os dispositivos e os primeiros dispositivos que respondem obter o arquivo para transferir.

abordagem atual

Agora, ainda enviamos uma solicitação para todos os dispositivos. A diferença é que todos os dispositivos terão a notificação para receber um arquivo e podem aceitar/recusar a transferência. A maior parte do código para isso está em data_transfer.cpp.

Agora (desde https://review.jami.net/c/jami-daemon/+/9327), quando um usuário enviar um arquivo, ele solicitará uma PeerConnection com todos os dispositivos pares. E para todas as conexões, anexamos um novo fluxo de entrada para poder aceitar/recusar/cancelar cada transferência separadamente.

Em data_transfer.cpp definimos a classe OptimisticMetaOutgoingInfo que representam a visão otimista para mostrar ao cliente. É otimista porque se um contato aceita uma transferência em um dispositivo e recusa em outros, esta classe mostrará a transferência de arquivo em curso. E só mostrará um erro se todos os dispositivos recusarem a transferência.

Essa classe está vinculada a SubOutgoingFileTransfer, que representa o estado de uma transferência com um dispositivo. Os clientes terão a capacidade de mostrar uma subtransferência em vez da otimista mais tarde (ver lista PARA FAZER).

Usando outro servidor 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 usuário:password -r "realm"

Em seguida, você pode configurar o servidor TURN nas configurações avançadas do aplicativo.

Nota

This needs some technical knowledge. Moreover, the TURN server should see the same IP address of your node as the destination node, or the peer connection will fail (because the authorization will be incorrect).

Lista de PARA FAZER

  1. Usar libtorrent?

  2. Mostre o status de subtransferências para arquivos saídos