RTCQuicTransport chega a um teste de origem perto de você (Chrome 73)

O quê?

O RTCQuicTransport é uma nova API de plataforma da Web que permite a troca de dados arbitrários com pares remotos usando o protocolo QUIC. Ele é destinado a casos de uso ponto a ponto e, portanto, é usado com uma API RTCIceTransport autônoma para estabelecer uma conexão ponto a ponto por meio do ICE. Os dados são transportados de maneira confiável e em ordem. Consulte a seção abaixo para detalhes sobre entregas não ordenadas e não confiáveis. Por ser um transporte de dados genérico e bidirecional, ele pode ser usado para jogos, transferências de arquivos, transporte de mídia, mensagens etc.

Por quê?

Uma API de transporte de dados de baixo nível pode permitir que aplicativos, como comunicações em tempo real, façam novas coisas na Web. Use a API como base, criando suas próprias soluções, ampliando os limites do que pode ser feito com conexões ponto a ponto, por exemplo, desbloqueando botões personalizados de alocação de taxa de bits. No futuro, mais suporte para mídia codificada poderá permitir a criação do seu próprio aplicativo de comunicação de vídeo com controles de baixo nível. O esforço de NV do WebRTC é mudar para APIs de nível inferior, e testar logo no início é valioso.

Por que o QUIC?

O protocolo QUIC é desejável para comunicações em tempo real. Ele é baseado em UDP, tem criptografia integrada e controle de congestionamento, além de ser multiplexado sem bloqueio de linha. O RTCQuicTransport oferece recursos muito semelhantes aos da API RTCDataChannel, mas usa o QUIC em vez do SCTP como protocolo de transporte. Como a RTCQuicTransport é uma API independente, ela não tem a sobrecarga da API RTCPeerConnection, que inclui a pilha de mídia em tempo real.

Como?

Visão geral da API

A API tem três abstrações principais: RTCIceTransport, RTCQuicTransport e RTCQuicStream.

Diagrama do RTCQuicTransport mostrando a arquitetura da API

RTCIceTransport

O ICE é um protocolo para estabelecer conexões ponto a ponto pela Internet e é usado atualmente no WebRTC. Esse objeto fornece uma API autônoma para estabelecer uma conexão ICE. Ele é usado como o transporte de pacote para a conexão QUIC, e o RTCQuicTransport o recebe no construtor.

RTCQuicTransport

Representa uma conexão QUIC. Ele é usado para estabelecer uma conexão QUIC e criar streams QUIC. Ele também expõe estatísticas relevantes para o nível de conexão do QUIC.

RTCQuicStream

Usado para ler e gravar dados no lado remoto. Os streams transportam dados de maneira confiável e em ordem. É possível criar vários streams a partir do mesmo RTCQuicTransport. Depois que os dados são gravados em um stream, eles disparam um evento "onquicstream" no transporte remoto. Os streams são uma maneira de distinguir dados diferentes na mesma conexão QUIC. Exemplos comuns podem ser o envio de arquivos separados em streams separados, pequenos blocos de dados em diferentes streams ou diferentes tipos de mídia em streams separados. RTCQuicStreams são leves, multiplexados em uma conexão QUIC e não causam bloqueio de cabeça de linha para outros RTCQuicStreams.

Configuração da conexão

Veja a seguir um exemplo de configuração de uma conexão QUIC ponto a ponto. Como RTCPeerConnection, a API RTCQuicTransport requer o uso de um canal de sinalização seguro para negociar os parâmetros da conexão, incluindo os parâmetros de segurança. O RTCIceTransport negocia os parâmetros ICE (ufrag e senha), além dos RTCIceCandidates.

Diagrama do RTCQuicTransport mostrando a arquitetura da API

Perspectiva do cliente:

const iceTransport = new RTCIceTransport();
const quicTransport = new RTCQuicTransport(iceTransport);
// Signal parameters, key and candidates.
signalingChannel.send({
  iceParams: iceTransport.getLocalParameters(),
  quicKey: quicTransport.getKey(),
});
iceTransport.onicecandidate = e => {
  if (e.candidate) {
    signalingChannel.send({candidate: e.candidate});
  }
};

// When remote parameters are signaled, start connection.
signalingChannel.onMessage = async ({iceParams, candidate}) => {
  if (iceParams) {
    iceTransport.start(iceParams);
    quicTransport.connect();
  } else if (candidate) {
    iceTransport.addRemoteCandidate(candidate);
  }
};

Perspectiva do servidor:

const iceTransport = new RTCIceTransport();
const quicTransport = new RTCQuicTransport(iceTransport);
// Signal parameters, key and candidates.
signalingChannel.send({
  iceParams: iceTransport.getLocalParameters(),
});
iceTransport.onicecandidate = e => {
  if (e.candidate) {
    signalingChannel.send({candidate: e.candidate});
  }
};

