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

Наследует: RefCounted < Object

Функции Universal Plug and Play (UPnP) для обнаружения сетевых устройств, запросов и переадресации портов.

Описание

This class can be used to discover compatible UPNPDevices on the local network and execute commands on them, like managing port mappings (for port forwarding/NAT traversal) and querying the local and remote network IP address. Note that methods on this class are synchronous and block the calling thread.

To forward a specific port (here 7777, note both discover() and add_port_mapping() can return errors that should be checked):

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

To close a specific port (e.g. after you have finished using it):

upnp.delete_port_mapping(port)

Note: UPnP discovery blocks the current thread. To perform discovery without blocking the main thread, use Threads like this:

# Emitted when UPnP port mapping setup is completed (regardless of success or failure).
signal upnp_completed(error)

# Replace this with your own server port number between 1024 and 65535.
const SERVER_PORT = 3928
var thread = null

func _upnp_setup(server_port):
    # UPNP queries take some time.
    var upnp = UPNP.new()
    var err = upnp.discover()

    if err != UPNP.UPNP_RESULT_SUCCESS:
        push_error(str(err))
        upnp_completed.emit(err)
        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():
    # Wait for thread finish here to handle game exit while the thread is running.
    thread.wait_to_finish()

Terminology: In the context of UPnP networking, "gateway" (or "internet gateway device", short IGD) refers to network devices that allow computers in the local network to access the internet ("wide area network", WAN). These gateways are often also called "routers".

Pitfalls:

  • As explained above, these calls are blocking and shouldn't be run on the main thread, especially as they can block for multiple seconds at a time. Use threading!

  • Networking is physical and messy. Packets get lost in transit or get filtered, addresses, free ports and assigned mappings change, and devices may leave or join the network at any time. Be mindful of this, be diligent when checking and handling errors, and handle these gracefully if you can: add clear error UI, timeouts and re-try handling.

  • Port mappings may change (and be removed) at any time, and the remote/external IP address of the gateway can change likewise. You should consider re-querying the external IP and try to update/refresh the port mapping periodically (for example, every 5 minutes and on networking failures).

  • Not all devices support UPnP, and some users disable UPnP support. You need to handle this (e.g. documenting and requiring the user to manually forward ports, or adding alternative methods of NAT traversal, like a relay/mirror server, or NAT hole punching, STUN/TURN, etc.).

  • Consider what happens on mapping conflicts. Maybe multiple users on the same network would like to play your game at the same time, or maybe another application uses the same port. Make the port configurable, and optimally choose a port automatically (re-trying with a different port on failure).

Further reading: If you want to know more about UPnP (and the Internet Gateway Device (IGD) and Port Control Protocol (PCP) specifically), Wikipedia is a good first stop, the specification can be found at the Open Connectivity Foundation and Godot's implementation is based on the MiniUPnP client.

Свойства

bool

discover_ipv6

false

int

discover_local_port

0

String

discover_multicast_if

""

Методы

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)


Перечисления

enum UPNPResult: 🔗

UPNPResult UPNP_RESULT_SUCCESS = 0

Команда UPNP или обнаружение прошли успешно.

UPNPResult UPNP_RESULT_NOT_AUTHORIZED = 1

Не авторизовано для использования команды на UPNPDevice. Может быть возвращено, если пользователь отключил UPNP на своем маршрутизаторе.

UPNPResult UPNP_RESULT_PORT_MAPPING_NOT_FOUND = 2

Для указанного порта и комбинации протоколов на указанном UPNPDevice сопоставление портов не найдено.

UPNPResult UPNP_RESULT_INCONSISTENT_PARAMETERS = 3

Несоответствующие параметры.

UPNPResult UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY = 4

Такой записи в массиве нет. Может быть возвращён, если заданная комбинация порта и протокола не найдена на UPNPDevice.

UPNPResult UPNP_RESULT_ACTION_FAILED = 5

Действие не удалось.

UPNPResult UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED = 6

UPNPDevice не допускает использования подстановочных знаков для исходного IP-адреса.

UPNPResult UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED = 7

UPNPDevice не допускает использования подстановочных знаков для внешнего порта.

UPNPResult UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED = 8

UPNPDevice не допускает использования подстановочных знаков для внутреннего порта.

UPNPResult UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD = 9

Значение удаленного хоста должно быть подстановочным знаком.

UPNPResult UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD = 10

Значение внешнего порта должно быть подстановочным знаком.

UPNPResult UPNP_RESULT_NO_PORT_MAPS_AVAILABLE = 11

Карты портов недоступны. Также может быть возвращен, если функция сопоставления портов недоступна.

UPNPResult UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM = 12

Конфликт с другим механизмом. Может быть возвращено вместо UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING, если сопоставление портов конфликтует с существующим.

UPNPResult UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING = 13

Конфликт с существующим сопоставлением портов.

UPNPResult UPNP_RESULT_SAME_PORT_VALUES_REQUIRED = 14

Значения внешнего и внутреннего порта должны быть одинаковыми.

UPNPResult UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED = 15

Поддерживаются только постоянные аренды. Не используйте параметр duration при добавлении сопоставлений портов.

UPNPResult UPNP_RESULT_INVALID_GATEWAY = 16

Неверный шлюз.

UPNPResult UPNP_RESULT_INVALID_PORT = 17

Неверный порт.

UPNPResult UPNP_RESULT_INVALID_PROTOCOL = 18

Неверный протокол.

UPNPResult UPNP_RESULT_INVALID_DURATION = 19

Неверная продолжительность.

UPNPResult UPNP_RESULT_INVALID_ARGS = 20

Недопустимые аргументы.

UPNPResult UPNP_RESULT_INVALID_RESPONSE = 21

