Documentazione di Steamworks
Steam Datagram Relay
Steam Datagram Relay (SDR) è la rete di gioco virtuale privata di Valve. Utilizzando le nostre API potrai non solo utilizzare la backbone di Valve dedicato ai contenuti di gioco per il tuo traffico, ma anche ottenere accesso alla nostra rete di relè. Questo tipo di gestione del traffico protegge i tuoi server e i giocatori dagli attacchi DoS, in quanto gli indirizzi IP non sono mai rivelati. Tutto il traffico che ricevi è autenticato, codificato e ha una frequenza limitata. Inoltre, per un numero di giocatori sorprendentemente elevato, siamo in grado di trovare un percorso più veloce tramite la nostra rete, il che riduce il loro ping.

Questa rete di relè può essere utilizzata sia per il traffico peer-to-peer che per i server dedicati.

Requisiti generali e suggerimenti per la portabilità del codice di rete esistente

Ecco alcune nozioni generali da conoscere che si applicano sia alla connettività P2P che dei server dedicati.

Per prima cosa, qualsiasi luogo in cui gli host di rete sono identificati da un IP pubblico (quasi sempre nel caso dei server di gioco) dovrà invece essere modificato per utilizzare un identificatore diverso. Ci sono diverse opzioni a proposito:
  • Per i client e i server di gioco che accedono a Steam, di solito si utilizza l'ID di Steam.
  • Se il tuo server di gioco non riesce ad accedere a Steam e stai usando il flusso di autenticazione con assegnazione di ticket, puoi usare qualunque altro identificatore di tua scelta. Vedi SteamNetworkingIdentity.
  • In alcuni codici di base, il presupposto che gli host di rete e i server di gioco vengano identificati utilizzando un indirizzo IPv4 è universale e per modificare tale presupposto è necessario un lavoro notevole. In effetti, le API di Steamworks ISteamMatchmaking e ISteamMatchmakingServers hanno questa proprietà, così come alcuni dei nostri giochi, tra cui Team Fortress 2. In questo caso, puoi usare il sistema con il "falso indirizzo IP" di Steamworks. Un falso indirizzo IP "sembra" un indirizzo IPv4 valido nella maggior parte dei casi, ma in realtà proviene da uno spazio di indirizzi riservato non usato su internet. Se assegni al tuo server un falso indirizzo IP, il server può comunque essere autenticato utilizzando un indirizzo IPv4 e quasi tutto funzionerà senza particolari problemi. I sistemi ISteamNetworkingSockets e ISteamMatchmakingServers riconoscono questi IP speciali e prendono le misure appropriate. Non sono instradabili e non funzionano per le operazioni comuni di internet (ad esempio, non è possibile eseguire il ping). Per maggiori informazioni, vedi ISteamNetworkingSockets::BeginAsyncRequestFakeIP.

Secondariamente, dovrai modificare qualsiasi codice socket di basso livello per utilizzare una delle API di Steamworks per la connettività.
  • Idealmente, puoi utilizzare una delle interfacce ISteamNetworkingSockets dell'API orientata alla connessione che restituisce un HSteamNetConnection.
    (Tieni presente che queste API supportano anche il trasporto UDP semplice che è molto utile per i test. Esiste anche una versione open source.)
  • Alcuni codici sono scritti in uno stile simile a UDP, in cui alcuni pacchetti possono essere inviati all'occorrenza a un qualsiasi host remoto e in qualsiasi momento; non tutti i messaggi vengono inviati a una "connessione" stabilita. In queste situazioni, ci sono due funzionalità di Steamworks che potrebbero essere utili.
    • Utilizza ISteamNetworkingMessages per comunicare con gli host identificati utilizzando un tipo SteamNetworkingIdentity, ad esempio un ID di Steam.
    • Usa ISteamNetworkingFakeUDPPort per comunicare con gli host che utilizzano un falso indirizzo IP.

Requisiti per l'uso dell'SDR su altre piattaforme e negozi

