Documentação do Steamworks
Rede de retransmissão de datagramas do Steam (SDR)
A rede de retransmissão de datagramas do Steam (SDR, do inglês Steam Datagram Relay) é a rede de jogos privada e virtual da Valve. Ao usar as nossas APIs, não apenas o tráfego do jogo será roteado pelo backbone dedicado ao conteúdo de jogos da Valve, mas você também terá acesso à nossa rede de retransmissores. A retransmissão de tráfego protege os seus servidores e usuários de ataques de negação de serviço (DoS), já que endereços IP nunca são revelados. Todo o tráfego que você receber é autenticado, criptografado e tem frequência controlada. Além disso, para uma quantidade surpreendente grande de usuários, a rota pela nossa rede será mais rápida, reduzindo a latência deles.

A rede de retransmissores pode ser usada para tráfego ponto a ponto (P2P) e para servidores dedicados.

Requisitos gerais e dicas para migrar código de rede existente

Seguem alguns pontos gerais para levar em consideração ao implementar conectividade P2P ou com servidores dedicados.

Primeiro, todos os lugares onde os hosts de rede são identificados por um endereço IP público (o que é quase sempre o caso de servidores) precisarão ser ajustados para usar um identificador diferente. Há várias opções:
  • Para clientes e servidores que iniciam a sessão no Steam, você provavelmente usará o ID Steam.
  • Caso o servidor não inicie a sessão no Steam, e você estiver usando o fluxo de autenticação baseado em tickets, qualquer outro identificador significativo pode ser usado. Consulte SteamNetworkingIdentity para detalhes.
  • Em algumas bases de código, é presumido que hosts de rede e servidores sejam identificados por meio de um endereço IPv4, e alterar essa presunção pode demandar muito trabalho. De fato, as APIs ISteamMatchmaking e ISteamMatchmakingServers funcionam desta forma, assim como alguns dos nossos jogos, como o Team Fortress 2. Nesses casos, você pode usar o sistema de "endereço IP falso" do Steamworks. Um "endereço IP" falso é um endereço IP que "parece" ser um endereço IPv4 válido para a maioria dos propósitos, mas vem de um intervalo de endereços reservado e que não é usado na internet. Ao atribuir um endereço IP falso ao seu servidor, ele ainda poderá ser identificado usando um endereço IPv4, e quase tudo funcionará sem maiores ajustes. Os sistemas das APIs ISteamNetworkingSockets e ISteamMatchmakingServers reconhecem esses endereços especiais e tomam a ação apropriada. Tais endereços não podem ser roteados e não funcionam para propósitos gerais de internet (por exemplo, não é possível enviar um comando de "ping" diretamente). Consulte a documentação da função ISteamNetworkingSockets::BeginAsyncRequestFakeIP para mais informações.

Segundo, você precisará modificar o código de soquetes de baixo nível para usar uma das APIs do Steamworks para conectividade.
  • Idealmente, você pode usar uma das APIs da interface ISteamNetworkingSockets orientadas à conexão, que retornam um HSteamNetConnection.
    (Essas APIs também funcionam com transporte de pacotes UDP tradicionais, o que é útil para testes. Além disso, há uma versão de código aberto.)
  • Algumas bases de código são mais orientadas ao protocolo UDP, onde pacotes podem ser enviados a qualquer host remoto a qualquer momento, e nem todas as mensagens são enviadas por meio de uma "conexão" estabelecida. Nessas situações, há dois recursos do Steamworks que podem ser úteis.
    • Use a API ISteamNetworkingMessages para se comunicar com hosts identificados por meio de um tipo SteamNetworkingIdentity, como um ID Steam.
    • Use a API ISteamNetworkingFakeUDPPort para se comunicar com hosts usando um endereço IP falso.

Requisitos para uso da SDR em outras plataformas e lojas

Uma API de rede e solução antiDDOS para um jogo com conectividade multiplataforma é inútil caso funcione em apenas uma plataforma. Na maioria dos casos, os usuários em outras plataformas e lojas podem acessar a rede de retransmissores, contanto que o jogo atenda a alguns requisitos básicos.
  • Deve haver uma versão do jogo lançada no Steam.
  • Você deve aceitar atualizar o seu jogo dentro de um prazo razoável (por volta de alguns meses) quando solicitado — por exemplo, se precisarmos corrigir algum erro ou falha na segurança.
  • Você deve estar ciente de que, infelizmente, não podemos garantir que este serviço sempre estará disponível a usuários não Steam. No evento improvável de precisarmos reduzir o alcance desse serviço, faremos o possível para trabalhar com você para evitar interrupções para os seus usuários, inclusive dando-lhe tempo para planejar o seu próximo passo. O SDK inclui mecanismos que nos possibilitam instruir os clientes a usar conectividade UDP direta ou tentar contornar a NAT, mas você também deve ter essa possibilidade em mente.
  • Você deve ter algum serviço de criação de partidas/matchmaking (o termo da SDR é "coordenador de partidas") que emita credenciais de autenticação. Temos um SDK separado para isso. Detalhes abaixo.

