Documentação do Steamworks
Steam Datagram Relay (SDR)
O "Steam Datagram Relay" (SDR) refere-se à rede de retransmissão de datagramas do Steam e trata-se da rede de jogos privada e virtual da Valve. Ao usar as nossas APIs, não só poderá reencaminhar o tráfego do seu jogo pela infraestrutura da Valve dedicada ao conteúdo de jogos, como também ter acesso à nossa rede de retransmissores. A retransmissão do tráfego protege os seus servidores e jogadores contra ataques de negação de serviço (DoS), porque endereços IP nunca são revelados. Todo o tráfego que receber é autenticado, encriptado e limitado por frequência. Além disso, para um número surpreendentemente elevado de jogadores, também podemos encontrar uma rota mais rápida pela nossa rede, reduzindo-lhes o ping.

Esta rede de retransmissores pode ser usada tanto para tráfego peer-to-peer (P2P) como para servidores dedicados.

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

Seguem-se alguns pontos gerais a ter em conta ao implementar conectividade P2P ou com servidores dedicados.

Primeiro, todos os sítios onde os anfitriões de rede forem identificados por um endereço IP público (o que é quase sempre o caso de servidores) terão de ser alterados para que seja usado um identificador diferente. Há várias opções para isto:
  • Para clientes e servidores que iniciarem sessão no Steam, provavelmente irá usar o SteamID.
  • Se o seu servidor não iniciar sessão no Steam e estiver a usar o fluxo de autenticação baseado em tickets, pode usar qualquer outro identificador que lhe seja mais conveniente. Consulte SteamNetworkingIdentity.
  • Em certas bases de código, é comum supor que os anfitriões de rede e os servidores são identificados ao usar um endereço IPv4 e mudar esta noção pode ser muito difícil. De facto, as APIs do Steamworks ISteamMatchmaking e ISteamMatchmakingServers têm esta propriedade, assim como alguns dos nossos jogos, como o Team Fortress 2. Neste caso, pode usar o sistema de "endereço IP falso" do Steamworks. Um "endereço IP falso" é um IP que "parece" ser um endereço IPv4 válido para a maioria dos propósitos, mas vem de um espaço de endereços reservado que não é usado na internet. Ao atribuir um "endereço IP falso" ao seu servidor, este ainda poderá ser identificado ao usar um endereço IPv4 e quase tudo irá simplesmente funcionar sem problemas. Os sistemas das APIs ISteamNetworkingSockets e ISteamMatchmakingServers reconhecem estes endereços IP especiais e tomam as medidas apropriadas. Tais IPs não podem ser encaminhados e não funcionam para propósitos gerais de internet (por exemplo, não pode fazer-lhes ping). Consulte ISteamNetworkingSockets::BeginAsyncRequestFakeIP para mais informações.

Segundo, terá de modificar o código de sockets de baixo nível para usar uma das APIs do Steamworks para conectividade.
  • Idealmente, pode usar uma das APIs da interface ISteamNetworkingSockets orientadas à ligação que retornem HSteamNetConnection.
    (Tenha em atenção que estas APIs também funcionam com transporte UDP básico, o que é bastante útil para testes. Além disso, há uma versão open source.)
  • Algumas bases de código são escritas de uma forma semelhante ao protocolo UDP, onde os pacotes de dados podem ser enviados para qualquer anfitrião sempre que necessário e nem todas as mensagens são enviadas para uma "ligação" estabelecida. Nestas situações, há duas funcionalidades do Steamworks que podem ser úteis.
    • Use ISteamNetworkingMessages para comunicar com anfitriões identificados através de um tipo SteamNetworkingIdentity, como um SteamID.
    • Use ISteamNetworkingFakeUDPPort para comunicar com anfitriões identificados através de um endereço IP falso.

Requisitos de utilização de SDR noutras plataformas e lojas

Uma API de rede e uma solução contra DDoS para um jogo multiplataformas são inúteis se só funcionarem numa plataforma. Na maioria dos casos, os utilizadores noutras plataformas e lojas podem aceder à rede de retransmissores, desde que o seu jogo cumpra alguns requisitos básicos.
  • Tem de haver uma versão do seu jogo lançada no Steam.
  • Tem de se comprometer a atualizar o seu jogo dentro de um prazo razoável (alguns meses, no máximo) quando pedido, caso precisemos de corrigir algum erro ou falha de segurança.
  • Tem de estar ciente que, infelizmente, não podemos garantir que este serviço esteja sempre disponível para utilizadores que não sejam do Steam. No caso improvável de termos de reverter este serviço, faremos todos os possíveis para trabalhar consigo de forma a evitar interrupções para os seus utilizadores e dar-lhe tempo para planear o seu próximo passo. O SDK inclui mecanismos que nos possibilitam instruir os clientes a usar conectividade UDP direta ou tentar contornar o NAT, mas também deve ter esta possibilidade em mente.
  • Precisa de ter algum tipo de serviço de matchmaking (o SDR chama "coordenador de partidas" a isto) que emita credenciais de autenticação. Temos um SDK separado para isto. Mais informações abaixo.

