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:
16 bits são usados para armazenar o comprimento do corpo.
16 bits para o canal id (destino)
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
Uma JamiAccount é proprietária do ConnectionManager e tem acesso aos objetos ChannelSocket (shared_ptr pertencente ao MultiplexedSocket.
O ConnectionManager possui objetos MultiplexedSockets e ICE
MultiplexedSockets possui o transporte TLS e os objetos ChannelSocket
O ChannelSocket é dono dos buffers de dados
Funções
O ConnectionManager é utilizado para gerir as ligações aos pares.
Os MultiplexedSockets são utilizados para enviar dados através do TLSSocket, ler os pacotes de entrada e gerir os canais.
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
)