Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

UPNP

Eredita: RefCounted < Object

Funzioni di Universal Plug and Play (UPnP) per il rilevamento dei dispositivi di rete, l'interrogazione e il port forwarding.

Descrizione

Questa classe può essere utilizzata per individuare UPNPDevice compatibili sulla rete locale ed eseguire comandi su di essi, come per gestire la mappatura delle porte (per inoltrare le porte/NAT traversal) e per richiedere l'indirizzo IP della rete locale e remota. Nota che i metodi su questa classe sono sincroni e bloccano il thread che li chiama.

Per inoltrare una porta specifica (qui 7777, nota che sia discover() sia add_port_mapping() possono restituire errori che dovrebbero essere verificati):

var upnp = UPNP.new()
upnp.discover()
upnp.add_port_mapping(7777)

Per chiudere una porta specifica (ad esempio dopo aver finito di usarla):

upnp.delete_port_mapping(port)

Nota: L'individuazione UPnP blocca il thread attuale. Per eseguire l'individuazione senza bloccare il thread principale, utilizza un Thread in questo modo:

# Emesso quando la configurazione della mappatura delle porte UPnP viene completata (a prescindere dal successo o dal fallimento).
signal upnp_completed(error)

# Sostituiscilo con il numero di porta del tuo server, tra 1024 e 65535.
const SERVER_PORT = 3928
var thread = null

func _upnp_setup(server_port):
    #Le richieste UPNP richiedono un po' di tempo.
    var upnp = UPNP.new()
    var err = upnp.discover()

    if err != UPNP.UPNP_RESULT_SUCCESS:
        push_error(str(err))
        upnp_completed.emit(OK)
        return

    if upnp.get_gateway() and upnp.get_gateway().is_valid_gateway():
        upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "UDP")
        upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "TCP")
        upnp_completed.emit(UPNP.UPNP_RESULT_SUCCESS)

func _ready():
    thread = Thread.new()
    thread.start(_upnp_setup.bind(SERVER_PORT))

func _exit_tree():
    # Attendi la fine del thread qui, per gestire l'uscita dal gioco mentre il thread è in esecuzione.
    thread.wait_to_finish()

Terminologia: Nel contesto della rete UPnP, "gateway" (o "dispositivo gateway Internet", abbreviato IGD) si riferisce ai dispositivi di rete che consentono ai computer nella rete locale di accedere a Internet ("rete WAN"). Questi gateway sono spesso chiamati anche "router".