Entre em contacto connosco para obter os SDKs relevantes e falarmos sobre os detalhes. Ainda estamos a ponderar sobre a melhor forma de distribuir este código e atualmente não poderemos disponibilizar a funcionalidade multiplataformas para todos os parceiros e jogos.

Consulte abaixo informações mais técnicas acerca da implementação de SDR noutras plataformas e lojas.

Caso não cumpra os requisitos mencionados acima, fique à vontade de usar a versão open source da API como desejar. Tenha em atenção que o código open source não permite o acesso à rede de retransmissores.

Jogos peer-to-peer (P2P)

No caso de tráfego P2P no Steam, tudo o que precisa para usar o SDR é de APIs como ISteamNetworkingSockets::CreateListenSocketP2P e ISteamNetworkingSockets::ConnectP2P. O Steam irá tratar de tudo o resto. Para outras plataformas e lojas, consulte abaixo os requisitos técnicos adicionais.

Servidores dedicados em datacenters conhecidos

As APIs peer-to-peer (P2P) funcionam perfeitamente mesmo quando um "peer" é um servidor dedicado! Porém, há um senão: se o seu servidor dedicado não estiver perto de um dos datacenters que hospedam os nossos retransmissores, então a melhor rota de retransmissão poderá ser mais lenta do que a rota IP padrão e a latência de alguns jogadores irá piorar.

Para a melhor experiência possível, os servidores dedicados devem ser hospedados num datacenter conhecido que faça parte da rede SDR. Certificamo-nos de há retransmissores disponíveis por perto e que a rota de retransmissão nunca é muito mais lenta do que a rota IP padrão. Os servidores hospedados nestes datacenters conhecidos estabelecem uma ligação através de uma API especial. Este caso de uso é mencionado no SDK como "Hosted Dedicated Server" (servidor dedicado hospedado). Tenha em atenção que isto não significa necessariamente que a Valve está a hospedar os servidores ou os retransmissores. A hospedagem pode ser de um datacenter de terceiros que tenha uma relação com a Valve e que seja conhecido pelo sistema SDR.

Caso esteja a hospedar servidores num grande provedor de hospedagem e tenha interesse em usar o SDR, entre em contacto connosco. Faremos os possíveis para colaborar com a empresa de hospedagem de forma a implementar retransmissores no datacenter. Esta é a situação ideal, mas mesmo se não for possível, poderemos adicionar o datacenter ao nosso sistema de configuração de rede e usar os retransmissores da Valve mais próximos.

Se fizer parte de uma empresa de hospedagem de servidores dedicados e quiser participar na nossa rede para que os seus clientes possam tirar proveito do SDR, contacte-nos! Ainda não implementamos retransmissores em empresas de hospedagem, mas estamos interessados em fazê-lo.

Fluxo de ligação simples para servidor dedicado sem coordenador de partidas

Caso não tenha um serviço central para matchmaking/início de sessão (às vezes chamado por nós de "coordenador de partidas") que atribui jogadores a servidores ou caso queira apenas manter as coisas o mais simples possível, pode estabelecer ligação com um servidor dedicado num datacenter conhecido ao usar as APIs ISteamNetworkingSockets::CreateListenSocketP2P e ISteamNetworkingSockets::ConnectP2P. Neste caso, a ligação começa no cliente como uma ligação P2P normal. As mensagens rendezvous são enviadas pelo Steam. Logo, se o jogador ou o servidor perder a ligação com o Steam, a ligação não poderá ser realizada. Adicionalmente, o Steam não restringe quem pode tentar estabelecer ligação, além de confirmar se o jogador tem a sessão iniciada no Steam e possui o jogo.

Fluxo de ligação ao servidor baseado em tickets

