diff options
Diffstat (limited to 'modules/enet')
-rw-r--r-- | modules/enet/SCsub | 6 | ||||
-rw-r--r-- | modules/enet/config.py | 3 | ||||
-rw-r--r-- | modules/enet/doc_classes/NetworkedMultiplayerENet.xml | 33 | ||||
-rw-r--r-- | modules/enet/networked_multiplayer_enet.cpp | 267 | ||||
-rw-r--r-- | modules/enet/networked_multiplayer_enet.h | 42 | ||||
-rw-r--r-- | modules/enet/register_types.cpp | 5 | ||||
-rw-r--r-- | modules/enet/register_types.h | 5 |
7 files changed, 207 insertions, 154 deletions
diff --git a/modules/enet/SCsub b/modules/enet/SCsub index 485c33b1a8..c8f4b3885e 100644 --- a/modules/enet/SCsub +++ b/modules/enet/SCsub @@ -1,13 +1,13 @@ #!/usr/bin/env python -Import('env') -Import('env_modules') +Import("env") +Import("env_modules") env_enet = env_modules.Clone() # Thirdparty source files -if env['builtin_enet']: +if env["builtin_enet"]: thirdparty_dir = "#thirdparty/enet/" thirdparty_sources = [ "godot.cpp", diff --git a/modules/enet/config.py b/modules/enet/config.py index 3e30bbe778..5fd343c75d 100644 --- a/modules/enet/config.py +++ b/modules/enet/config.py @@ -1,13 +1,16 @@ def can_build(env, platform): return True + def configure(env): pass + def get_doc_classes(): return [ "NetworkedMultiplayerENet", ] + def get_doc_path(): return "doc_classes" diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml index 76b3710e96..f46ef2d812 100644 --- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml +++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml @@ -7,8 +7,8 @@ A PacketPeer implementation that should be passed to [member SceneTree.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals. </description> <tutorials> - <link>https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link> - <link>http://enet.bespin.org/usergroup0.html</link> + <link title="High-level multiplayer">https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link> + <link title="API documentation on the ENet website">http://enet.bespin.org/usergroup0.html</link> </tutorials> <methods> <method name="close_connection"> @@ -104,25 +104,50 @@ The IP used when creating a server. This is set to the wildcard [code]"*"[/code] by default, which binds to all available interfaces. The given IP needs to be in IPv4 or IPv6 address format, for example: [code]"192.168.1.1"[/code]. </description> </method> + <method name="set_dtls_certificate"> + <return type="void"> + </return> + <argument index="0" name="certificate" type="X509Certificate"> + </argument> + <description> + Configure the [X509Certificate] to use when [member use_dtls] is [code]true[/code]. For servers, you must also setup the [CryptoKey] via [method set_dtls_key]. + </description> + </method> + <method name="set_dtls_key"> + <return type="void"> + </return> + <argument index="0" name="key" type="CryptoKey"> + </argument> + <description> + Configure the [CryptoKey] to use when [member use_dtls] is [code]true[/code]. Remember to also call [method set_dtls_certificate] to setup your [X509Certificate]. + </description> + </method> </methods> <members> <member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false"> Enforce ordered packets when using [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system. </member> <member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count" default="3"> - The number of channels to be used by ENet. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per channel basis. + The number of channels to be used by ENet. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per-channel basis. This is done to combat latency and reduces ordering restrictions on packets. The delivery status of a packet in one channel won't stall the delivery of other packets in another channel. </member> <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="NetworkedMultiplayerENet.CompressionMode" default="0"> The compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all. </member> + <member name="dtls_verify" type="bool" setter="set_dtls_verify_enabled" getter="is_dtls_verify_enabled" default="true"> + Enable or disable certificate verification when [member use_dtls] [code]true[/code]. + </member> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> <member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true"> Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server. </member> <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="-1"> - Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels, one for reliable and one for unreliable packets. Channel [code]0[/code] is reserved, and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data. + Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels: one for reliable packets, and one for unreliable packets. The channel [code]0[/code] is reserved and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data. See [member channel_count] for more information about ENet channels. </member> <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> + <member name="use_dtls" type="bool" setter="set_dtls_enabled" getter="is_dtls_enabled" default="false"> + When enabled, the client or server created by this peer, will use [PacketPeerDTLS] instead of raw UDP sockets for communicating with the remote peer. This will make the communication encrypted with DTLS at the cost of higher resource usage and potentially larger packet size. + Note: When creating a DTLS server, make sure you setup the key/certificate pair via [method set_dtls_key] and [method set_dtls_certificate]. For DTLS clients, have a look at the [member dtls_verify] option, and configure the certificate accordingly via [method set_dtls_certificate]. + </member> </members> <constants> <constant name="COMPRESS_NONE" value="0" enum="CompressionMode"> diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index 21dd758391..64977ad237 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -34,50 +34,45 @@ #include "core/os/os.h" void NetworkedMultiplayerENet::set_transfer_mode(TransferMode p_mode) { - transfer_mode = p_mode; } -NetworkedMultiplayerPeer::TransferMode NetworkedMultiplayerENet::get_transfer_mode() const { +NetworkedMultiplayerPeer::TransferMode NetworkedMultiplayerENet::get_transfer_mode() const { return transfer_mode; } void NetworkedMultiplayerENet::set_target_peer(int p_peer) { - target_peer = p_peer; } int NetworkedMultiplayerENet::get_packet_peer() const { - - ERR_FAIL_COND_V(!active, 1); + ERR_FAIL_COND_V_MSG(!active, 1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(incoming_packets.size() == 0, 1); return incoming_packets.front()->get().from; } int NetworkedMultiplayerENet::get_packet_channel() const { - - ERR_FAIL_COND_V(!active, -1); + ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(incoming_packets.size() == 0, -1); return incoming_packets.front()->get().channel; } int NetworkedMultiplayerENet::get_last_packet_channel() const { - - ERR_FAIL_COND_V(!active, -1); + ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(!current_packet.packet, -1); return current_packet.channel; } Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) { - - ERR_FAIL_COND_V(active, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(p_in_bandwidth < 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(p_out_bandwidth < 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); + ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The port number must be set between 0 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); + ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); + ERR_FAIL_COND_V(dtls_enabled && (dtls_key.is_null() || dtls_cert.is_null()), ERR_INVALID_PARAMETER); ENetAddress address; memset(&address, 0, sizeof(address)); @@ -104,7 +99,13 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth /* limit incoming bandwidth if > 0 */, p_out_bandwidth /* limit outgoing bandwidth if > 0 */); - ERR_FAIL_COND_V(!host, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create an ENet multiplayer server."); +#ifdef GODOT_ENET + if (dtls_enabled) { + enet_host_dtls_server_setup(host, dtls_key.ptr(), dtls_cert.ptr()); + } + enet_host_refuse_new_connections(host, refuse_connections); +#endif _setup_compressor(); active = true; @@ -114,13 +115,13 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int connection_status = CONNECTION_CONNECTED; return OK; } -Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_client_port) { - ERR_FAIL_COND_V(active, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(p_client_port < 0 || p_client_port > 65535, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(p_in_bandwidth < 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(p_out_bandwidth < 0, ERR_INVALID_PARAMETER); +Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_client_port) { + ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); + ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The server port number must be set between 0 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_client_port < 0 || p_client_port > 65535, ERR_INVALID_PARAMETER, "The client port number must be set between 0 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); + ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); if (p_client_port != 0) { ENetAddress c_client; @@ -135,7 +136,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por if (bind_ip.is_wildcard()) { c_client.host = 0; } else { - ERR_FAIL_COND_V(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6."); c_client.host = *(uint32_t *)bind_ip.get_ipv4(); } #endif @@ -148,14 +149,20 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por p_in_bandwidth /* limit incoming bandwidth if > 0 */, p_out_bandwidth /* limit outgoing bandwidth if > 0 */); } else { - host = enet_host_create(NULL /* create a client host */, + host = enet_host_create(nullptr /* create a client host */, 1 /* only allow 1 outgoing connection */, channel_count /* allow up to channel_count to be used */, p_in_bandwidth /* limit incoming bandwidth if > 0 */, p_out_bandwidth /* limit outgoing bandwidth if > 0 */); } - ERR_FAIL_COND_V(!host, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host."); +#ifdef GODOT_ENET + if (dtls_enabled) { + enet_host_dtls_client_setup(host, dtls_cert.ptr(), dtls_verify, p_address.utf8().get_data()); + } + enet_host_refuse_new_connections(host, refuse_connections); +#endif _setup_compressor(); @@ -169,14 +176,14 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por ip = IP::get_singleton()->resolve_hostname(p_address, IP::TYPE_IPV4); #endif - ERR_FAIL_COND_V(!ip.is_valid(), ERR_CANT_RESOLVE); + ERR_FAIL_COND_V_MSG(!ip.is_valid(), ERR_CANT_RESOLVE, "Couldn't resolve the server IP address or domain name."); } ENetAddress address; #ifdef GODOT_ENET enet_address_set_ip(&address, ip.get_ipv6(), 16); #else - ERR_FAIL_COND_V(!ip.is_ipv4(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(!ip.is_ipv4(), ERR_INVALID_PARAMETER, "Connecting to an IPv6 server isn't supported when using vanilla ENet. Recompile Godot with the bundled ENet library."); address.host = *(uint32_t *)ip.get_ipv4(); #endif address.port = p_port; @@ -186,9 +193,9 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por // Initiate connection, allocating enough channels ENetPeer *peer = enet_host_connect(host, &address, channel_count, unique_id); - if (peer == NULL) { + if (peer == nullptr) { enet_host_destroy(host); - ERR_FAIL_COND_V(!peer, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(!peer, ERR_CANT_CREATE, "Couldn't connect to the ENet multiplayer server."); } // Technically safe to ignore the peer or anything else. @@ -202,17 +209,16 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por } void NetworkedMultiplayerENet::poll() { - - ERR_FAIL_COND(!active); + ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); _pop_current_packet(); ENetEvent event; /* Keep servicing until there are no available events left in queue. */ while (true) { - - if (!host || !active) // Might have been disconnected while emitting a notification + if (!host || !active) { // Might have been disconnected while emitting a notification return; + } int ret = enet_host_service(host, &event, 0); @@ -256,33 +262,32 @@ void NetworkedMultiplayerENet::poll() { if (server) { // Do not notify other peers when server_relay is disabled. - if (!server_relay) + if (!server_relay) { break; + } // Someone connected, notify all the peers available for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - - if (E->key() == *new_id) + if (E->key() == *new_id) { continue; + } // Send existing peers to new peer - ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE); + ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]); encode_uint32(E->key(), &packet->data[4]); enet_peer_send(event.peer, SYSCH_CONFIG, packet); // Send the new peer to existing peers - packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE); + packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]); encode_uint32(*new_id, &packet->data[4]); enet_peer_send(E->get(), SYSCH_CONFIG, packet); } } else { - emit_signal("connection_succeeded"); } } break; case ENET_EVENT_TYPE_DISCONNECT: { - // Reset the peer's client information. int *id = (int *)event.peer->data; @@ -296,20 +301,18 @@ void NetworkedMultiplayerENet::poll() { } if (!server) { - // Client just disconnected from server. emit_signal("server_disconnected"); close_connection(); return; } else if (server_relay) { - // Server just received a client disconnect and is in relay mode, notify everyone else. for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - - if (E->key() == *id) + if (E->key() == *id) { continue; + } - ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE); + ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]); encode_uint32(*id, &packet->data[4]); enet_peer_send(E->get(), SYSCH_CONFIG, packet); @@ -321,7 +324,6 @@ void NetworkedMultiplayerENet::poll() { memdelete(id); } break; case ENET_EVENT_TYPE_RECEIVE: { - if (event.channelID == SYSCH_CONFIG) { // Some config message ERR_CONTINUE(event.packet->dataLength < 8); @@ -334,13 +336,11 @@ void NetworkedMultiplayerENet::poll() { switch (msg) { case SYSMSG_ADD_PEER: { - - peer_map[id] = NULL; + peer_map[id] = nullptr; emit_signal("peer_connected", id); } break; case SYSMSG_REMOVE_PEER: { - peer_map.erase(id); emit_signal("peer_disconnected", id); } break; @@ -348,7 +348,6 @@ void NetworkedMultiplayerENet::poll() { enet_packet_destroy(event.packet); } else if (event.channelID < channel_count) { - Packet packet; packet.packet = event.packet; @@ -380,9 +379,9 @@ void NetworkedMultiplayerENet::poll() { incoming_packets.push_back(packet); // And make copies for sending for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - - if (uint32_t(E->key()) == source) // Do not resend to self + if (uint32_t(E->key()) == source) { // Do not resend to self continue; + } ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, packet.packet->flags); @@ -394,9 +393,9 @@ void NetworkedMultiplayerENet::poll() { // And make copies for sending for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - - if (uint32_t(E->key()) == source || E->key() == -target) // Do not resend to self, also do not send to excluded + if (uint32_t(E->key()) == source || E->key() == -target) { // Do not resend to self, also do not send to excluded continue; + } ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, packet.packet->flags); @@ -417,7 +416,6 @@ void NetworkedMultiplayerENet::poll() { enet_peer_send(peer_map[target], event.channelID, packet.packet); } } else { - incoming_packets.push_back(packet); } @@ -435,14 +433,13 @@ void NetworkedMultiplayerENet::poll() { } bool NetworkedMultiplayerENet::is_server() const { - ERR_FAIL_COND_V(!active, false); + ERR_FAIL_COND_V_MSG(!active, false, "The multiplayer instance isn't currently active."); return server; } void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) { - - ERR_FAIL_COND(!active); + ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); _pop_current_packet(); @@ -473,10 +470,9 @@ void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) { } void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) { - - ERR_FAIL_COND(!active); - ERR_FAIL_COND(!is_server()); - ERR_FAIL_COND(!peer_map.has(p_peer)); + ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); + ERR_FAIL_COND_MSG(!is_server(), "Can't disconnect a peer when not acting as a server."); + ERR_FAIL_COND_MSG(!peer_map.has(p_peer), vformat("Peer ID %d not found in the list of peers.", p_peer)); if (now) { int *id = (int *)peer_map[p_peer]->data; @@ -486,20 +482,20 @@ void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) { // notify everyone else, send disconnect signal & remove from peer_map like in poll() if (server_relay) { for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - if (E->key() == p_peer) { continue; } - ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE); + ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]); encode_uint32(p_peer, &packet->data[4]); enet_peer_send(E->get(), SYSCH_CONFIG, packet); } } - if (id) + if (id) { memdelete(id); + } emit_signal("peer_disconnected", p_peer); peer_map.erase(p_peer); @@ -509,13 +505,11 @@ void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) { } int NetworkedMultiplayerENet::get_available_packet_count() const { - return incoming_packets.size(); } Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - - ERR_FAIL_COND_V(incoming_packets.size() == 0, ERR_UNAVAILABLE); + ERR_FAIL_COND_V_MSG(incoming_packets.size() == 0, ERR_UNAVAILABLE, "No incoming packets available."); _pop_current_packet(); @@ -529,19 +523,19 @@ Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buff } Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - - ERR_FAIL_COND_V(!active, ERR_UNCONFIGURED); - ERR_FAIL_COND_V(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED); + ERR_FAIL_COND_V_MSG(!active, ERR_UNCONFIGURED, "The multiplayer instance isn't currently active."); + ERR_FAIL_COND_V_MSG(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED, "The multiplayer instance isn't currently connected to any server or client."); int packet_flags = 0; int channel = SYSCH_RELIABLE; switch (transfer_mode) { case TRANSFER_MODE_UNRELIABLE: { - if (always_ordered) + if (always_ordered) { packet_flags = 0; - else + } else { packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; + } channel = SYSCH_UNRELIABLE; } break; case TRANSFER_MODE_UNRELIABLE_ORDERED: { @@ -554,24 +548,23 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer } break; } - if (transfer_channel > SYSCH_CONFIG) + if (transfer_channel > SYSCH_CONFIG) { channel = transfer_channel; + } - Map<int, ENetPeer *>::Element *E = NULL; + Map<int, ENetPeer *>::Element *E = nullptr; if (target_peer != 0) { - E = peer_map.find(ABS(target_peer)); - ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer '" + itos(target_peer) + "'."); + ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer)); } - ENetPacket *packet = enet_packet_create(NULL, p_buffer_size + 8, packet_flags); + ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags); encode_uint32(unique_id, &packet->data[0]); // Source ID encode_uint32(target_peer, &packet->data[4]); // Dest ID copymem(&packet->data[8], p_buffer, p_buffer_size); if (server) { - if (target_peer == 0) { enet_host_broadcast(host, channel, packet); } else if (target_peer < 0) { @@ -581,9 +574,9 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer int exclude = -target_peer; for (Map<int, ENetPeer *>::Element *F = peer_map.front(); F; F = F->next()) { - - if (F->key() == exclude) // Exclude packet + if (F->key() == exclude) { // Exclude packet continue; + } ENetPacket *packet2 = enet_packet_create(packet->data, packet->dataLength, packet_flags); @@ -595,7 +588,6 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer enet_peer_send(E->get(), channel, packet); } } else { - ERR_FAIL_COND_V(!peer_map.has(1), ERR_BUG); enet_peer_send(peer_map[1], channel, packet); // Send to server for broadcast } @@ -606,31 +598,26 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer } int NetworkedMultiplayerENet::get_max_packet_size() const { - return 1 << 24; // Anything is good } void NetworkedMultiplayerENet::_pop_current_packet() { - if (current_packet.packet) { enet_packet_destroy(current_packet.packet); - current_packet.packet = NULL; + current_packet.packet = nullptr; current_packet.from = 0; current_packet.channel = -1; } } NetworkedMultiplayerPeer::ConnectionStatus NetworkedMultiplayerENet::get_connection_status() const { - return connection_status; } uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { - uint32_t hash = 0; while (hash == 0 || hash == 1) { - hash = hash_djb2_one_32( (uint32_t)OS::get_singleton()->get_ticks_usec()); hash = hash_djb2_one_32( @@ -649,33 +636,32 @@ uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { } int NetworkedMultiplayerENet::get_unique_id() const { - - ERR_FAIL_COND_V(!active, 0); + ERR_FAIL_COND_V_MSG(!active, 0, "The multiplayer instance isn't currently active."); return unique_id; } void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) { - refuse_connections = p_enable; +#ifdef GODOT_ENET + if (active) { + enet_host_refuse_new_connections(host, p_enable); + } +#endif } bool NetworkedMultiplayerENet::is_refusing_new_connections() const { - return refuse_connections; } void NetworkedMultiplayerENet::set_compression_mode(CompressionMode p_mode) { - compression_mode = p_mode; } NetworkedMultiplayerENet::CompressionMode NetworkedMultiplayerENet::get_compression_mode() const { - return compression_mode; } size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet *)(context); if (size_t(enet->src_compressor_mem.size()) < inLimit) { @@ -706,7 +692,7 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer * mode = Compression::MODE_ZSTD; } break; default: { - ERR_FAIL_V(0); + ERR_FAIL_V_MSG(0, vformat("Invalid ENet compression mode: %d", enet->compression_mode)); } } @@ -716,11 +702,13 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer * } int ret = Compression::compress(enet->dst_compressor_mem.ptrw(), enet->src_compressor_mem.ptr(), ofs, mode); - if (ret < 0) + if (ret < 0) { return 0; + } - if (ret > int(outLimit)) + if (ret > int(outLimit)) { return 0; // Do not bother + } copymem(outData, enet->dst_compressor_mem.ptr(), ret); @@ -728,20 +716,16 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer * } size_t NetworkedMultiplayerENet::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet *)(context); int ret = -1; switch (enet->compression_mode) { case COMPRESS_FASTLZ: { - ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_FASTLZ); } break; case COMPRESS_ZLIB: { - ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_DEFLATE); } break; case COMPRESS_ZSTD: { - ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_ZSTD); } break; default: { @@ -755,12 +739,9 @@ size_t NetworkedMultiplayerENet::enet_decompress(void *context, const enet_uint8 } void NetworkedMultiplayerENet::_setup_compressor() { - switch (compression_mode) { - case COMPRESS_NONE: { - - enet_host_compress(host, NULL); + enet_host_compress(host, nullptr); } break; case COMPRESS_RANGE_CODER: { enet_host_compress_with_range_coder(host); @@ -768,22 +749,19 @@ void NetworkedMultiplayerENet::_setup_compressor() { case COMPRESS_FASTLZ: case COMPRESS_ZLIB: case COMPRESS_ZSTD: { - enet_host_compress(host, &enet_compressor); } break; } } void NetworkedMultiplayerENet::enet_compressor_destroy(void *context) { - // Nothing to do } IP_Address NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const { - - ERR_FAIL_COND_V(!peer_map.has(p_peer_id), IP_Address()); - ERR_FAIL_COND_V(!is_server() && p_peer_id != 1, IP_Address()); - ERR_FAIL_COND_V(peer_map[p_peer_id] == NULL, IP_Address()); + ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IP_Address(), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); + ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IP_Address(), "Can't get the address of peers other than the server (ID -1) when acting as a client."); + ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IP_Address(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); IP_Address out; #ifdef GODOT_ENET @@ -796,10 +774,9 @@ IP_Address NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const { } int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const { - - ERR_FAIL_COND_V(!peer_map.has(p_peer_id), 0); - ERR_FAIL_COND_V(!is_server() && p_peer_id != 1, 0); - ERR_FAIL_COND_V(peer_map[p_peer_id] == NULL, 0); + ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), 0, vformat("Peer ID %d not found in the list of peers.", p_peer_id)); + ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, 0, "Can't get the address of peers other than the server (ID -1) when acting as a client."); + ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, 0, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); #ifdef GODOT_ENET return peer_map[p_peer_id]->address.port; #else @@ -808,9 +785,8 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const { } void NetworkedMultiplayerENet::set_transfer_channel(int p_channel) { - - ERR_FAIL_COND(p_channel < -1 || p_channel >= channel_count); - ERR_FAIL_COND_MSG(p_channel == SYSCH_CONFIG, "Channel " + itos(SYSCH_CONFIG) + " is reserved."); + ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel)); + ERR_FAIL_COND_MSG(p_channel == SYSCH_CONFIG, vformat("The channel %d is reserved.", SYSCH_CONFIG)); transfer_channel = p_channel; } @@ -819,9 +795,8 @@ int NetworkedMultiplayerENet::get_transfer_channel() const { } void NetworkedMultiplayerENet::set_channel_count(int p_channel) { - - ERR_FAIL_COND(active); - ERR_FAIL_COND(p_channel < SYSCH_MAX); + ERR_FAIL_COND_MSG(active, "The channel count can't be set while the multiplayer instance is active."); + ERR_FAIL_COND_MSG(p_channel < SYSCH_MAX, vformat("The channel count must be greater than or equal to %d to account for reserved channels (got %d).", SYSCH_MAX, p_channel)); channel_count = p_channel; } @@ -838,7 +813,7 @@ bool NetworkedMultiplayerENet::is_always_ordered() const { } void NetworkedMultiplayerENet::set_server_relay_enabled(bool p_enabled) { - ERR_FAIL_COND(active); + ERR_FAIL_COND_MSG(active, "Server relaying can't be toggled while the multiplayer instance is active."); server_relay = p_enabled; } @@ -848,7 +823,6 @@ bool NetworkedMultiplayerENet::is_server_relay_enabled() const { } void NetworkedMultiplayerENet::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0)); ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "client_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0)); ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100)); @@ -856,6 +830,12 @@ void NetworkedMultiplayerENet::_bind_methods() { ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &NetworkedMultiplayerENet::set_compression_mode); ClassDB::bind_method(D_METHOD("get_compression_mode"), &NetworkedMultiplayerENet::get_compression_mode); ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &NetworkedMultiplayerENet::set_bind_ip); + ClassDB::bind_method(D_METHOD("set_dtls_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_enabled); + ClassDB::bind_method(D_METHOD("is_dtls_enabled"), &NetworkedMultiplayerENet::is_dtls_enabled); + ClassDB::bind_method(D_METHOD("set_dtls_key", "key"), &NetworkedMultiplayerENet::set_dtls_key); + ClassDB::bind_method(D_METHOD("set_dtls_certificate", "certificate"), &NetworkedMultiplayerENet::set_dtls_certificate); + ClassDB::bind_method(D_METHOD("set_dtls_verify_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_verify_enabled); + ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled); ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address); ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port); @@ -875,6 +855,8 @@ void NetworkedMultiplayerENet::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "channel_count"), "set_channel_count", "get_channel_count"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "always_ordered"), "set_always_ordered", "is_always_ordered"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_relay"), "set_server_relay_enabled", "is_server_relay_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dtls_verify"), "set_dtls_verify_enabled", "is_dtls_verify_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_dtls"), "set_dtls_enabled", "is_dtls_enabled"); BIND_ENUM_CONSTANT(COMPRESS_NONE); BIND_ENUM_CONSTANT(COMPRESS_RANGE_CODER); @@ -884,14 +866,13 @@ void NetworkedMultiplayerENet::_bind_methods() { } NetworkedMultiplayerENet::NetworkedMultiplayerENet() { - active = false; server = false; refuse_connections = false; server_relay = true; unique_id = 0; target_peer = 0; - current_packet.packet = NULL; + current_packet.packet = nullptr; transfer_mode = TRANSFER_MODE_RELIABLE; channel_count = SYSCH_MAX; transfer_channel = -1; @@ -904,10 +885,12 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet() { enet_compressor.destroy = enet_compressor_destroy; bind_ip = IP_Address("*"); + + dtls_enabled = false; + dtls_verify = true; } NetworkedMultiplayerENet::~NetworkedMultiplayerENet() { - if (active) { close_connection(); } @@ -916,7 +899,35 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet() { // Sets IP for ENet to bind when using create_server or create_client // if no IP is set, then ENet bind to ENET_HOST_ANY void NetworkedMultiplayerENet::set_bind_ip(const IP_Address &p_ip) { - ERR_FAIL_COND(!p_ip.is_valid() && !p_ip.is_wildcard()); + ERR_FAIL_COND_MSG(!p_ip.is_valid() && !p_ip.is_wildcard(), vformat("Invalid bind IP address: %s", String(p_ip))); bind_ip = p_ip; } + +void NetworkedMultiplayerENet::set_dtls_enabled(bool p_enabled) { + ERR_FAIL_COND(active); + dtls_enabled = p_enabled; +} + +bool NetworkedMultiplayerENet::is_dtls_enabled() const { + return dtls_enabled; +} + +void NetworkedMultiplayerENet::set_dtls_verify_enabled(bool p_enabled) { + ERR_FAIL_COND(active); + dtls_verify = p_enabled; +} + +bool NetworkedMultiplayerENet::is_dtls_verify_enabled() const { + return dtls_verify; +} + +void NetworkedMultiplayerENet::set_dtls_key(Ref<CryptoKey> p_key) { + ERR_FAIL_COND(active); + dtls_key = p_key; +} + +void NetworkedMultiplayerENet::set_dtls_certificate(Ref<X509Certificate> p_cert) { + ERR_FAIL_COND(active); + dtls_cert = p_cert; +} diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h index 11487b99a5..722c7001fd 100644 --- a/modules/enet/networked_multiplayer_enet.h +++ b/modules/enet/networked_multiplayer_enet.h @@ -31,13 +31,13 @@ #ifndef NETWORKED_MULTIPLAYER_ENET_H #define NETWORKED_MULTIPLAYER_ENET_H +#include "core/crypto/crypto.h" #include "core/io/compression.h" #include "core/io/networked_multiplayer_peer.h" #include <enet/enet.h> class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer { - GDCLASS(NetworkedMultiplayerENet, NetworkedMultiplayerPeer); public: @@ -85,7 +85,6 @@ private: Map<int, ENetPeer *> peer_map; struct Packet { - ENetPacket *packet; int from; int channel; @@ -111,15 +110,20 @@ private: IP_Address bind_ip; + bool dtls_enabled; + Ref<CryptoKey> dtls_key; + Ref<X509Certificate> dtls_cert; + bool dtls_verify; + protected: static void _bind_methods(); public: - virtual void set_transfer_mode(TransferMode p_mode); - virtual TransferMode get_transfer_mode() const; - virtual void set_target_peer(int p_peer); + virtual void set_transfer_mode(TransferMode p_mode) override; + virtual TransferMode get_transfer_mode() const override; + virtual void set_target_peer(int p_peer) override; - virtual int get_packet_peer() const; + virtual int get_packet_peer() const override; virtual IP_Address get_peer_address(int p_peer_id) const; virtual int get_peer_port(int p_peer_id) const; @@ -131,22 +135,22 @@ public: void disconnect_peer(int p_peer, bool now = false); - virtual void poll(); + virtual void poll() override; - virtual bool is_server() const; + virtual bool is_server() const override; - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + virtual int get_available_packet_count() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - virtual int get_max_packet_size() const; + virtual int get_max_packet_size() const override; - virtual ConnectionStatus get_connection_status() const; + virtual ConnectionStatus get_connection_status() const override; - virtual void set_refuse_new_connections(bool p_enable); - virtual bool is_refusing_new_connections() const; + virtual void set_refuse_new_connections(bool p_enable) override; + virtual bool is_refusing_new_connections() const override; - virtual int get_unique_id() const; + virtual int get_unique_id() const override; void set_compression_mode(CompressionMode p_mode); CompressionMode get_compression_mode() const; @@ -166,6 +170,12 @@ public: ~NetworkedMultiplayerENet(); void set_bind_ip(const IP_Address &p_ip); + void set_dtls_enabled(bool p_enabled); + bool is_dtls_enabled() const; + void set_dtls_verify_enabled(bool p_enabled); + bool is_dtls_verify_enabled() const; + void set_dtls_key(Ref<CryptoKey> p_key); + void set_dtls_certificate(Ref<X509Certificate> p_cert); }; VARIANT_ENUM_CAST(NetworkedMultiplayerENet::CompressionMode); diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp index 27f27196d6..18051f756a 100644 --- a/modules/enet/register_types.cpp +++ b/modules/enet/register_types.cpp @@ -35,7 +35,6 @@ static bool enet_ok = false; void register_enet_types() { - if (enet_initialize() != 0) { ERR_PRINT("ENet initialization failure"); } else { @@ -46,7 +45,7 @@ void register_enet_types() { } void unregister_enet_types() { - - if (enet_ok) + if (enet_ok) { enet_deinitialize(); + } } diff --git a/modules/enet/register_types.h b/modules/enet/register_types.h index 19f8c5a352..cac0a4f7ee 100644 --- a/modules/enet/register_types.h +++ b/modules/enet/register_types.h @@ -28,5 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef ENET_REGISTER_TYPES_H +#define ENET_REGISTER_TYPES_H + void register_enet_types(); void unregister_enet_types(); + +#endif // ENET_REGISTER_TYPES_H |