Entre em contato conosco para obter os SDKs relevantes e discutir os detalhes do uso em outras plataformas. Ainda estamos decidindo a melhor forma de distribuir o código e atualmente não podemos garantir a disponibilidade multiplataforma para todos os parceiros e todos os jogos.

Abaixo, temos mais informações técnicas de implementação da SDR em outras plataformas e lojas.

Caso não atenda aos requisitos acima, você poderá usar a versão de código aberto da API como desejar. Esteja ciente de que o código aberto não permite o acesso à rede de retransmissores.

Jogos com conexão ponto a ponto (P2P)

Para tráfego ponto a ponto (P2P) no Steam, basta usar APIs como ISteamNetworkingSockets::CreateListenSocketP2P e ISteamNetworkingSockets::ConnectP2P para usar a SDR. O Steam cuidará de todo o resto. Para outras plataformas e lojas, saiba mais sobre os requisitos técnicos adicionais abaixo.

Servidores dedicados em datacenters conhecidos

As APIs ponto a ponto funcionam perfeitamente mesmo quando um "ponto" é um servidor dedicado! Mas há um porém: se o servidor dedicado não estiver próximo a um dos datacenters que hospedam os nossos retransmissores, a melhor rota de retransmissão pode ser mais lenta do que a rota IP normal, e a latência de alguns usuários piorará.

Para a melhor experiência com servidores dedicados, eles devem ser hospedados em um datacenter conhecido e que faça parte da SDR. Garantimos que haverá retransmissores próximos e que a rota de retransmissão nunca será muito mais lenta que a rota IP normal. Os servidores hospedados nesses datacenters conhecidos se conectam usando uma API especial. Este caso de uso é mencionado no SDK como um "servidor dedicado hospedado". Observe que isso não significa necessariamente que a Valve está hospedando os servidores ou os retransmissores — a hospedagem pode ser de um datacenter de terceiros com o qual estabelecemos um relacionamento e que é conhecido pelo sistema SDR.

Caso esteja hospedando servidores em um grande provedor de hospedagem e tenha interesse em usar a SDR, entre em contato conosco. Tentaremos trabalhar com a empresa de hospedagem para a implantação de retransmissores no datacenter. Essa é a situação ideal, mas mesmo se não for possível, podemos adicionar o datacenter ao nosso sistema de configuração de rede e usar os retransmissores da Valve mais próximos.

Caso represente uma empresa de hospedagem de servidores dedicados e deseje participar da nossa rede para que os seus clientes possam usar a SDR, entre em contato conosco! Ainda não implantamos retransmissores em empresas de hospedagem, mas temos interesse em fazê-lo.

Fluxo de conexão simples para servidor dedicado sem coordenador de partidas

Caso não tenha um serviço central próprio de criação de partidas/início de sessão (às vezes chamado de "coordenador de partidas") que associa usuários a servidores ou caso apenas deseje manter as coisas o mais simples possível, você pode se conectar a um servidor dedicado em um datacenter conhecido usando as APIs ISteamNetworkingSockets::CreateListenSocketP2P e ISteamNetworkingSockets::ConnectP2P. Nesse caso, a conexão começa no cliente como uma conexão P2P comum. As mensagens de encontro (rendezvous) são enviadas pelo Steam, portanto, se o usuário ou servidor perder a conexão com o Steam, a conexão não poderá ser feita. Além de verificar se o usuário está conectado ao Steam e possui o jogo, o Steam não restringe quem pode tentar se conectar.

Fluxo de conexão ao servidor baseado em tickets