Caso tenha o seu próprio serviço de coordenação de partidas, recomendamos que use um fluxo de ligação baseado em tickets. Normalmente, isto exige só um pouco mais de trabalho em comparação com um fluxo de ligação simples tipo P2P e oferece duas vantagens importantes:
  • Só emite tickets para utilizadores com permissão para se ligarem ao servidor, logo tentativas de ligação indesejadas não vão chegar sequer ao seu servidor.
  • Assim que um utilizador tiver um ticket, ele conseguirá estabelecer ligação com o servidor mesmo se perder a ligação com o Steam, se o servidor perder a ligação com o Steam, se o computador do utilizador ficar irresponsivo e for reiniciado, etc. Garantir que a ligação ao servidor seja restabelecida depois de falhas comuns é especialmente importante para jogos que penalizam os jogadores que abandonarem uma partida.

Uma ligação baseada em tickets a um servidor dedicado via SDR funciona da seguinte forma:
  • Quando o seu servidor inicia sessão no coordenador de partidas, envia o respetivo SteamDatagramHostedAddress, que se trata de um blob opaco com informações de encaminhamento físico (consulte ISteamNetworkingSockets::GetHostedDedicatedServerAddress). Também temos algumas ferramentas que podem ser usadas para ajudar com inícios de sessão autenticados no seu coordenador de partidas.
  • O servidor começa a escutar tráfego retransmitido ao usar ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket.
  • A determinada altura, o cliente tenta entrar no matchmaking ou estabelecer uma ligação a um servidor.
  • O cliente pode usar os métodos na interface ISteamNetworkingUtils para obter os tempos de latência para datacenters e verificar a conectividade. Provavelmente irá querer que o cliente envie estas informações para o seu coordenador de partidas de forma a decidir melhor como associar jogadores a datacenters.
  • Quando o seu coordenador de partidas estiver pronto para autorizar a ligação de um utilizador a um servidor, SteamDatagramRelayAuthTicket é gerado e assinado com a sua chave secreta. Este ticket autoriza um utilizador específico a comunicar com um servidor específico durante um período limitado e também contém as informações de encaminhamento, mas encriptadas. O coordenador de partidas envia o ticket ao cliente.
  • O cliente armazena o ticket numa cache local (consulte ISteamNetworkingSockets::ReceivedRelayAuthTicket para mais informações, incluindo o motivo do armazenamento em cache).
  • O cliente usa ISteamNetworkingSockets::ConnectToHostedDedicatedServer para estabelecer ligação ao servidor. Consulte ISteamNetworkingSockets para mais detalhes sobre como enviar e receber mensagens.

De momento, a autenticação baseada em tickets não está disponível em combinação com o sistema de endereços IP falsos.

SDK do coordenador de partidas

"Coordenador de partidas" é o termo que usamos para nos referirmos aos seus serviços de back‑end e matchmaking. Existe um SDK pequeno e separado que pode ser associado ao seu coordenador de partidas para que possa:
  • Emitir tickets para que clientes tenham acesso a servidores de partidas hospedados via SDR.
  • Processar strings PingLocation_t e calcular os tempos de latência entre estes objetos.
  • Emitir certificados de identidade a jogadores noutras plataformas e lojas.
  • Tirar partido de outras funcionalidades avançadas.

O SDK está disponível aqui.

Autenticação através do SDK do coordenador de partidas

O SDR usa dois mecanismos de autenticação:

  • Tickets de servidores hospedados são emitidos pelo seu coordenador de partidas e autorizam um cliente específico a comunicar com um servidor dedicado específico durante um período limitado. Tickets de retransmissão só são usados no caso de uso de servidores dedicados. Consulte SteamDatagramRelayAuthTicket.
  • Certificados são usados da forma tradicional para autenticar e realizar uma troca de chaves de DH (Diffie–Hellman) para estabelecer um canal encriptado. Certificados são um conceito extremo a extremo e podem ser usados em todas as formas de comunicação SteamNetworkingSockets, incluindo conectividade UDP direta ou P2P. Consulte SteamDatagram_CreateCert no SDK do coordenador de partidas e em ISteamNetworkingSockets::GetCertificateRequest.

Usamos uma infraestrutura de chaves públicas (PKI) proprietária para autenticar clientes e servidores. Cada jogador recebe um certificado individual, de curta validade, associado à respetiva identidade. O Steam trata desta parte. Para servidores, usamos normalmente certificados de validade mais longa que autorizam um datacenter inteiro por AppID. Estes certificados são emitidos por si.