Неверный ответ.

UPNPResult UPNP_RESULT_INVALID_PARAM = 22

Недопустимый параметр.

UPNPResult UPNP_RESULT_HTTP_ERROR = 23

Ошибка HTTP.

UPNPResult UPNP_RESULT_SOCKET_ERROR = 24

Ошибка сокета.

UPNPResult UPNP_RESULT_MEM_ALLOC_ERROR = 25

Ошибка выделения памяти.

UPNPResult UPNP_RESULT_NO_GATEWAY = 26

Нет доступного шлюза. Возможно, сначала нужно вызвать discover(), или discovery не обнаружил ни одного допустимого IGD (InternetGatewayDevices).

UPNPResult UPNP_RESULT_NO_DEVICES = 27

Нет доступных устройств. Возможно, сначала нужно вызвать discover(), или discovery не обнаружил ни одного из допустимых UPNPDevice-ов.

UPNPResult UPNP_RESULT_UNKNOWN_ERROR = 28

Неизвестная ошибка.


Описания свойств

bool discover_ipv6 = false 🔗

  • void set_discover_ipv6(value: bool)

  • bool is_discover_ipv6()

Если true, IPv6 используется для обнаружения UPNPDevice.


int discover_local_port = 0 🔗

  • void set_discover_local_port(value: int)

  • int get_discover_local_port()

Если 0, локальный порт для использования при обнаружении выбирается системой автоматически. Если 1, обнаружение будет выполнено с исходного порта 1900 (тот же, что и порт назначения). В противном случае в качестве порта будет использовано значение.


String discover_multicast_if = "" 🔗

  • void set_discover_multicast_if(value: String)

  • String get_discover_multicast_if()

Интерфейс многоадресной рассылки для использования при обнаружении. Использует интерфейс многоадресной рассылки по умолчанию, если он пуст.


Описания метода

void add_device(device: UPNPDevice) 🔗

Добавляет указанное UPNPDevice в список обнаруженных устройств.


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

Добавляет сопоставление для переадресации внешнего port (от 1 до 65535, хотя рекомендуется использовать порт 1024 или выше) на шлюзе по умолчанию (см. get_gateway()) на port_internal на локальной машине для указанного протокола proto (либо "TCP", либо "UDP", где UDP является значением по умолчанию). Если сопоставление портов для указанной комбинации порта и протокола уже существует на этом шлюзовом устройстве, этот метод пытается перезаписать его. Если это нежелательно, вы можете получить шлюз вручную с помощью get_gateway() и вызвать add_port_mapping() на нем, если таковой имеется. Обратите внимание, что переадресация известного порта (ниже 1024) с помощью UPnP может завершиться неудачей в зависимости от устройства.

В зависимости от шлюзового устройства, если сопоставление для этого порта уже существует, оно либо будет обновлено, либо отклонит эту команду из-за этого конфликта, особенно если существующее сопоставление для этого порта не было создано через UPnP или указывает на другой сетевой адрес (или устройство), нежели этот.

Если port_internal равен 0 (по умолчанию), то для внешнего и внутреннего порта используется один и тот же номер порта (значение port).

Описание (desc) отображается в некоторых пользовательских интерфейсах управления маршрутизаторами и может использоваться для указания того, какое приложение добавило сопоставление.

Аренда duration сопоставления может быть ограничена указанием продолжительности в секундах. Значение по умолчанию 0 означает отсутствие продолжительности, т. е. постоянную аренду, и, в частности, некоторые устройства поддерживают только эти постоянные аренды. Обратите внимание, что независимо от того, постоянная она или нет, это всего лишь запрос, и шлюз все равно может в любой момент решить удалить сопоставление (что обычно происходит при перезагрузке шлюза, при изменении его внешнего IP-адреса или на некоторых моделях, когда он обнаруживает, что сопоставление портов стало неактивным, т. е. не имело трафика в течение нескольких минут). Если не 0 (постоянно), допустимый диапазон согласно спецификации составляет от 120 (2 минуты) до 86400 секунд (24 часа).

Возможные возвращаемые значения см. в UPNPResult.


void clear_devices() 🔗

Очищает список обнаруженных устройств.


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

Удаляет сопоставление портов для заданной комбинации порта и протокола на шлюзе по умолчанию (см. get_gateway()), если таковое существует. port должен быть допустимым портом от 1 до 65535, proto может быть либо "TCP" либо "UDP". Может быть отклонено для сопоставлений, указывающих на адреса, отличные от этого, для известных портов (ниже 1024) или для сопоставлений, не добавленных через UPnP. См. UPNPResult для возможных возвращаемых значений.


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

Обнаруживает локальные UPNPDevice. Очищает список ранее обнаруженных устройств.

Фильтры для устройств типа IGD (InternetGatewayDevice) по умолчанию, так как они управляют переадресацией портов. timeout — это время ожидания ответов в миллисекундах. ttl — это время жизни; касайтесь этого, только если вы знаете, что делаете.

См. UPNPResult для возможных возвращаемых значений.


UPNPDevice get_device(index: int) const 🔗

Возвращает UPNPDevice по указанному index.


int get_device_count() const 🔗

Возвращает количество обнаруженных UPNPDevice.


UPNPDevice get_gateway() const 🔗

Возвращает шлюз по умолчанию. Это первый обнаруженный UPNPDevice, который также является допустимым IGD (InternetGatewayDevice).


String query_external_address() const 🔗

Возвращает внешний IP адрес шлюза по умолчанию (см. get_gateway()) в виде строки. Возвращает пустую строку в случае ошибки.


void remove_device(index: int) 🔗

Удаляет устройство с адресом index из списка обнаруженных устройств.


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

Устанавливает устройство с индексом index из списка обнаруженных устройств на device.