Caso você tenha o seu próprio serviço de coordenação de partidas, recomendamos usar um fluxo de conexão baseado em tickets. O trabalho necessário é só um pouco maior que um fluxo de conexão simples, no estilo P2P, e oferece duas vantagens importantes:
  • Você só emite tickets para usuários com permissão para tentar se conectar, assim tentativas de conexão indesejadas nem chegarão ao seu servidor.
  • Uma vez que um usuário tenha um ticket, ele conseguirá se conectar ao servidor mesmo se perder a conexão com o Steam, o servidor perder a conexão com o Steam, o computador do usuário travar e reiniciar etc. Garantir a reconexão ao servidor em casos comuns de falha é especialmente importante para jogos que penalizam os usuários que abandonam uma partida.

Uma conexão baseada em tickets a um servidor dedicado pela SDR funciona assim:
  • Quando o servidor iniciar a sessão no coordenador de partidas, ele transmite o seu SteamDatagramHostedAddress, que é um blob opaco com dados de roteamento físico (consulte ISteamNetworkingSockets::GetHostedDedicatedServerAddress). Aliás, também temos algumas ferramentas que podem ser usadas para ajudar com sessões autenticadas ao coordenador de partidas.
  • O servidor começa a "escutar" tráfego retransmitido usando a função ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket.
  • Em algum momento, um cliente pede para entrar na criação de partidas ou se conectar a um servidor.
  • O cliente pode usar as funções na API ISteamNetworkingUtils para obter o tempo de latência para datacenters e verificar a conectividade. É melhor que o cliente envie esses dados ao coordenador de partidas, que decidirá melhor como associar usuários a datacenters.
  • Quando o coordenador de partidas estiver pronto para autorizar a conexão de um cliente a um servidor, um SteamDatagramRelayAuthTicket é gerado e depois assinado com a sua chave secreta. Esse ticket autoriza um cliente específico a se comunicar com um servidor específico, por um período limitado, e também contém os dados de roteamento, mas criptografados. O coordenador de partidas envia o ticket ao cliente.
  • O cliente armazena o ticket em um cache local (consulte ISteamNetworkingSockets::ReceivedRelayAuthTicket para mais informações, incluindo uma justificativa para a complicação de armazenamento em cache).
  • O cliente usa a função ISteamNetworkingSockets::ConnectToHostedDedicatedServer para se conectar ao servidor. Consulte ISteamNetworkingSockets para mais detalhes sobre como enviar e receber mensagens.

Atualmente, a autenticação baseada em tickets não pode ser usada com o sistema de endereços IP falsos.

SDK de coordenação de partidas

"Coordenador de partidas" é o termo que usamos para nos referir aos seus serviços de backend e criação de partidas. Existe um SDK pequeno e separado que pode ser vinculado ao seu coordenador de partidas para que possa:
  • Emitir tickets e permitir que clientes acessem servidores hospedados dentro da SDR.
  • Processar strings PingLocation_t e calcular o tempo de latência entre objetos.
  • Emitir certificados de identidade para usuários de outras plataformas e lojas.
  • Aproveitar outros recursos avançados.

O SDK está disponível aqui.

Autenticação usando o SDK de coordenação de partidas

A SDR usa dois mecanismos de autenticação:

  • Tickets de servidores hospedados são emitidos pelo coordenador de partidas e autorizam um cliente específico a se comunicar com um servidor específico por um período limitado. Tickets de retransmissão são usados exclusivamente para o caso de uso de servidores dedicados (consulte SteamDatagramRelayAuthTicket).
  • Certificados são usados do jeito tradicional para autenticar e realizar a troca de chaves de Diffie-Hellman para estabelecer um canal criptografado. Certificados são um conceito ponta a ponta e podem ser usados em todas as formas de comunicação que usem a API SteamNetworkingSockets, incluindo conectividade UDP direta ou P2P. Consulte SteamDatagram_CreateCert do SDK de coordenação de partidas e a função ISteamNetworkingSockets::GetCertificateRequest.

Usamos uma infraestrutura de chaves públicas (PKI) proprietária para autenticar clientes e servidores. Cada jogador recebe um certificado individual, de validade curta e associado à sua identidade específica. O Steam cuida dessa parte. Para servidores, costumamos usar certificados de validade mais longa, que autorizam um datacenter inteiro por AppID. Esses certificados devem ser emitidos por você.

Antes de poder emitir tickets e certificados, você precisará gerar um par de chaves e nos enviar a sua chave pública. Publicaremos um certificado assinado pela nossa chave de Autoridade Certificadora mestra, que marcará a sua chave como confiável para os seus aplicativos. Em seguida, você deverá usar localmente a nossa ferramenta de certificados para gerar um certificado para cada datacenter que hospedará servidores seus e depois os assinará com a sua chave privada. Então, distribua esses certificados aos seus servidores por um canal protegido, passando-os ao servidor como variável de ambiente (veja abaixo).