Antes de poder emitir tickets e certificados, terá de gerar um par de chaves e de nos enviar a sua chave pública. Iremos publicar um certificado assinado pela nossa chave de autoridade de certificação (CA) mestra, que irá marcar a sua chave como confiável para as suas aplicações. De seguida, terá de usar a nossa ferramenta de certificados para gerar localmente um certificado para cada datacenter onde pretende hospedar servidores e assiná-lo com a sua chave privada. Depois irá distribuir estes certificados pelos nossos servidores por um canal protegido, passando-os ao seu servidor como variável de ambiente (consulte esta secção mais abaixo).

Também irá usar a sua chave para gerar tickets sempre que um jogador estabelecer ligação a um servidor.

Mantenha em segurança a sua chave CA privada e as chaves privadas dos seus certificados! Se a sua chave for obtida por outrém e tiver de ser revogada e substituída, isto poderá levar a interrupções no serviço.

Implementação de SDR noutras plataformas e lojas


Os seus clientes noutras plataformas e lojas não irão iniciar sessão no Steam. Por isso, terá de lhes fornecer alguns serviços que o Steam fornece aos utilizadores do Steam.

Inicialização do coordenador de partidas

  • O seu serviço de matchmaking (conhecido como o "coordenador de partidas") terá de ser associado ao SDK do coordenador de partidas. O ficheiro de cabeçalho "steamdatagram_gamecoordinator.h" tem mais detalhes. O SDK do coordenador de partidas usa uma API na linguagem C, logo é relativamente fácil de integrar com outras linguagens.
  • Faça o download da configuração de rede no momento da inicialização e verifique a cada hora de existem atualizações (consulte SteamDatagram_GameCoordinator_GetNetworkConfigURL e SteamDatagram_GameCoordinator_SetNetworkConfig). A configuração de rede é um ficheiro JSON pequeno que, no momento em que o presente documento foi redigido, tem 26 KB (9 KB comprimido). Este URL tem alta disponibilidade. Porém, se quiser evitar a possibilidade de falha, pode usar uma versão transferida recentemente.
  • Irá 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 irá chamar a função ISteamNetworkingSockets::GetCertificateRequest para obter um blob e enviá-lo ao seu coordenador de partidas com o pedido de início de sessão.
  • Quando o coordenador de partidas receber o pedido de início de sessão, gere um certificado para o cliente usando SteamDatagram_CreateCert.
  • Envie o certificado gerado de volta para o cliente na resposta de início de sessão. O cliente deve instalar o certificado usando ISteamNetworkingSockets::SetCertificate.
  • Recomendamos que também distribua a configuração de rede entre os clientes neste momento. O cliente irá aplicar a configuração de rede usando SteamDatagram_SetNetworkConfig.

Os certificados têm um prazo de expiração e recomendamos que use um prazo de 48 horas. Se os clientes permanecerem conectados durante mais de 48 horas, terá de renovar periodicamente o certificado. É aceitável aplicar um certificado novo a qualquer momento. Por isso, se quiser emitir certificados com mais frequência (ao início de cada partida, por exemplo), não há problema.

Cada cliente deve ter uma identidade única. Se possível, use identidades específicas da plataforma (no caso de clientes do Steam, isto é um requisito.) Porém, se tal não for possível, pode usar uma identidade "genérica" que seja relevante para o o seu sistema de matchmaking. Consulte SteamNetworkingIdentity.

Jogos peer-to-peer (P2P)

Ligações P2P requerem um serviço de "sinalização" (signaling), que se trata de um canal de baixa largura de banda, não sensível à latência e com entrega de melhor esforço que seja capaz de reencaminhar mensagens ocasionais de rendezvous usadas para negociar o encaminhamento. Isto requer que os clientes mantenham uma ligação persistente ao seu serviço de matchmaking, para que lhes possa enviar mensagens (por exemplo, um websocket ou ligação TCP). Se os clientes só comunicarem com o seu coordenador de partidas através de um padrão de solicitação e resposta (como http, por exemplo), esse método não irá funcionar. Só precisa de fornecer uma entrega de "melhor esforço", o que significa que a biblioteca tolera mensagens falhadas ou enviadas repetidamente.

  • Para iniciar uma ligação, use ISteamNetworkingSockets::ConnectP2PCustomSignaling. Terá de implementar uma subclasse de ISteamNetworkingConnectionSignaling e, quando a função SendSignal for chamada, o cliente deverá enviar a mensagem para o seu back‑end que, por sua vez, deverá tomar o melhor esforço para entregar a mensagem ao peer. Quando uma ligação é criada pela primeira vez, uma troca inicial de 4 a 10 mensagens é normal. Depois disso, pode ser pedido que entregue um sinal para uma ligação estabelecida se as condições de encaminhamento mudarem.
  • Quando um cliente receber um sinal, chame ISteamNetworkingSockets::ReceivedP2PCustomSignal. A biblioteca irá descodificar a mensagem. Caso diga respeito a uma ligação existente, o sinal será processado internamente. Se o sinal for para uma ligação nova, a função ISteamNetworkingSignalingRecvContext::OnConnectRequest será chamada.