// When remote parameters are signaled, start connection.
signalingChannel.onMessage = async ({iceParams, quicKey, candidate}) => {
  if (iceParams && quicKey) {
    iceTransport.start(iceParams);
    quicTransport.listen(quicKey);
  } else if (candidate) {
    iceTransport.addRemoteCandidate(candidate);
  }
};

Transferência de dados

A transferência de dados pode ser realizada usando as APIs RTCQuicStream para leitura e gravação:

RTCQuicStreamReadResult readInto(Uint8Array data);
void write(RTCQuicStreamWriteParameters data);
Promise<void> waitForWriteBufferedAmountBelow(unsigned long amount);
Promise<void> waitForReadable(unsigned long amount);

Armazenando em buffer

As promessas retornadas pelos métodos waitFor* permitem armazenar dados em buffer quando o JavaScript está ocupado. A pressão de retorno é aplicada no lado de envio quando o buffer de leitura fica cheio no lado de recebimento. O lado de envio tem um buffer de gravação que pode ser preenchido quando a pressão de retorno é aplicada. Portanto, o lado de gravação também tem um método waitForWriteBufferedAmountBelow para permitir a espera de espaço no buffer para gravação. Mais informações sobre como gravar/ler dados podem ser encontradas em outras documentação para desenvolvedores.

Entrega não solicitada/não confiável

Embora um RTCQuicStream só ofereça suporte ao envio de dados de forma confiável e em ordem, a entrega não confiável/não ordenada pode ser feita por outros meios. Para entrega não ordenada, é possível enviar pequenos blocos de dados em fluxos separados porque os dados não são ordenados entre fluxos. Para entregas não confiáveis, é possível enviar pequenos blocos de dados com o fim definido como verdadeiro, seguido por uma chamada para reset() no stream após um tempo limite. O tempo limite precisa depender de quantas retransmissões são desejadas antes de descartar os dados.

Quando?

O teste de origem começará na versão do Chrome 73 e será disponibilizado até a versão M75, inclusive. Depois disso, o teste de origem termina. Com base no feedback e no interesse, vamos fazer as mudanças apropriadas e enviar a API, continuar com um novo teste de origem ou descontinuar a API.

Onde?

Navegador Chrome em todas as plataformas exceto iOS.

O que mais?

Feedback

Uma das principais metas do teste de origem é receber feedback de vocês, os desenvolvedores. Temos interesse em:

  • O que essa API ativa para você?
  • Como essa API melhora outras APIs de transporte de dados (WebSockets ou RTCDataChannel do WebRTC)? Como ela poderia melhorar?
  • Performance
  • Ergonomia da API

Registrar-se no teste de origem

  1. Solicite um token para sua origem.
  2. Adicione o token às suas páginas. Há duas maneiras de fornecê-lo em qualquer página da sua origem:
    • Adicione uma tag origin-trial <meta> ao cabeçalho de qualquer página. Por exemplo, isso pode ser algo como: <meta http-equiv="origin-trial" content="TOKEN_GOES_HERE">
    • Se for possível configurar seu servidor, também será possível fornecer o token nas páginas usando um cabeçalho HTTP Origin-Trial. O cabeçalho de resposta resultante precisará ser parecido com este: Origin-Trial: TOKEN_GOES_HERE

Especificação da Web

O rascunho de especificação foi ultrapassado em relação à API no teste de origem, incluindo:

  • Streams unidirecionais que estão mais alinhados com os streams WhatWG
  • Como desativar retransmissões
  • Datagramas (em breve)

Temos interesse em implementar a especificação completa e muito mais, incluindo o suporte a stream WhatWG, mas queremos ouvir seu feedback primeiro.

Segurança

A segurança no handshake do QUIC é aplicada pelo uso de uma chave pré-compartilhada para estabelecer uma conexão QUIC criptografada do P2P. Essa chave precisa ser sinalizada por um canal fora de banda seguro com garantias de confidencialidade e integridade. A chave ficará exposta ao JavaScript.

Ataque ativo

Ao contrário do DTLS-SRTP, que requer apenas integridade para sinalizar a impressão digital do certificado, a sinalização da chave pré-compartilhada requer integridade e confidencialidade. Se a PSK for comprometida, por exemplo, pelo servidor no canal de sinalização, um invasor ativo poderá montar um ataque "man-in-the-middle" no handshake do QUIC.

Status atual

Step Status
1. Criar uma explicação Concluído
**2a. Especificação RTCQuicTransport ** **Em andamento**
**2b. Especificação RTCIceTransport ** **Em andamento**
**3. Receba feedback e faça iterações no design** **Em andamento**
4. Teste de origem Começa no Chrome 73.
5. Iniciar Not started

Links úteis