Insidie:

  • Come spiegato in precedenza, queste chiamate sono bloccanti e non dovrebbero essere eseguite sul thread principale, soprattutto perché possono bloccarsi per più secondi alla volta. Usa altri thread!

  • La rete è fisica e disordinata. I pacchetti si perdono durante il transito o sono filtrati, gli indirizzi, le porte libere e le mappature assegnate cambiano e i dispositivi possono abbandonare o unirsi alla rete in qualsiasi momento. Tieni questo presente, sii diligente quando verifichi e gestisci gli errori e gestiscili con grazia se puoi: aggiungi un'interfaccia utente di errore chiara, timeout e gestione dei nuovi tentativi.

  • Le mappature delle porte possono cambiare (ed essere rimosse) in qualsiasi momento e l'indirizzo IP remoto/esterno del gateway può cambiare allo stesso modo. Dovresti considerare di ri-interrogare l'IP esterno e provare ad aggiornare periodicamente la mappatura delle porte (ad esempio, ogni 5 minuti e in caso di guasti di rete).

  • Non tutti i dispositivi supportano UPnP e alcuni utenti disabilitano il supporto UPnP. Devi gestire questo aspetto (ad esempio documentando e richiedendo all'utente di inoltrare manualmente le porte o aggiungendo metodi alternativi di attraversamento NAT, come un server di relay/mirror o NAT hole punching, STUN/TURN, ecc.).

  • Considera cosa succede in caso di conflitti di mappatura. Forse più utenti sulla stessa rete vorrebbero giocare al tuo gioco allo stesso tempo, o forse un'altra applicazione utilizza la stessa porta. Rendi la porta configurabile e scegli automaticamente una porta in modo ottimale (riprovando con una porta diversa in caso di guasto).

Ulteriori approfondimenti: Se vuoi saperne di più su UPnP (e in particolare su Internet Gateway Device (IGD) e Port Control Protocol (PCP)), Wikipedia è un buon punto di partenza, le specifiche possono essere trovate su Open Connectivity Foundation e l'implementazione di Godot è basata sul client MiniUPnP.

Proprietà

bool

discover_ipv6

false

int

discover_local_port

0

String

discover_multicast_if

""

Metodi

void

add_device(device: UPNPDevice)

int

add_port_mapping(port: int, port_internal: int = 0, desc: String = "", proto: String = "UDP", duration: int = 0) const

void

clear_devices()

int

delete_port_mapping(port: int, proto: String = "UDP") const

int

discover(timeout: int = 2000, ttl: int = 2, device_filter: String = "InternetGatewayDevice")

UPNPDevice

get_device(index: int) const

int

get_device_count() const

UPNPDevice

get_gateway() const

String

query_external_address() const

void

remove_device(index: int)

void

set_device(index: int, device: UPNPDevice)


Enumerazioni

enum UPNPResult: 🔗

UPNPResult UPNP_RESULT_SUCCESS = 0

Il comando o il rilevamento di UPNP è andato a buon fine.

UPNPResult UPNP_RESULT_NOT_AUTHORIZED = 1

Non autorizzato a utilizzare il comando su UPNPDevice. Può essere restituito quando l'utente ha disabilitato UPNP sul proprio router.

UPNPResult UPNP_RESULT_PORT_MAPPING_NOT_FOUND = 2

Non è stata trovata alcuna mappatura di porte per la porta specificata, la combinazione di protocolli sul UPNPDevice specificato.

UPNPResult UPNP_RESULT_INCONSISTENT_PARAMETERS = 3

Parametri inconsistenti.

UPNPResult UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY = 4

Nessuna voce di questo tipo nell'array. Può essere restituito se una determinata combinazione di porta e protocollo non viene trovata su un UPNPDevice.

UPNPResult UPNP_RESULT_ACTION_FAILED = 5

L'azione non è riuscita.

UPNPResult UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED = 6

L'UPNPDevice non consente valori jolly per l'indirizzo IP sorgente.

UPNPResult UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED = 7

L'UPNPDevice non consente valori jolly per la porta esterna.

UPNPResult UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED = 8

L'UPNPDevice non consente valori jolly per la porta interna.

UPNPResult UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD = 9

Il valore dell'host remoto deve essere un carattere jolly.

UPNPResult UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD = 10

Il valore della porta esterna deve essere un carattere jolly.

UPNPResult UPNP_RESULT_NO_PORT_MAPS_AVAILABLE = 11

Non sono disponibili mappe di porte. Potrebbe anche essere restituito se la funzionalità di mappatura di porte non è disponibile.

UPNPResult UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM = 12

In conflitto con un altro meccanismo. Può essere restituito al posto di UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING se una mappatura di porte è in conflitto con una esistente.

UPNPResult UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING = 13

In conflitto con una mappatura di porte esistente.

UPNPResult UPNP_RESULT_SAME_PORT_VALUES_REQUIRED = 14

I valori delle porte esterne e interne devono essere gli stessi.

UPNPResult UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED = 15

Sono supportati solo i lease permanenti. Non usare il parametro duration quando si aggiungono le mappature delle porte.

UPNPResult UPNP_RESULT_INVALID_GATEWAY = 16

Gateway non valida.

UPNPResult UPNP_RESULT_INVALID_PORT = 17

Porta non valida.

UPNPResult UPNP_RESULT_INVALID_PROTOCOL = 18

Protocollo non valido.

UPNPResult UPNP_RESULT_INVALID_DURATION = 19

Durata non valida.

UPNPResult UPNP_RESULT_INVALID_ARGS = 20

Argomenti non validi.

UPNPResult UPNP_RESULT_INVALID_RESPONSE = 21

Risposta non valida.

UPNPResult UPNP_RESULT_INVALID_PARAM = 22

Parametro non valido.

UPNPResult UPNP_RESULT_HTTP_ERROR = 23

Errore HTTP.

UPNPResult UPNP_RESULT_SOCKET_ERROR = 24

Errore di socket.

UPNPResult UPNP_RESULT_MEM_ALLOC_ERROR = 25

Errore di allocazione di memoria.

UPNPResult UPNP_RESULT_NO_GATEWAY = 26

Nessun gateway disponibile. Potresti dover chiamare prima discover() oppure il rilevamento non ha rilevato alcun IGD (InternetGatewayDevice) valido.

UPNPResult UPNP_RESULT_NO_DEVICES = 27

Nessun dispositivo disponibile. Potresti dover chiamare prima discover() oppure il rilevamento non ha rilevato alcun UPNPDevice valido.

UPNPResult UPNP_RESULT_UNKNOWN_ERROR = 28

Errore sconosciuto.


Descrizioni delle proprietà

bool discover_ipv6 = false 🔗

  • void set_discover_ipv6(value: bool)

  • bool is_discover_ipv6()

Se true, l'IPv6 è utilizzato per il rilevamento dei UPNPDevice.


int discover_local_port = 0 🔗

  • void set_discover_local_port(value: int)

  • int get_discover_local_port()

Se 0, la porta locale da usare per la scoperta è scelta automaticamente dal sistema. Se 1, la scoperta sarà fatta dalla porta sorgente 1900 (la stessa della porta di destinazione). Altrimenti, il valore sarà usato come porta.


String discover_multicast_if = "" 🔗

  • void set_discover_multicast_if(value: String)

  • String get_discover_multicast_if()

Interfaccia multicast da usare per la rilevazione. Utilizza l'interfaccia multicast predefinita se vuota.


Descrizioni dei metodi

void add_device(device: UPNPDevice) 🔗

Aggiunge il dispositivo UPNPDevice specificato alla lista dei dispositivi rilevati.


int add_port_mapping(port: int, port_internal: int = 0, desc: String = "", proto: String = "UDP", duration: int = 0) const 🔗

Aggiunge una mappatura per inoltrare la port esterna (tra 1 e 65535, sebbene si consiglia di utilizzare la porta 1024 o superiore) sul gateway predefinito (vedi get_gateway()) alla porta port_internal sulla macchina locale per il protocollo proto (sia "TCP" sia "UDP", con UDP come predefinito). Se una mappatura delle porte per la combinazione di porta e protocollo specificata esiste già su quel dispositivo gateway, questo metodo tenta di sovrascriverla. Se ciò non è desiderato, è possibile recuperare manualmente il gateway con get_gateway() e chiamare add_port_mapping() su di esso, se presente. Si noti che l'inoltro di una porta nota (inferiore a 1024) con UPnP potrebbe non riuscire a seconda del dispositivo.

A seconda del dispositivo gateway, se esiste già una mappatura per quella porta, verrà aggiornata o rifiuterà questo comando a causa di tale conflitto, soprattutto se la mappatura esistente per quella porta non è stata creata tramite UPnP o punta a un indirizzo di rete (o dispositivo) diverso da questo.

Se port_internal è 0 (il valore predefinito), lo stesso numero di porta viene utilizzato sia per la porta esterna sia per la porta interna (il valore di port).

La descrizione (desc) viene mostrata in alcune interfacce utente di gestione dei router e può essere utilizzata per indicare quale applicazione ha aggiunto la mappatura.

La durata del lease della mappatura può essere limitata specificando duration in secondi. Il valore predefinito di 0 significa nessuna durata, ovvero un lease permanente e in particolare alcuni dispositivi supportano solo questi lease permanenti. Si noti che, permanente o meno, questa è solo una richiesta e il gateway può comunque decidere in qualsiasi momento di rimuovere la mappatura (che di solito avviene al riavvio del gateway, quando cambia il suo indirizzo IP esterno o su alcuni modelli quando rileva che una mappatura di porta è diventata inattiva, ovvero non ha avuto traffico per diversi minuti). Se non è 0 (permanente), l'intervallo consentito in base alle specifiche è compreso tra 120 (2 minuti) e 86400 secondi (24 ore).

Vedi UPNPResult per i valori restituiti possibili.


void clear_devices() 🔗

Svuota la lista dei dispositivi rilevati.


int delete_port_mapping(port: int, proto: String = "UDP") const 🔗

Elimina la mappatura di porta per la combinazione di porta e protocollo specificata sul gateway predefinito (vedi get_gateway()), se ne esiste uno. port deve essere una porta valida compresa tra 1 e 65535, proto può essere "TCP" o "UDP". Potrebbe essere rifiutato per le mappature che puntano a indirizzi diversi da questo, per porte note (inferiori a 1024) o per le mappature non aggiunte tramite UPnP. Vedi UPNPResult per i valori restituiti possibili.


int discover(timeout: int = 2000, ttl: int = 2, device_filter: String = "InternetGatewayDevice") 🔗

Individua i UPNPDevice locali. Cancella la lista dei dispositivi individuati in precedenza.

Filtra per dispositivi di tipo IGD (InternetGatewayDevice) come predefinito, poiché gestiscono l'inoltro delle porte. timeout è il tempo di attesa delle risposte in millisecondi. ttl è il tempo di vita ("time-to-live"); specificalo solo se sai cosa stai facendo.

Vedi UPNPResult per i valori possibili restituiti.


UPNPDevice get_device(index: int) const 🔗

Restituisce l'UPNPDevice all'indice index.


int get_device_count() const 🔗

Restituisce il numero di UPNPDevice rilevati.


UPNPDevice get_gateway() const 🔗

Restituisce il gateway predefinito. Questo è il primo UPNPDevice rilevato che è anche un IGD (InternetGatewayDevice) valido.


String query_external_address() const 🔗

Restituisce l'indirizzo IP esterno del gateway predefinito (vedi get_gateway()) come sotto forma di stringa. Restituisce una stringa vuota in caso di errore.


void remove_device(index: int) 🔗

Rimuove il dispositivo all'indice index dalla lista dei dispositivi rilevati.


void set_device(index: int, device: UPNPDevice) 🔗

Imposta il dispositivo all'indice index dalla lista dei dispositivi rilevati a device.