Transferencia de archivos
ESTA PÁGINA ESTÁ OBSOLETA: LEER File transfer
¿Cómo usarlo?
Android
Cuando estás hablando con alguien en Android, tienes la posibilidad de enviar una foto en tu dispositivo o tomar una foto con estos botones:
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
Nota: cuando envías un archivo, el otro tiene que aceptarlo. En este momento verás “esperando a un compañero”:
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
¿Cómo funciona?
Cómo funciona
Introducción
Jami es una aplicación distribuida y tiene que funcionar sin conectividad a Internet. Así que, transferencia de archivos también! Básicamente, usamos el mismo método para realizar transferencias de archivos y llamadas, pero en TCP. Para resumir cómo funciona, podemos imaginar una situación en la que Alice (A) quiere transferir un archivo a Bob (B).
Para ello, Jami está utilizando ICE (RFC 6544), un protocolo utilizado para negociar enlaces entre pares. Alice enviará, a un paquete cifrado a través del DHT, el IP de su dispositivo. Así, cuando Bob reciba los ips de Alice, podrán negociar un transporte donde Bob podrá enviar paquetes a Alice. La negociación puede ser exitosa, pero si falla, se utilizará un servidor TURN (el configurado en las configuraciones) para realizar la transferencia. Si la negociación tiene éxito, Bob enviará sus ips a Alice para realizar la negociación en la otra dirección.
Ahora que el enlace TCP bidireccional está aquí, el siguiente paso será negociar un TLS 1.3 (generalmente un (TLS1.3)-(DHE-FFDHE8192)-(RSA-PSS-RSAE-SHA384)-(AES-256-GCM) cuando escriba estas líneas) entre Alice y Bob, entonces Alice comenzará a transferir el archivo.
La primera parte será un pequeño encabezado para describir el contenido del archivo.
Proceso
Enviando un archivo
Se utiliza el siguiente método:
1. Un cliente llamará DataTransferFacade::sendFile()
. DataTransferFacade
es la clase correspondiente a la API expuesta para los clientes. Se utiliza para administrar una vista de las transferencias de archivos (las clases correspondientes son DataTransfer
, IncomingFileTransfer
, OutgoingFileTransfer
y SubOutgoingFileTransfer
). Este método pedirá a la JamiAccount
vinculada a solicitar una conexión.
¡[Diagrama: Diagrama de clase de transferencia de datos]images/file-transfer-dataatransfer-class-diagram.png)
2. El método DhtPeerConnector: requestConnection()
se activa y crea una conexión entre todos los dispositivos conectados del peer (que se encuentran en la DHT). DhtPeerConnector
se utiliza para administrar el bucle principal de eventos que gestionan las conexiones. Cuando se encuentra un dispositivo, el bucle de eventos creará un ClientConnector
(que gestiona la conexión para un dispositivo) y lanzará el método proceso)
.
3. Este método se utiliza para iniciar el transporte ICE y colocar un PeerConnectionMsg (que contiene el mensaje SDP, véase más adelante) en el DHT y esperar una respuesta (DhtPeerConnector::Impl::onResponseMsg
).
4. Luego se recibe una respuesta del DHT, que contiene direcciones públicas del dispositivo de pares. Ahora podemos negociar un enlace TLS (directamente a través de ICE, o a través de TURN como una retroceso). Este TlsSocketEndpoint
se da al objeto PeerConnection
como salida y se puede iniciar la transferencia.
Cuando el socket TLS está listo, se llama la llamada de regreso DataTransferFacade::Impl::onConnectionRequestReply
, y un OutgoingFileTransfer
se vincula a la PeerConnection
como entrada. Este OutgoingFileTransfer
contiene una lista de SubOutgoingFileTransfer
(uno por dispositivo) donde cada subtransfer es una transferencia a un dispositivo. Lo hacemos para poder proporcionar la visión más optimista de la transferencia (si un contacto como 3 dispositivos, donde el contacto cancela la transferencia en un dispositivo, pero aceptó la transferencia en los otros dos, se mostrará la transferencia más avanzada).
6. El SubOutgoingFileTransfer
primero transferirá el encabezado del archivo, esperará la aceptación por pares (un mensaje «GO\n» en el socket) y luego enviará el archivo.
7. Si se recibe una cancelación del peer o del cliente o si la transferencia de archivos termina, la conexión se cerrará a través de un mensaje CANCEL
en el DhtPeerConnector::eventLoop()
y se liberarán los recursos.
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
Recibir un archivo
La misma estructura se utiliza para recibir archivos, pero el método cambia un poco:
La clase
JamiAccount
se utiliza para recibir mensajes del DHT, porque lo primero que se recibirá será la solicitud del DHT.Luego, este mensaje se le da a
DhtPeerConnector: onRequestMessage()
a través del eventLoop.El
DhtPeerConnector::Impl::answerToRequest
intentará conectarse al servidor TURN (si no está conectado) e iniciar el transporte ICE. Este método abrirá 2 conexiones de control a un servidor TURN (una para autorizar pares IPv4, otra para pares IPv6, debido a RFC 6156) si ya no está abierto y permite que las direcciones públicas de pares se conecten. Luego, si el SDP recibido no contiene candidatos ICE, utilizará el TURN y elaborará la respuesta SDP para esperar al pares. Si el SDP contiene candidatos ICE, el método intentará negociar el enlace (o retroceder en el TURN) y luego responder al SDP (con candidatos ICE o no).Una vez que los enlaces están listos, como el remitente, se negocia un enlace TLS y se le da a la
PeerConnection
dado a laIncomingFileTransfer
como entrada.
Re-pedir una transferencia de archivos anterior
Como se especifica en Other mime types, las interacciones de transferencia de datos ahora se sincronizan y almacenan en conversaciones. Por lo tanto, un dispositivo puede detectar fácilmente si un archivo se descargó o no. De lo contrario, puede solicitar a todos los miembros de la conversación que transmitan el archivo nuevamente.
Para ello, el dispositivo enviará un json con el tipo de mime: application/data-transfer-request+json
que contiene conversation
(id de la conversación), interaction
(interacción relacionada), deviceId
el dispositivo que recibe el archivo.
El remitente ahora verifica si el dispositivo es un dispositivo del compañero anunciado y que el dispositivo es un miembro de la conversación, y puede enviar el archivo a través de una transferencia de archivos clásica.
El receptor ahora puede aceptar la primera transferencia entrante, descargar el archivo y verificar que la sha3sum es correcta.
Esquema
¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
SDP enviado por el 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
Donde 0d04b932
es el ufrag y 7c33834e7cf944bf0e367b47
la contraseña de la sesión ICE. 2130706431
y 1694498815
son la prioridad de los candidatos. 192.168.0.126 42751 tipo de anfitrión tcptype pasivo
es un anfitrión pasivo candidato y 1694498815 X.X.X 42751 tipo srflx tcptype pasivo
un anfitrión pasivo que refleja la ip pública (mapeado a través de UPnP por ejemplo).
Dispositivos múltiples
Un usuario puede vincular su cuenta a varios dispositivos. Entonces, necesitamos implementar la transferencia cuando un usuario envía un archivo a un contacto que tiene varios dispositivos vinculados a esta cuenta.
Primero enfoque
El primer enfoque fue enviar una solicitud a través del DHT a todos los dispositivos y los primeros dispositivos que respondieron obtienen el archivo para transferir.
Enfoque actual
Ahora, todavía enviamos una solicitud a todos los dispositivos. La diferencia es que todos los dispositivos tendrán la notificación para recibir un archivo y pueden aceptar / rechazar la transferencia. La mayor parte del código para eso está en data_transfer.cpp.
Ahora (desde https://review.jami.net/c/jami-daemon/+/9327), cuando un usuario envíe un archivo, solicitará una Conexión entre pares con todos los dispositivos entre pares. Y para todas las conexiones, adjuntamos un nuevo flujo de entrada para tener la capacidad de aceptar/rechazar/cancelar cada transferencia por separado.
En data_transfer.cpp definimos la clase OptimisticMetaOutgoingInfo que representa la vista optimista para mostrar al cliente. Es optimista porque si un contacto acepta una transferencia en un dispositivo y se niega en otros, esta clase mostrará la transferencia de archivos en curso. Y solo mostrará un error si todos los dispositivos rechazan la transferencia.
Esta clase está vinculada a SubOutgoingFileTransfer que representan el estado de una transferencia con un dispositivo. Los clientes tendrán la capacidad de mostrar una subtransferencia en lugar de la optimista más adelante (ver lista TODO).
Usando otro servidor TURN
En realidad, el servidor TURN predeterminado es turn.jami.net. Pero puede alojar su propio servidor TURN. Por ejemplo, ejecutando un servidor coturn.
sudo turnserver -a -v -n -u usuario: contraseña -r "realm"
Luego, puede configurar el servidor TURN en la configuración avanzada de la aplicación.
Nota: esto requiere algunos conocimientos técnicos. Además, el servidor TURN debe ver la misma dirección IP de su nodo que el nodo de destino o la conexión de pares fallará (porque la autorización será incorrecta)
Lista de todos
¿Usas libtorrent?
Muestre el estado de las subtransferencias para archivos salientes