Resumo

  • Um telefone podia abrir comunicação com o servidor sem permitir que o servidor iniciasse uma nova conexão de retorno. O Outbound aproveitou os fluxos abertos pelo próprio terminal para entregar novas solicitações.
  • Conta, instância do dispositivo e registro de fluxo passaram a ter funções distintas. Duas rotas para a mesma instância não deveriam ser contadas como dois destinatários simultâneos.
  • O código 430 permite reconhecer a falha de um fluxo. Uma resposta final da instância, exceto nos casos previstos de 408 e 430, impede reenviar a mesma solicitação por outra de suas rotas.

A resposta que não confirmava o caminho

O telefone envia uma verificação STUN e recebe uma resposta. À primeira vista, parece a confirmação que procurava: alguma coisa continua ouvindo do outro lado. Mas o endereço público informado na resposta mudou. Para o SIP Outbound, isso deve ser tratado como falha do fluxo.

O detalhe aparece no RFC 5626, publicado em outubro de 2009. Em UDP, o fluxo é uma associação entre protocolo, endereços e portas dos dois lados. Se o mapeamento externo mudou, a associação que havia sido registrada não é mais a mesma. Receber uma mensagem não basta para garantir que futuras solicitações encontrarão o terminal pelo caminho antigo.

Esse é um bom ponto de entrada para uma história geralmente resumida como “manter a conexão aberta”. O mecanismo precisava fazer mais: saber qual caminho estava aberto, a que instância pertencia e o que a perda dele autorizava tentar novamente.

Havia dois trabalhos de manutenção

Uma associação de registro precisa ser renovada antes de vencer. Um fluxo precisa permanecer utilizável. Essas tarefas se relacionam, mas não são equivalentes.

O RFC permite conservar uma conexão que responde aos pings quando o registro encontra um erro recuperável de renovação, como um 503 com orientação para tentar depois. Fechar e reabrir tudo poderia acrescentar trabalho sem resolver a causa. No outro sentido, uma resposta STUN com novo mapeamento significa que o fluxo antigo falhou, mesmo que algum tráfego continue passando.

Os intervalos de manutenção também têm custo. Aumentar a frequência pode reduzir o tempo até detectar uma falha, mas usa bateria e processamento. O Flow-Timer do servidor expressa uma expectativa de atividade, com margem para atraso; não é uma promessa de entrega de todas as chamadas naquele intervalo.

O RFC 6223, de abril de 2011, separou a negociação de manutenção entre vizinhos por meio do parâmetro Via keep. O documento é explícito: isso não define a reutilização da conexão. A negociação ocorre por direção, e conservar um caminho não dá, isoladamente, autorização para qualquer solicitação inversa.

Nome do aparelho, endereço e conexão continuaram diferentes

O RFC 5923, de junho de 2010, descreve aliases de conexões TLS para vizinhos capazes de iniciar comunicação nos dois sentidos. Essa hipótese é diferente da restrição que motiva o Outbound. Autenticar um par, manter uma conexão e aceitar sua reutilização inversa não são uma única decisão automática.

Já o RFC 5627 permite obter uma URI globalmente utilizável que aponta para uma instância específica: o GRUU. Em uma transferência, usar só a AOR pode alcançar outro telefone ou a caixa postal, quando se precisa do aparelho que está na conversa. O GRUU identifica o alvo por meio do domínio; o Outbound organiza formas de voltar até ele. Nenhum deles é uma garantia de disponibilidade permanente.

O cenário de navegador do RFC 7118, publicado em janeiro de 2014, ilustra essa separação de maneira concreta. Um cliente que pediu e recebeu suporte Outbound pode usar um nome aleatório sob .invalid em Contact, pois as solicitações retornam pelo proxy WebSocket e pelo fluxo existente. Isso responde a uma limitação daquele ambiente de execução, não torna qualquer Contact inválido uma rota funcional. O transporte da mídia está fora do escopo desse documento.

O registro SIP da IANA preserva os nomes de códigos e parâmetros e suas referências. Ele não informa quantos produtos implementam corretamente cada comportamento. A história do Outbound não termina na inclusão de campos: termina na possibilidade de manter várias rotas sem perder a conta de quem recebe, do que falhou e de quem já deu uma resposta.

O telefone que saía não estava necessariamente disponível para entrar

O registro SIP já existia. O RFC 3261, de junho de 2002, descreveu a associação entre uma Address of Record, ou AOR, e um ou mais endereços Contact. O proxy consulta o serviço de localização para saber aonde enviar uma solicitação dirigida ao usuário. O registrador mantém essas associações; são funções lógicas que podem compartilhar uma máquina.

Só que registrar um endereço não muda a política de um firewall nem desfaz um NAT. Um terminal pode iniciar uma conexão para fora e receber respostas nela, mas continuar inacessível quando o servidor tenta abrir uma conexão nova em sentido contrário. Também pode funcionar como cliente TLS sem ter um nome estável e um certificado adequados para atuar como servidor.

Não se trata de dizer que o SIP básico era incapaz de responder pelo canal original. Em transportes confiáveis, a resposta já deveria usar a conexão da solicitação enquanto ela permanecesse aberta. Uma chamada recebida depois é outra coisa: o novo INVITE não é a resposta do REGISTER anterior.

