O gestor de ligações (ConnectionManager)

Introdução

O gestor de ligações é a primeira parte das funcionalidades da conversação em grupo. Esta classe gere as ligações aos pares e oferece ao utilizador sockets multiplexados para os dispositivos a que se quer ligar. Por exemplo, se a Alice quiser ligar-se a um dos dispositivos do Bob para transferir 2 ficheiros, pedirá ao ConnectionManager para abrir 2 canais (um por ficheiro) para o Bob. Isto dará:

    aliceAccount->connectionManager().connectDevice(bobDeviceId, "file://file1",
        [](std::shared_ptr<ChannelSocket> socket) {
        if (socket) {
            // transfer first file
        }
    });

    aliceAccount->connectionManager().connectDevice(bobDeviceId, "file://file2",
        [](std::shared_ptr<ChannelSocket> socket) {
        if (socket) {
            // transfer second file
        }
    });

Por detrás disso, o ConnectionManager liga-se primeiro ao dispositivo do Bob através da DHT (via ICE) e configura um Socket TLS. Em seguida, ele pedirá um canal e, quando o canal estiver pronto, informará Alice por meio de um retorno de chamada. Para o segundo ficheiro, utilizará o primeiro socket e abrirá apenas um novo canal (apenas necessita de 2 pacotes TLS, por isso é rápido)

Lado DHT

É o mesmo que Chamadas, ver Trocar candidatos ICE, Negociação ICE, Encriptar a tomada de controlo mas apenas em TCP.

No entanto, quando um lado recebe um novo pedido ICE, é acionada a chamada de retorno definida por void onICERequest(onICERequestCallback&& cb);.

Negociar um novo canal

Um canal é definido por um id (único) e um uri (não único). Por exemplo (1, “git://*”)

Quando estiver pronto, o ConnectionManager considera que o canal 0 existe. Este canal é chamado o canal CONTROL e é utilizado para pedir novos canais.

O protocolo utilizado é bastante simples e assemelha-se ao protocolo RTP:

  1. 16 bits são usados para armazenar o comprimento do corpo.

  2. 16 bits para o canal id (destino)

  3. corpo

Assim, todos os pacotes têm um cabeçalho len de 32 bits.

Para pedir um novo canal, o ConnectionManager enviará um objeto ChannelRequest (o msgpack é utilizado para serializar a estrutura) no canal 0 para enviar o id e o nome do novo canal ao par (com isAnswer = false). O par irá chamar o callback dado com ̀ void onChannelRequest(ChannelRequestCallBack&& cb); e irá recusar ou aceitar o pedido. Se aceite, o par responderá com um ChannelRequest com os mesmos dados (e ̀isAnswer = true`) e então os callbacks de ambos os pares serão acionados para informar que o ChannelSock é utilizável.

Fechar um canal

É transmitido um EOF para um canal se o comprimento do conteúdo for 0.

Estrutura do gestor de ligações

Propriedade

  1. Uma JamiAccount é proprietária do ConnectionManager e tem acesso aos objetos ChannelSocket (shared_ptr pertencente ao MultiplexedSocket.

  2. O ConnectionManager possui objetos MultiplexedSockets e ICE

  3. MultiplexedSockets possui o transporte TLS e os objetos ChannelSocket

  4. O ChannelSocket é dono dos buffers de dados

Funções

  1. O ConnectionManager é utilizado para gerir as ligações aos pares.

  2. Os MultiplexedSockets são utilizados para enviar dados através do TLSSocket, ler os pacotes de entrada e gerir os canais.

  3. Os ChannelSockets são utilizados pelo cliente para interagir com o outro par.

Utilização

Os cenários são descritos nos testes unitários correspondentes (test/unitTest/connectionManager/connectionManager.cpp)