Você também usará a sua chave para gerar tickets sempre que um usuário se conectar a um servidor.

Guarde bem tanto a sua chave privada da Autoridade Certificadora como as chaves privadas dos seus certificados! Caso ocorra um vazamento, será necessário revogar e substituir a chave atual, o que pode resultar em interrupções no serviço.

Implementação da SDR em outras plataformas e lojas


Os seus clientes em outras plataformas e lojas não irão iniciar a sessão no Steam, portanto, você precisará fornecer a esses usuários alguns serviços que o Steam fornece a usuários do Steam.

Inicialização do coordenador de partidas

  • O seu serviço de criação de partidas/matchmaking (que chamamos de "coordenador de partidas") deverá se ligar ao SDK do coordenador de partidas. O arquivo de cabeçalho steamdatagram_gamecoordinator.h tem mais detalhes. O SDK do coordenador de partidas usa uma API C pura, facilitando a sua integração com outras linguagens.
  • Baixe a configuração de rede no momento da inicialização, e verifique se há atualizações de hora em hora (consulte SteamDatagram_GameCoordinator_GetNetworkConfigURL e SteamDatagram_GameCoordinator_SetNetworkConfig). A configuração de rede é um arquivo JSON pequeno que, no momento em que escrevemos este artigo, pesa 26 KB (9 KB comprimido). O URL possui alta disponibilidade. Contudo, caso deseje tratar a possibilidade de falha, você pode usar uma versão recém-baixada.
  • Você precisará de um par de chaves autenticadas para o seu jogo. Envie-nos a chave pública e inicialize o SDK do coordenador de partidas com a sua chave privada (consulte SteamDatagram_SetPrivateKey_Ed25519 para mais informações).

Início de sessão do cliente

  • O cliente chamará a função ISteamNetworkingSockets::GetCertificateRequest para obter um blob, que deverá ser enviado junto com a mensagem de início de sessão ao seu coordenador de partidas.
  • Quando o coordenador de partidas receber a solicitação de início de sessão, ele deverá gerar um certificado para o cliente por meio da função SteamDatagram_CreateCert.
  • Envie o certificado gerado de volta para o cliente na resposta de início de sessão. O cliente deverá instalar o certificado usando a função ISteamNetworkingSockets::SetCertificate.
  • É aconselhável que neste momento você também distribua a configuração de rede para os clientes. O cliente aplicará a configuração de rede usando a função SteamDatagram_SetNetworkConfig.

Os certificados têm um prazo de validade, e recomendamos que você use 48 horas. Caso os clientes permaneçam conectados por mais de 48 horas, você terá que renovar o certificado periodicamente. É aceitável aplicar um certificado novo a qualquer momento. Assim, se desejar emitir certificados com uma frequência maior (como no início de cada partida), não há problema.

Cada cliente deverá ter uma identidade única. Se possível, use identidades específicas da plataforma (para clientes do Steam, isso é obrigatório). Contudo, caso isso não seja possível, você pode usar uma identidade de "cadeia de caracteres genérica" que tenha significado para o seu sistema de criação de partidas. Consulte SteamNetworkingIdentity para detalhes.

Jogos com conexão ponto a ponto (P2P)

Conexões ponto a ponto exigem um serviço de "sinalização". Esse é canal de baixa largura de banda, não sensível à latência e com entrega de melhor esforço que seja capaz de encaminhar mensagens ocasionais de encontro (rendezvous) usadas para negociar o roteamento. Isso exige que os clientes mantenham uma conexão persistente ao seu serviço de criação de partidas (como um websocket ou uma conexão TCP), de forma que você possa enviar mensagens a eles. Se a comunicação de clientes com o coordenador de partidas é exclusivamente por protocolos de requisição e resposta, como HTTP, a sinalização não será possível. É necessário fornecer apenas uma entrega de "melhor esforço", ou seja, a biblioteca tolera a perda ou a repetição de mensagens.

  • Para iniciar uma conexão, use a função ISteamNetworkingSockets::ConnectP2PCustomSignaling. Você precisará implementar uma subclasse de ISteamNetworkingConnectionSignaling. Quando a função SendSignal for chamada, o cliente deverá enviar a mensagem ao seu backend, que, por sua vez, deverá fazer o melhor esforço para entregar a mensagem ao par. Quando uma conexão é criada pela primeira vez, uma troca inicial de 4 a 10 mensagens é normal. Depois, pode ser solicitado que entregue um sinal para uma conexão estabelecida caso as condições de encaminhamento mudem.
  • Quando um cliente receber um sinal, chame a função ISteamNetworkingSockets::ReceivedP2PCustomSignal. A biblioteca decodificará a mensagem. Caso se trate de uma conexão existente, o sinal será processado internamente. Se o sinal for para uma nova conexão, a função ISteamNetworkingSignalingRecvContext::OnConnectRequest será chamada.