Consulte steamnetworkingcustomsignaling.h para mais detalhes.

Execução de servidores em datacenters conhecidos

Esta secção documenta alguns detalhes técnicos relacionados com a execução de servidores dedicados em datacenters conhecidos.

Variáveis de ambiente

O servidor dedicado recebe as configurações a partir de variáveis de ambiente. Tenha em atenção que, nos datacenters da Valve, todos estes valores serão definidos automaticamente.
  • SDR_LISTEN_PORT – A porta UDP pela qual o seu servidor irá receber o tráfego de retransmissores. O servidor dedicado só irá usar um único socket (mas pode ter mais de um "socket de escuta" lógico se usar "portais virtuais". Consulte ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket). Nos nossos datacenters, costumamos usar o intervalo 30xxx.
  • SDR_IP – O seu servidor necessita de ter um endereço IP público que possa receber tráfego "não solicitado" de retransmissores. Se o servidor só tiver uma interface com um endereço IP público, então será usado o endereço IP desta interface. Caso contrário, terá de dizer ao servidor qual endereço IP usar. O socket do SDR terá o valor INADDR_ANY, mas estas informações são necessárias para preencher o SteamDatagramHostedAddress do servidor. Tenha em especial atenção que esta variável costuma ser necessária em ambientes de desenvolvimento, onde o seu servidor estará protegido por uma firewall corporativa (mais informações abaixo). Também pode especificar uma porta se a porta pública for diferente da porta de SDR_LISTEN_PORT.
  • SDR_POPID – O código alfanumérico de 3 ou 4 caracteres (SteamNetworkingPOPID) do datacenter, em produção. Num ambiente de desenvolvimento, deixe isto em branco.
  • SDR_PRIVATE_KEY – A chave privada do seu certificado. Trata-se de um bloco PEM OpenSSH que começa com "-----BEGIN OPENSSH PRIVATE KEY-----".
  • SDR_CERT – O seu certificado assinado. Trata-se de um bloco de formato proprietário, semelhante a PEM, que começa com "-----BEGIN STEAMDATAGRAM CERT-----".
  • SDR_NETWORK_CONFIG – O caminho completo para uma cópia local e recente do ficheiro de configuração de rede do SDR para a sua aplicação. Se deixar isto em branco, o servidor irá obter uma cópia da configuração de rede ao usar HTTP quando for iniciado. Para o melhor desempenho possível, pode fazer o download periódico (de hora em hora, por exemplo) da configuração mais recente e guardá-la localmente para que falhas na rede não causem interrupções. É desta forma que os servidores da Valve são configurados.

Execução num ambiente de desenvolvimento

Como ISteamNetworkingSockets é compatível com conectividade UDP básica, normalmente é melhor começar por ter o seu código a funcionar através desta interface por UDP, sem se preocupar com retransmissores.

Recomendamos que o código do seu servidor use a presença da variável de ambiente SDR_LISTEN_PORT para decidir se o seu servidor deve ficar à escuta de dados do SDR. Pode usar a API ISteamNetworkingSockets::GetHostedDedicatedServerPort para obter esse valor.

Num 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 irá conter o código especial de 3 caracteres "dev".

De uma forma geral, a autenticação é desativada em servidores no ambiente "dev". (Clientes e retransmissores irão ambos permitir ligações a servidores "dev" sem um certificado assinado, desde que tenham um ticket assinado.) Irá precisar de outro mecanismo para se autenticar com o seu coordenador de partidas. Além disso, o seu coordenador de partidas terá também de ter cuidado ao emitir tickets para servidores que alegarem estar no ambiente "dev"!

O seu servidor necessita de poder receber tráfego público não solicitado, ou seja, se não tiver um endereço IP público, irá precisar de abrir uma porta na sua firewall e provavelmente terá de definir o valor de SDR_IP com o endereço IP público apropriado (e a porta, se for diferente do valor de SDR_LISTEN_PORT).