Una soluzione di rete API associata a una risorsa contro gli attacchi DDoS per un gioco multipiattaforma è inutile se funziona solo su una piattaforma. Nella maggior parte dei casi, i tuoi giocatori sulle altre piattaforme e negozi possono accedere alla rete di relè, purché il tuo gioco soddisfi alcune condizioni di base.
  • Disporre di una versione del tuo gioco distribuita su Steam.
  • Quando richiesto, accettare di aggiornare il tuo gioco entro un periodo di tempo ragionevole (alcuni mesi) se dobbiamo inviare una correzione di bug o una patch di sicurezza.
  • Riconoscere che, sfortunatamente, non possiamo promettere che questo servizio sarà sempre disponibile per i giocatori che non possiedono un account di Steam. Nel caso improbabile in cui saremo fossimo a restringere questo servizio, faremo tutto il possibile per lavorare con voi al fine di evitare interruzioni per i vostri giocatori, dandovi il tempo di pianificare soluzioni alternative. L'SDK ha meccanismi integrati che permettono di fare in modo che i client ricorrano alla connettività UDP diretta o tentino il NAT punching, ma dovresti tenere a mente anche questa possibilità.
  • Disporre di una specie di servizio di matchmaking (l'SDR lo definisce il "coordinatore di gioco") in grado di emettere delle credenziali di autenticazione. Abbiamo un SDK dedicato per questo (vedi sotto).

Contattaci per gli SDK relativi e per parlare dei dettagli. Stiamo ancora definendo i dettagli di come distribuire questo codice e al momento potremmo non essere in grado di rendere disponibile il supporto multipiattaforma a tutti i partner e a tutti i giochi.

Leggi qui sotto per ulteriori informazioni di natura tecnica in merito all'implementazione dell'SDR su altre piattaforme e negozi.

Se non soddisfi i criteri sopra elencati, puoi usare la versione open source dell'API come meglio credi. Ricorda che il codice open source non supporta l'accesso alla rete di relè.

Giochi peer-to-peer

Per il traffico peer-to-peer su Steam, tutto ciò che devi fare per sfruttare l'SDR è usare API come ISteamNetworkingSockets::CreateListenSocketP2P e ISteamNetworkingSockets::ConnectP2P. Di tutto il resto si occuperà Steam. Per altre piattaforme e negozi, leggi i requisiti tecnici aggiuntivi di seguito.

Server dedicati in centri dati conosciuti

Le API peer-to-peer funzionano bene anche quando un "peer" è un server dedicato! Ma c'è un aspetto importante da tenere in considerazione: se il tuo server dedicato non è vicino ai centri dati presso cui abbiamo in esecuzione i relè, il miglior percorso inoltrato potrebbe essere più lento del percorso IP ordinario. Di conseguenza, nella migliore delle ipotesi alcuni giocatori avranno una latenza maggiore rispetto a quella precedente.

Per un'esperienza ottimale con il server dedicato, questo dovrebbe essere gestito in un centro dati conosciuto che faccia parte della rete SDR. Ci accertiamo che ci siano relè in esecuzione nelle vicinanze e che il percorso attraverso di essi non sia mai troppo più lento del percorso IP predefinito. I server gestiti in questi centri dati conosciuti si connettono attraverso un'API speciale. Questo caso di utilizzo viene definito "server dedicato ospitato" nell'SDK. Tieni presente che questo non significa necessariamente che Valve ospiti i server o i relè. Infatti, questi ultimi potrebbero essere ospitati da un centro dati di terze parti con cui abbiamo stabilito un collegamento e noto al sistema Steam Datagram Relay.

Se stai gestendo server di gioco su uno dei principali fornitori di hosting e ti interessa usare l'SDR, contattaci. Nella migliore delle ipotesi, cercheremo di collaborare con la tua società di hosting per eseguire i relè nel centro dati, ma anche nel caso in cui ciò non sia possibile, dovremmo essere in grado di aggiungere il centro dati alla nostra rete e usare i relè di Valve che si trovano più vicino.

Contattaci se sei una società di hosting dei servizi dedicati e vuoi unirti alla nostra rete, in modo che i tuoi clienti possano usare l'SDR. Non abbiamo ancora distribuito relè in società di hosting di terze parti, tuttavia è un'opzione che ci interessa.

Semplice flusso di connessione verso un server dedicato senza il coordinatore di gioco

Se non disponi di un tuo servizio di matchmaking/accesso (a volte noi lo chiamiamo "coordinatore di gioco") che assegna i giocatori ai server, o se preferisci non complicare troppo le cose, puoi connetterti a un server dedicato all'interno di un centro dati conosciuto utilizzando ISteamNetworkingSockets::CreateListenSocketP2P e ISteamNetworkingSockets::ConnectP2P. In questo caso, la connessione ha inizio sul lato client, proprio come una classica connessione P2P. I messaggi di rendezvous vengono inviati tramite Steam, quindi se la connessione a Steam viene persa dal giocatore o dal server, non è possibile ristabilirla. Inoltre, Steam non impone limitazioni sulle persone che possono tentare di connettersi, a parte verificare che il giocatore abbia effettuato l'accesso a Steam e possieda il gioco.

Flusso di connessione del server basato sui ticket

Se non disponi di un coordinatore di gioco personale, ti consigliamo di utilizzare un flusso di connessione basato sui ticket. In genere è appena un po' più complicato rispetto a un semplice flusso di connessione in stile P2P e offre due vantaggi importanti:
  • Emetti i ticket solo ai giocatori che dovrebbero essere autorizzati a tentare la connessione, in modo che i tentativi di connessione indesiderati non raggiungano nemmeno il server.
  • Una volta che un giocatore dispone di un ticket, si può connettere al server anche quando perde la connessione a Steam, oppure quando il server perde la connessione a Steam o il computer del giocatore si arresta e si riavvia, ecc. Rendere la riconnessione al server di gioco stabile e solida, al fine di evitare questi errori comuni, è particolarmente importante in tutti quei giochi che penalizzano i giocatori che lasciano la partita.

Una connessione basata sui ticket a un server dedicato su SDR funziona in questo modo:
  • Quando il tuo server di gioco effettua l'accesso al tuo coordinatore di gioco, invia il proprio SteamDatagramHostedAddress, che è un blob opaco contenente le informazioni di instradamento fisico (vedi ISteamNetworkingSockets::GetHostedDedicatedServerAddress). Tieni anche presente che disponiamo di alcuni strumenti che possono aiutarti a effettuare un accesso autenticato al tuo coordinatore di gioco.
  • Il server si mette in ascolto del traffico trasmesso utilizzando ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket.
  • A un certo punto il tuo client vorrà avviare il matchmaking o connettersi a un server.
  • Il client può usare i metodi disponibili nell'interfaccia ISteamNetworkingUtils per ottenere i tempi di ping verso i centri dati e controllare la connettività. Il client dovrà poi inviare queste informazioni al tuo coordinatore di gioco, per consentirti di prendere le giuste decisioni riguardo all'assegnazione dei giocatori ai centri dati.
  • Quando il tuo coordinatore di gioco è pronto ad autorizzare un client a connettersi a un server, genera un SteamDatagramRelayAuthTicket e lo firma con la tua chiave segreta. Questo ticket autorizza un client specifico a comunicare con un server di gioco specifico per un periodo di tempo limitato. Contiene anche le informazioni di instradamento crittografate. Il coordinatore di gioco invia il ticket al client.
  • Il client salva il ticket in una cache locale (vedi ISteamNetworkingSockets::ReceivedRelayAuthTicket per ulteriori informazioni, compreso il motivo per cui il salvataggio nella cache è utile, anche se sembra una complicazione).
  • Il client usa ISteamNetworkingSockets::ConnectToHostedDedicatedServer per connettersi al server. Vedi ISteamNetworkingSockets per maggiori dettagli su come inviare e ricevere i messaggi.

Al momento, l'autenticazione basata sui ticket non è disponibile in combinazione con il sistema di falsi indirizzi IP.

SDK del coordinatore di gioco

"Coordinatore di gioco" è il termine che utilizziamo per riferirci ai servizi di back-end e di matchmaking. Esiste un piccolo SDK separato che puoi associare al tuo coordinatore di gioco, utilizzabile per:
  • Emettere ticket per fornire ai clienti accesso ai server di gioco ospitati dietro SDR.
  • Analizzare delle stringhe con PingLocation_t e calcolare la latenza tra questi oggetti.
  • Emettere certificati di identità per i giocatori su altre piattaforme e negozi.
  • Sfruttare altre funzionalità avanzate.

L'SDK è disponibile qui.

Autenticazione tramite l'SDK del coordinatore di gioco

L'SDR usa due meccanismi di autenticazione:

  • I ticket per il server ospitato vengono emessi dal coordinatore di gioco e autorizzano un client specifico a comunicare con un server dedicato specifico per un certo periodo di tempo. I ticket di trasmissione sono utilizzati solo nel caso di un server dedicato. Consulta SteamDatagramRelayAuthTicket.
  • I certificati vengono usati in modo tradizionale per autenticare ed eseguire un scambio di chiavi DH al fine di stabilire un canale crittografato. I certificati sono un concetto end-to-end e possono essere impiegati in tutte le forme di comunicazione SteamNetworkingSockets, compresa la connettività UDP diretta o P2P. Consulta SteamDatagram_CreateCert nell'SDK del coordinatore di gioco e ISteamNetworkingSockets::GetCertificateRequest.

Per autenticare i client e i server utilizziamo un'infrastruttura a chiave pubblica (PKI). I giocatori ricevono certificati individuali a breve termine, associati alla loro identità specifica. Di questo si occupa Steam. Per i server di gioco utilizziamo generalmente certificati più a lungo termine che autorizzano un intero centro dati per un particolare appID. Quei certificati dovrai emetterli tu.

Prima di poter emettere ticket e certificati, dovrai generare una coppia di chiavi e inviarci la tua chiave pubblica. Noi pubblicheremo un certificato firmato dalla nostra chiave CA master che contrassegna la tua chiave come affidabile per le tue applicazioni. A questo punto, utilizzando il nostro strumento di certificazione dovrai generare un certificato offline per ogni centro dati in cui desideri eseguire i server e firmarlo con la tua chiave privata. Dovrai distribuire tali certificati ai tuoi server di gioco su un canale sicuro, inviandoli al tuo server all'interno dell'ambiente (vedi sotto).

Userai la tua chiave anche per generare i ticket ogni volta che un giocatore si connette a un server di gioco.

Tieni al sicuro la tua chiave CA privata e le chiavi private dei tuoi certificati! Se la tua chiave viene divulgata, dovrà essere revocata e sostituita, il che potrebbe provocare un'interruzione del servizio.

Implementazione dell'SDR su altre piattaforme e negozi


I tuoi utenti su altre piattaforme e negozi non effettueranno l'accesso a Steam, quindi dovrai fornire alcuni servizi a tali giocatori, che Steam fornisce ai giocatori su Steam.

Inizializzazione del coordinatore di gioco

  • Il tuo servizio di matchmaking (definito "coordinatore di gioco") dovrà collegarsi con l'SDK del coordinatore di gioco. Il file di intestazione steamdatagram_gamecoordinator.h contiene ulteriori dettagli. L'SDK del coordinatore di gioco utilizza un'API C standard, per cui dovrebbe essere relativamente semplice integrarla con altri linguaggi.
  • Scarica la configurazione di rete durante l'inizializzazione, e verifica la presenza di aggiornamenti all'incirca ogni ora. (Consulta SteamDatagram_GameCoordinator_GetNetworkConfigURL e SteamDatagram_GameCoordinator_SetNetworkConfig.) La configurazione di rete è rappresentata da un piccolo file JSON che al momento è pari a circa 26K (9K compresso). Questo URL ha una disponibilità estremamente elevata. In ogni caso, se accetti l'eventualità che la connessione possa fallire, puoi usare una versione scaricata recentemente.
  • Avrai bisogno di una coppia di chiavi autenticate per il tuo gioco. Inviaci la chiave pubblica e inizializza l'SDK del coordinatore di gioco con la tua chiave privata. (Per ulteriori informazioni, vedi SteamDatagram_SetPrivateKey_Ed25519.)

Inizio della sessione del client

  • Il client chiamerà ISteamNetworkingSockets::GetCertificateRequest per ottenere un blog e inviarlo assieme al messaggio di richiesta di connessione al tuo coordinatore di gioco.
  • Quando il coordinatore di gioco riceve la richiesta di connessione, genera un certificato per il client usando SteamDatagram_CreateCert.
  • Reinvia il certificato generato al client nella risposta di connessione. Il client dovrebbe installare il certificato usando ISteamNetworkingSockets::SetCertificate.
  • Consigliamo vivamente di distribuire anche la configurazione di rete ai client in questo momento. Il client applicherà la configurazione di rete usando SteamDatagram_SetNetworkConfig.

I certificati hanno una scadenza, e consigliamo di usare una scadenza di 48 ore. Se i client si collegano per oltre 48 ore, dovrai rinnovare periodicamente il certificato. Un nuovo certificato da applicare in qualunque momento è accettabile, quindi se vuoi emettere certificati più spesso, per esempio all'inizio di ogni partita, non c'è problema.

Ogni client deve avere un'identità unica. Se possibile, usa identità specifiche della piattaforma (per i client di Steam, questo è un requisito). Tuttavia, se non fosse possibile, puoi usare un'identità "stringa generica" che abbia un significato per il sistema di ricerca delle partite. Vedi SteamNetworkingIdentity.

Giochi peer-to-peer

Le connessioni P2P richiedono un servizio di "segnalazione". Si tratta di un canale a larghezza di banda ridotta, non sensibile alla latenza e a consegna best effort, in grado d'inviare sporadici messaggi di rendezvous per la negoziazione del percorso. Tutto ciò comporta che i client debbano avere una connessione persistente al tuo servizio di matchmaking, in modo che tu possa inviare messaggi ai client stessi, come un websocket o una connessione TCP. Ciò non è possibile se i client comunicano con il tuo coordinatore di gioco solo usando richiesta e risposta, come ad esempio tramite HTTP. Devi fornire solo una consegna "best effort", vale a dire che la libreria dovrebbe consentire il rilascio di messaggi o riceverne più volte.

  • Per avviare una connessione, usa ISteamNetworkingSockets::ConnectP2PCustomSignaling. Dovrai implementare una sottoclasse di ISteamNetworkingConnectionSignaling e, quando SendSignal viene chiamato, il client dovrà inviare il messaggio al tuo back-end. Sarà infine il tuo back-end a fare del suo meglio per consegnare il messaggio al peer. Alla prima creazione di una connessione, uno scambio iniziale di 4-10 messaggi è tipico. In seguito, potresti essere chiamato a fornire un segnale per una connessione stabilita se le condizioni di routing dovessero cambiare.
  • Quando un client riceve una segnalazione, chiama ISteamNetworkingSockets::ReceivedP2PCustomSignal. La libreria decodificherà il messaggio. Se riguarda una connessione esistente, la segnalazione verrà elaborata internamente. Se la segnalazione riguarda una nuova connessione, verrà chiamato ISteamNetworkingSignalingRecvContext::OnConnectRequest.

Vedi steamnetworkingcustomsignaling.h per ulteriori dettagli.

Esecuzione dei server in centri dati noti

Questa sezione documenta alcuni dettagli tecnici coinvolti nell'esecuzione di server dedicati in centri dati conosciuti.

Variabili d'ambiente

La configurazione del server dedicato viene stabilita dalle variabili d'ambiente. Ricorda che nei data center di Valve tutti questi valori verranno impostati automaticamente.
  • SDR_LISTEN_PORT: la porta UDP in cui il tuo server riceverà il traffico dai relè. Il sever dedicato usa solo un socket singolo (ma puoi avere più "socket di ascolto" utilizzando le "porte virtuali". Vedi ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket). Nei nostri centri dati utilizziamo generalmente l'intervallo 30xxx.
  • SDR_IP: il tuo server deve avere un IP pubblico in grado di ricevere il traffico "indesiderato" dai relè. Se il server ha solo un'interfaccia con un IP pubblico, verrà usato quest'ultimo. In caso contrario dovrai indicare al server di gioco quale IP deve utilizzare. Il socket SDR sarà associato a INADDR_ANY, ma questa informazione serve per compilare l'API SteamDatagramHostedAddress del server. In particolare, ricorda che generalmente è necessario impostarlo negli ambienti di sviluppo, dove il server si trova dietro un firewall aziendale (vedi sotto). Puoi anche specificare una porta, se la porta pubblica non è SDR_LISTEN_PORT.
  • SDR_POPID: il codice alfanumerico di 3 o 4 lettere (SteamNetworkingPOPID) del centro dati, in produzione. Va lasciato vuoto negli ambienti di sviluppo.
  • SDR_PRIVATE_KEY: la chiave privata del tuo certificato. È un blocco OpenSSH PEM che inizia con "-----BEGIN OPENSSH PRIVATE KEY-----".
  • SDR_CERT: il tuo certificato firmato. È un blocco in formato proprietario simile a PEM che inizia con "-----BEGIN STEAMDATAGRAM CERT-----".
  • SDR_NETWORK_CONFIG: il percorso completo a una copia recente e locale del file di configurazione di rete SDR per la tua applicazione. Se questa variabile non viene impostata, per ottenere la configurazione di rete il server userà la copia impiegando HTTP all'avvio. Per ottenere prestazioni ottimali puoi scaricare periodicamente (ad esempio ogni ora) la configurazione più recente e salvarla localmente, per evitare che i problemi di rete provochino interruzioni del servizio. Questo è il modo in cui sono configurati i server di Valve.

Esecuzione in un ambiente di sviluppo

Poiché ISteamNetworkingSockets supporta la connettività UDP semplice, generalmente è meglio iniziare a sviluppare il codice in modo che funzioni su questa interfaccia su UDP, senza preoccuparsi dei relè.

Conviene che il codice del server usi la presenza della variabile d'ambiente SDR_LISTEN_PORT per decidere se il server debba restare in ascolto della rete SDR. Puoi usare ISteamNetworkingSockets::GetHostedDedicatedServerPort per ottenere il valore.

Nell'ambiente di sviluppo dovrai lasciare vuota la variabile SDR_POPID. Quando le variabili SDR_LISTEN_PORT e SDR_POPID sono vuote, POPID viene impostato sul codice speciale a 3 caratteri "dev".

In generale, l'autenticazione è disabilitata per i server nell'ambiente "dev" (sia i client che i relè consentiranno le connessioni ai server "dev" senza un certificato firmato, purché abbiano un ticket firmato). Per l'autenticazione con il coordinatore di gioco è necessario un altro meccanismo. Inoltre, il tuo coordinatore di gioco dovrà prestare attenzione quando emette ticket a un server che dichiara di trovarsi nell'ambiente "dev"!

Il tuo server deve poter ricevere il traffico pubblico non richiesto, il che significa che se non ha un IP pubblico è necessario impostare il port forwarding nel firewall e probabilmente impostare SDR_IP sul giusto IP pubblico (e impostare la porta, se è diversa da SDR_LISTEN_PORT).