jami-docs

Forked version of Jami documentation, see wrycode.com/jami-docs-demo
git clone git://git.wrycode.com/wrycode/jami-docs.git
Log | Files | Refs

file-transfer.md (10509B)


      1 # File Transfers
      2 
      3 ## How to use it?
      4 
      5 
      6 #### Gnome
      7 
      8 For sending a file on gnome, in a conversation you need to click to the
      9 send file icon at the bottom right of the conversation:
     10 
     11 Then you will see your image as soon as the transfer is finished (and
     12 show images is activated)
     13 
     14 On the contrary if you receive a file (and if it's not a picture < 20
     15 Mb), you will have to accept the transfer:
     16 
     17 And then the file will be sent. You have the possibility to cancel in a
     18 middle of a transfer.
     19 
     20 #### Android
     21 
     22 When you are talking to somebody on Android, you have the possibility to
     23 send a picture on your device or take a photo with these buttons:
     24 
     25 Note: when you send a file, the other has to accept it. At this moment
     26 you will see 'awaiting peer':
     27 
     28 ## How it works? (technical)
     29 
     30 
     31 ### How it works
     32 
     33 #### Introduction
     34 
     35 Jami is a distributed application and has to work without any internet connectivity. So, file transfer too! Basically, we use the same method to perform file transfer and calls, but in TCP. To summarize how it works, we can imagine a situation where Alice (A) wants to transfer a file to Bob (B).
     36 
     37 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 of its device. So, when Bob receives the ips 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 ips to Alice to perform the negotiation in the other direction. Note that the link is still not secure, so Bob will send the ips through the DHT in an encrypted message. If the second negotiation fails, the TURN will be used as a fallback.
     38 
     39 Now that the bidirectionnal TCP link is here, the next step will be to negotiate a TLS 1.3 (generally a (TLS1.3)-(DHE-FFDHE8192)-(RSA-PSS-RSAE-SHA384)-(AES-256-GCM) when I write these lines) between Alice an Bob, then Alice will start to transfer the file.
     40 
     41 The first part will be a small header to describe the content of the file. Then, after Bob accepts the transfer, the full file will be transmitted.
     42 
     43 #### Process
     44 
     45 ##### Sending a file
     46 
     47 The following method is used:
     48 
     49 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.
     50 
     51 ![DataTransfer](DataTransfer.png)
     52 
     53 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.
     54 
     55 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`).
     56 
     57 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.
     58 
     59 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).
     60 
     61 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.
     62 
     63 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.
     64 
     65 ![TLSsocketEndpoint](TLSsocketEndpoint.png)
     66 
     67 ##### Receiving a file
     68 
     69 
     70 The same structure is used to receive files, but the method changes a bit:
     71 
     72 1. The `JamiAccount` class is used to receives messages from the DHT, because the first thing received will be the DHT request.
     73 2. Then, this message is given to `DhtPeerConnector: onRequestMessage()` through the eventLoop.
     74 3. The `DhtPeerConnector::Impl::answerToRequest` will try to connect to the TURN server (if not connected) and initialize the ICE transport. This method open 2 control connections to a TURN server (one to authorize IPv4 peers, another one for IPv6 peers, due to **RFC 6156**) if it's not already open and permit Peer public addresses to connect. Then, if the SDP received doesn't contains ICE candidates, will use the TURN and craft the SDP answer to wait for the peer. If the SDP contains ICE candidates, the method will try to negotiate the link (or fallback on the TURN) and then answer the SDP (with ICE candidates or not).
     75 4. Once the links are ready, like the sender, a TLS link is negotiated and given to the `PeerConnection` given to the `IncomingFileTransfer` as an input. The headers of the file will come and the client is now able to accept or cancel the transfer.
     76 
     77 ##### Schema
     78 
     79 ![Main](Main.png)
     80 
     81 ##### SDP sent over the DHT
     82 
     83 ```
     84 0d04b932
     85 7c33834e7cf944bf0e367b47
     86 H6e6ca682 1 TCP 2130706431 2607:fad8:4:6:9eb6:d0ff:dead:c0de 50693 typ host tcptype passive
     87 H6e6ca682 1 TCP 2130706431 2607:fad8:4:6:9eb6:d0ff:dead:c0de 9 typ host tcptype active
     88 H42c1b577 1 TCP 2130706431 fe80::9eb6:d0ff:fee7:1412 50693 typ host tcptype passive
     89 H42c1b577 1 TCP 2130706431 fe80::9eb6:d0ff:fee7:1412 9 typ host tcptype active
     90 Hc0a8007e 1 TCP 2130706431 192.168.0.123 42751 typ host tcptype passive
     91 Hc0a8007e 1 TCP 2130706431 192.168.0.123 9 typ host tcptype active
     92 Sc0a8007e 1 TCP 1694498815 X.X.X.X 42751 typ srflx tcptype passive
     93 Z.Z.Z.Z:YYYY
     94 A.A.A.A:YYYY
     95 ```
     96 
     97 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 (mapped via UPnP for example).
     98 
     99 #### PJSIP related patches.
    100 
    101 3 patches will be included into the PJSIP project:
    102 
    103 1. RFC 6062, used to perform TURN over TCP (merged upstream: pjproject - fa6616c43c7e19797084f4e02a67d1fb6fd99473)
    104 2. RFC 6544, used to perform ICE over TCP
    105 3. A fix for pj_activesock
    106 
    107 Note that the stack for the file transfer is:
    108 
    109 ```
    110 +-----------+----------------+-----------------------+
    111 +    STUN   +    TLS data    +          TLS data     +
    112 +-----------+----------------+-----------------------+
    113 +     RFC  4571 (RTP)        +  RFC  6062 (TURN TCP) +
    114 +----------------------------+-----------------------+
    115 +                           TCP                      +
    116 +----------------------------------------------------+
    117 ```
    118 
    119 ### Multi devices
    120 
    121 A RING user can link its account to several devices. So, we need to
    122 implement the transfer when a user send a file to a contact who have
    123 multiple devices linked to this account.
    124 
    125 #### First approach
    126 
    127 The first approach was to send a request through the DHT to all devices
    128 and the first devices which answers get the file to transfer. This is
    129 bad for your contact because they will not know which device will
    130 receives will get the transfer.
    131 
    132 #### Current approach
    133 
    134 Now, we still send a request to all devices. The difference is that all
    135 devices will have the notification for receiving a file and can
    136 accept/refuse the transfer. The major part of the code for that is in
    137 *data\_transfer.cpp*.
    138 
    139 Now (since <https://gerrit-ring.savoirfairelinux.com/#/c/9327/>), when a
    140 user send a file, it will request a *PeerConnection* with all peer
    141 devices. And for all connections, we attach a new input stream to have
    142 the ability to accept/refuse/cancel each transfer separately.
    143 
    144 In *data\_transfer.cpp* we define the *OptimisticMetaOutgoingInfo* class
    145 which represent the optimistic view to show to the client. It's
    146 optimistic because if a contact accept a transfer on one device and
    147 refuse on others, this class will show the ongoing file transfer. And it
    148 will only show an error if all devices refuse the transfer.
    149 
    150 This class is linked to *SubOutgoingFileTransfer* which represent the
    151 state of a transfer with one device. Clients will have the ability to
    152 show a sub transfer instead the optimistic later (see TODO list).
    153 
    154 ### Using another TURN server
    155 
    156 Actually the default TURN server is *turn.ring.cx*. But you can host
    157 your own TURN server. For example by running a
    158 [coturn](https://github.com/coturn/coturn) server.
    159 
    160 `sudo turnserver -a -v -n -u user:password -r "realm"`
    161 
    162 Then, you can configure the TURN server in the advanced settings of
    163 RING.
    164 
    165 Note: this needs some technical knowledges. Moreover, the TURN server
    166 should see the same ip address of your node as the destination node or
    167 the peer connection will fail (because the authorization will be
    168 incorrect)
    169 
    170 ## Future
    171 
    172 
    173 For now, if a file transfer fails when ongoing, the sender can't resume
    174 the transfer and must relaunch the whole transfer. In the future, there
    175 will be a retry button for resuming the transfer.
    176 
    177 Finally, because Ring do not support text conferences (just video
    178 conferences, where there is one master merging slaves SIP calls), there
    179 is no real file transfer in conferences. For now, when you are in a
    180 conference on the gnome client for example: A master, B and C slave. B
    181 will be able to send a file to A the master (C same) A will be able to
    182 send a file to B or to C (just have to select the correct conversation).
    183 
    184 ### TODO List
    185 
    186 1. Add unit-tests (https://gerrit-ring.savoirfairelinux.com/\#/c/9365/)
    187 2. Show subtransfers status for outgoing files
    188 3. Offset resume (for failed transfer)