O Outbound fez essa nova solicitação aproveitar o fluxo que o cliente havia criado. Para TCP, o fluxo corresponde a uma conexão. Para UDP, é a associação de transporte descrita acima. A regra não exige fingir que UDP possui conexões TCP; exige que o encaminhamento reconheça a relação concreta que pode alcançar o agente.

Saber passar pelo proxy não era saber qual saída usar

Quando um proxy de borda fica entre o telefone e o registrador, o caminho de volta precisa incluir esse intermediário. O endereço Contact, isoladamente, pode não revelar isso.

O RFC 3327, de dezembro de 2002, criou Path para recolher informações dos proxies durante o registro e armazená-las com a associação. Em uma solicitação futura que passa pelo domínio responsável, o proxy usa esse vetor como rota previamente indicada.

Path não transforma REGISTER em uma chamada. O registro não cria um diálogo, e Record-Route não deve ser usado nele para inventar o percurso de um diálogo. São memórias diferentes: uma permite encontrar novamente o terminal registrado; outra orienta solicitações dentro de uma conversa que se estabeleceu.

No Outbound, o primeiro proxy após o cliente acrescenta um token capaz de identificar aquele fluxo, junto com a indicação ob apropriada em Path. Assim, quando a solicitação chega de volta, o proxy consegue selecionar não apenas o próximo nó, mas a associação exata com o terminal.

O token precisa resistir a alterações e permitir recuperar o fluxo. O exemplo criptográfico do RFC não é uma exigência de implementação única. Tampouco um token substitui a autenticação do registro. Um caminho inserido indevidamente pode desviar solicitações futuras; a integridade da informação de rota é parte do problema, não decoração de segurança.

O número que deveria sobreviver ao reinício

Para manter mais de uma saída, o dispositivo precisa se registrar mais de uma vez. O servidor deve reconhecer que as inscrições pertencem à mesma instância, em vez de contar cada uma como outro telefone.

O instance-id identifica a instância do agente e permanece estável após reinício ou mudança de rede. O reg-id distingue os fluxos simultâneos que ela registra. A sequência de reg-id deve ser reutilizada depois de uma reinicialização, para que os registros novos coincidam com os anteriores e os substituam.

É uma colisão planejada. Se toda reconexão recebesse uma identidade nova de registro, a tabela poderia acumular destinos antigos sem acrescentar nenhum aparelho real. A combinação AOR, instance-id e reg-id informa qual associação está sendo renovada ou trocada.

Contact continua necessário e é armazenado. O proxy ainda o usa para formar os destinos da solicitação. O que muda é a função de comparação: o texto de Contact não precisa mais representar sozinho a identidade do terminal e a identidade do caminho.

O RFC 5626 proíbe colocar, ao mesmo tempo, mais de um Contact do mesmo AOR e instance-id no conjunto de destinos. Isso não impede vários aparelhos sob uma conta nem proíbe toda bifurcação SIP. Impede confundir alternativas para alcançar uma instância com destinatários diferentes que devam ser acionados simultaneamente.

A borda podia notar a perda antes do cliente

Na sequência hipotética do RFC, o telefone mantém registros por dois proxies. Um deles falha e reinicia. Antes que o telefone perceba a perda do fluxo, outra pessoa inicia uma chamada.

O primeiro proxy já não tem o fluxo apontado pelo token e responde 430 Flow Failed. O proxy responsável pelo usuário pode tentar a associação com o mesmo AOR e instance-id, mas outro reg-id. O segundo caminho entrega a solicitação e recebe a configuração de rota necessária ao novo diálogo. Mais tarde, o terminal detecta a falha e refaz o registro perdido.

É uma demonstração do mecanismo, não uma ocorrência documentada em uma operadora. Mostra a recuperação de uma nova solicitação durante a janela em que o telefone ainda não detectou o defeito. Não garante que qualquer diálogo em andamento migre de forma transparente; os procedimentos específicos de borda para solicitações internas ao diálogo não são inteiramente definidos ali.

430 também não significa que o usuário desapareceu, que recusou a chamada ou que todos os caminhos falharam. Sua comunicação prevista é entre proxies. O terminal não deveria recebê-lo e o trata como 400 caso isso aconteça. Já um token adulterado tem outro tratamento recomendado, com 403. A causa precisa continuar visível para que a reação seja proporcional.

O segundo caminho não podia apagar a primeira resposta

Se a instância já enviou uma resposta final, a regra muda. Tirando 408 e 430, o proxy não pode reenviar a mesma solicitação a outra associação que represente aquele mesmo AOR e instance-id. O aparelho já respondeu.

Um erro de entrega e uma resposta do destinatário não são dois nomes para a mesma falha. No primeiro caso, outra rota pode fazer a solicitação chegar. No segundo, outra rota pode apenas repetir algo que já foi processado.

Isso não determina todas as tentativas futuras de chamada e não cria uma regra geral para todos os protocolos. Delimita a mesma solicitação para a mesma instância. A redundância pode trocar o caminho, mas não transformar uma resposta recebida em ausência de resposta.

É por isso que um contador de tentativas bem-sucedidas é insuficiente para avaliar o sistema. Parar na hora certa também pode ser o resultado correto.