Consulte o arquivo de cabeçalho steamnetworkingcustomsignaling.h para mais detalhes.

Execução de servidores em datacenters conhecidos

Esta seção documenta alguns detalhes técnicos sobre a execução de servidores dedicados em datacenters conhecidos.

Variáveis de ambiente

O servidor dedicado receberá as configurações a partir de variáveis de ambiente. Observe que, nos datacenters da Valve, esses valores serão configurados automaticamente.
  • SDR_LISTEN_PORT: a porta UDP pela qual o servidor receberá o tráfego de retransmissores. O servidor dedicado só usará um soquete (mas é possível ter mais de um "soquete de escuta" lógico por meio do uso de "portas virtuais". Consulte ISteamNetworkingutils::CreateHostedDedicatedServerListenSocket). Nos nossos datacenters, usamos o intervalo 30xxx.
  • SDR_IP: o seu servidor precisa ter um endereço IP público para receber tráfego "não solicitado" de retransmissores. Se o servidor só tiver uma interface de rede com um endereço IP público, então o endereço dessa interface será usado. Caso contrário, será necessário informar ao servidor qual endereço IP usar. O soquete da SDR terá o valor INADDR_ANY, mas esse dado é necessário para preencher o SteamDatagramHostedAddress do servidor. Observe que essa variável costuma ser necessária em ambientes de desenvolvimento, nos quais o servidor estará protegido por um firewall corporativo (veja abaixo). Também é possível especificar uma porta, caso a porta pública seja diferente da porta informada na variável SDR_LISTEN_PORT.
  • SDR_POPID: código alfanumérico de 3 ou 4 caracteres (SteamNetworkingPOPID) do datacenter, em produção. Em um ambiente de desenvolvimento, deixe em branco.
  • SDR_PRIVATE_KEY: a chave privada do certificado. É um bloco PEM OpenSSH que começa com o texto "-----BEGIN OPENSSH PRIVATE KEY-----".
  • SDR_CERT: o seu certificado assinado. É um bloco de formato proprietário, similar a PEM, que começa com o texto "-----BEGIN STEAMDATAGRAM CERT-----".
  • SDR_NETWORK_CONFIG: o caminho completo para uma cópia local e recente do arquivo de configuração de rede da SDR para o aplicativo. Caso deixe em branco, então o servidor obterá a cópia da configuração de rede por meio de HTTP quando inicializado. Para melhor desempenho, baixe a última configuração periodicamente (ex.: de hora em hora) e salve-a localmente para que problemas com a rede não causem interrupções. É assim que os servidores da Valve estão configurados.

Execução em ambiente de desenvolvimento

Já que a API ISteamNetworkingSockets é compatível com conexões UDP tradicionais, normalmente é melhor começar ajustando o código para funcionar por meio desta API usando UDP, sem se preocupar com retransmissores.

Sugerimos que o código do servidor use a presença da variável de ambiente SDR_LISTEN_PORT para decidir se deve ficar na escuta para pacotes da SDR. A API ISteamNetworkingSockets::GetHostedDedicatedServerPort pode ser usada para obter esse valor.

Em ambiente de desenvolvimento, deixe a variável SDR_POPID em branco. Quando as variáveis SDR_LISTEN_PORT e SDR_POPID estiverem em branco, o POPID conterá o código especial de 3 caracteres "dev".

Em geral, a autenticação é desativada em servidores no ambiente "dev". (Clientes e retransmissores permitirão conexões a servidores "dev" sem um certificado assinado, contanto que tenham um ticket assinado.) Você precisará de outro mecanismo para se autenticar com o coordenador de partidas. E o coordenador de partidas também precisa ter cautela ao emitir tickets para servidores que alegam estar no ambiente "dev"!

O servidor precisa receber tráfego público não solicitado, ou seja, caso não tenha um endereço IP público, será necessário abrir uma porta no firewall e (provavelmente) configurar o valor da variável SDR_IP com o endereço IP público correto (e porta, se diferente do valor de SDR_LISTEN_PORT).