1/**************************************************************************/
2/* enet_multiplayer_peer.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "enet_multiplayer_peer.h"
32
33#include "core/io/ip.h"
34#include "core/io/marshalls.h"
35#include "core/os/os.h"
36
37void ENetMultiplayerPeer::set_target_peer(int p_peer) {
38 target_peer = p_peer;
39}
40
41int ENetMultiplayerPeer::get_packet_peer() const {
42 ERR_FAIL_COND_V_MSG(!_is_active(), 1, "The multiplayer instance isn't currently active.");
43 ERR_FAIL_COND_V(incoming_packets.size() == 0, 1);
44
45 return incoming_packets.front()->get().from;
46}
47
48MultiplayerPeer::TransferMode ENetMultiplayerPeer::get_packet_mode() const {
49 ERR_FAIL_COND_V_MSG(!_is_active(), TRANSFER_MODE_RELIABLE, "The multiplayer instance isn't currently active.");
50 ERR_FAIL_COND_V(incoming_packets.size() == 0, TRANSFER_MODE_RELIABLE);
51 return incoming_packets.front()->get().transfer_mode;
52}
53
54int ENetMultiplayerPeer::get_packet_channel() const {
55 ERR_FAIL_COND_V_MSG(!_is_active(), 1, "The multiplayer instance isn't currently active.");
56 ERR_FAIL_COND_V(incoming_packets.size() == 0, 1);
57 int ch = incoming_packets.front()->get().channel;
58 if (ch >= SYSCH_MAX) { // First 2 channels are reserved.
59 return ch - SYSCH_MAX + 1;
60 }
61 return 0;
62}
63
64Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) {
65 ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
66 set_refuse_new_connections(false);
67 Ref<ENetConnection> host;
68 host.instantiate();
69 Error err = host->create_host_bound(bind_ip, p_port, p_max_clients, 0, p_max_channels > 0 ? p_max_channels + SYSCH_MAX : 0, p_out_bandwidth);
70 if (err != OK) {
71 return err;
72 }
73
74 active_mode = MODE_SERVER;
75 unique_id = 1;
76 connection_status = CONNECTION_CONNECTED;
77 hosts[0] = host;
78 return OK;
79}
80
81Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, int p_channel_count, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) {
82 ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
83 set_refuse_new_connections(false);
84 Ref<ENetConnection> host;
85 host.instantiate();
86 Error err;
87 if (p_local_port) {
88 err = host->create_host_bound(bind_ip, p_local_port, 1, 0, p_in_bandwidth, p_out_bandwidth);
89 } else {
90 err = host->create_host(1, 0, p_in_bandwidth, p_out_bandwidth);
91 }
92 if (err != OK) {
93 return err;
94 }
95
96 unique_id = generate_unique_id();
97
98 Ref<ENetPacketPeer> peer = host->connect_to_host(p_address, p_port, p_channel_count > 0 ? p_channel_count + SYSCH_MAX : 0, unique_id);
99 if (peer.is_null()) {
100 host->destroy();
101 ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Couldn't connect to the ENet multiplayer server.");
102 }
103
104 // Need to wait for CONNECT event.
105 connection_status = CONNECTION_CONNECTING;
106 active_mode = MODE_CLIENT;
107 peers[1] = peer;
108 hosts[0] = host;
109
110 return OK;
111}
112
113Error ENetMultiplayerPeer::create_mesh(int p_id) {
114 ERR_FAIL_COND_V_MSG(p_id <= 0, ERR_INVALID_PARAMETER, "The unique ID must be greater then 0");
115 ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
116 active_mode = MODE_MESH;
117 unique_id = p_id;
118 connection_status = CONNECTION_CONNECTED;
119 return OK;
120}
121
122Error ENetMultiplayerPeer::add_mesh_peer(int p_id, Ref<ENetConnection> p_host) {
123 ERR_FAIL_COND_V(p_host.is_null(), ERR_INVALID_PARAMETER);
124 ERR_FAIL_COND_V_MSG(active_mode != MODE_MESH, ERR_UNCONFIGURED, "The multiplayer instance is not configured as a mesh. Call 'create_mesh' first.");
125 List<Ref<ENetPacketPeer>> host_peers;
126 p_host->get_peers(host_peers);
127 ERR_FAIL_COND_V_MSG(host_peers.size() != 1 || host_peers[0]->get_state() != ENetPacketPeer::STATE_CONNECTED, ERR_INVALID_PARAMETER, "The provided host must have exactly one peer in the connected state.");
128 hosts[p_id] = p_host;
129 peers[p_id] = host_peers[0];
130 emit_signal(SNAME("peer_connected"), p_id);
131 return OK;
132}
133
134void ENetMultiplayerPeer::_store_packet(int32_t p_source, ENetConnection::Event &p_event) {
135 Packet packet;
136 packet.packet = p_event.packet;
137 packet.channel = p_event.channel_id;
138 packet.from = p_source;
139 if (p_event.packet->flags & ENET_PACKET_FLAG_RELIABLE) {
140 packet.transfer_mode = TRANSFER_MODE_RELIABLE;
141 } else if (p_event.packet->flags & ENET_PACKET_FLAG_UNSEQUENCED) {
142 packet.transfer_mode = TRANSFER_MODE_UNRELIABLE;
143 } else {
144 packet.transfer_mode = TRANSFER_MODE_UNRELIABLE_ORDERED;
145 }
146 packet.packet->referenceCount++;
147 incoming_packets.push_back(packet);
148}
149
150void ENetMultiplayerPeer::_disconnect_inactive_peers() {
151 HashSet<int> to_drop;
152 for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
153 if (E.value->is_active()) {
154 continue;
155 }
156 to_drop.insert(E.key);
157 }
158 for (const int &P : to_drop) {
159 peers.erase(P);
160 if (hosts.has(P)) {
161 hosts.erase(P);
162 }
163 ERR_CONTINUE(active_mode == MODE_CLIENT && P != TARGET_PEER_SERVER);
164 emit_signal(SNAME("peer_disconnected"), P);
165 }
166}
167
168void ENetMultiplayerPeer::poll() {
169 ERR_FAIL_COND_MSG(!_is_active(), "The multiplayer instance isn't currently active.");
170
171 _pop_current_packet();
172
173 _disconnect_inactive_peers();
174
175 switch (active_mode) {
176 case MODE_CLIENT: {
177 if (!peers.has(1)) {
178 close();
179 return;
180 }
181 ENetConnection::Event event;
182 ENetConnection::EventType ret = hosts[0]->service(0, event);
183 do {
184 if (ret == ENetConnection::EVENT_CONNECT) {
185 connection_status = CONNECTION_CONNECTED;
186 emit_signal(SNAME("peer_connected"), 1);
187 } else if (ret == ENetConnection::EVENT_DISCONNECT) {
188 if (connection_status == CONNECTION_CONNECTED) {
189 // Client just disconnected from server.
190 emit_signal(SNAME("peer_disconnected"), 1);
191 }
192 close();
193 } else if (ret == ENetConnection::EVENT_RECEIVE) {
194 _store_packet(1, event);
195 } else if (ret != ENetConnection::EVENT_NONE) {
196 close(); // Error.
197 }
198 } while (hosts.has(0) && hosts[0]->check_events(ret, event) > 0);
199 } break;
200 case MODE_SERVER: {
201 ENetConnection::Event event;
202 ENetConnection::EventType ret = hosts[0]->service(0, event);
203 do {
204 if (ret == ENetConnection::EVENT_CONNECT) {
205 if (is_refusing_new_connections()) {
206 event.peer->reset();
207 continue;
208 }
209 // Client joined with invalid ID, probably trying to exploit us.
210 if (event.data < 2 || peers.has((int)event.data)) {
211 event.peer->reset();
212 continue;
213 }
214 int id = event.data;
215 event.peer->set_meta(SNAME("_net_id"), id);
216 peers[id] = event.peer;
217 emit_signal(SNAME("peer_connected"), id);
218 } else if (ret == ENetConnection::EVENT_DISCONNECT) {
219 int id = event.peer->get_meta(SNAME("_net_id"));
220 if (!peers.has(id)) {
221 // Never fully connected.
222 continue;
223 }
224 emit_signal(SNAME("peer_disconnected"), id);
225 peers.erase(id);
226 } else if (ret == ENetConnection::EVENT_RECEIVE) {
227 int32_t source = event.peer->get_meta(SNAME("_net_id"));
228 _store_packet(source, event);
229 } else if (ret != ENetConnection::EVENT_NONE) {
230 close(); // Error
231 }
232 } while (hosts.has(0) && hosts[0]->check_events(ret, event) > 0);
233 } break;
234 case MODE_MESH: {
235 HashSet<int> to_drop;
236 for (KeyValue<int, Ref<ENetConnection>> &E : hosts) {
237 ENetConnection::Event event;
238 ENetConnection::EventType ret = E.value->service(0, event);
239 do {
240 if (ret == ENetConnection::EVENT_CONNECT) {
241 event.peer->reset();
242 } else if (ret == ENetConnection::EVENT_RECEIVE) {
243 _store_packet(E.key, event);
244 } else if (ret == ENetConnection::EVENT_NONE) {
245 break; // Keep polling the others.
246 } else {
247 to_drop.insert(E.key); // Error or disconnect.
248 break; // Keep polling the others.
249 }
250 } while (E.value->check_events(ret, event) > 0);
251 }
252 for (const int &P : to_drop) {
253 if (peers.has(P)) {
254 emit_signal(SNAME("peer_disconnected"), P);
255 peers.erase(P);
256 }
257 hosts.erase(P);
258 }
259 } break;
260 default:
261 return;
262 }
263}
264
265bool ENetMultiplayerPeer::is_server() const {
266 return active_mode == MODE_SERVER;
267}
268
269bool ENetMultiplayerPeer::is_server_relay_supported() const {
270 return active_mode == MODE_SERVER || active_mode == MODE_CLIENT;
271}
272
273void ENetMultiplayerPeer::disconnect_peer(int p_peer, bool p_force) {
274 ERR_FAIL_COND(!_is_active() || !peers.has(p_peer));
275 peers[p_peer]->peer_disconnect(0); // Will be removed during next poll.
276 if (active_mode == MODE_CLIENT || active_mode == MODE_SERVER) {
277 hosts[0]->flush();
278 } else {
279 ERR_FAIL_COND(!hosts.has(p_peer));
280 hosts[p_peer]->flush();
281 }
282 if (p_force) {
283 peers.erase(p_peer);
284 if (hosts.has(p_peer)) {
285 hosts.erase(p_peer);
286 }
287 if (active_mode == MODE_CLIENT) {
288 hosts.clear(); // Avoid flushing again.
289 close();
290 }
291 }
292}
293
294void ENetMultiplayerPeer::close() {
295 if (!_is_active()) {
296 return;
297 }
298
299 _pop_current_packet();
300
301 for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
302 if (E.value.is_valid() && E.value->get_state() == ENetPacketPeer::STATE_CONNECTED) {
303 E.value->peer_disconnect_now(0);
304 }
305 }
306 for (KeyValue<int, Ref<ENetConnection>> &E : hosts) {
307 E.value->flush();
308 }
309
310 active_mode = MODE_NONE;
311 incoming_packets.clear();
312 peers.clear();
313 hosts.clear();
314 unique_id = 0;
315 connection_status = CONNECTION_DISCONNECTED;
316 set_refuse_new_connections(false);
317}
318
319int ENetMultiplayerPeer::get_available_packet_count() const {
320 return incoming_packets.size();
321}
322
323Error ENetMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
324 ERR_FAIL_COND_V_MSG(incoming_packets.size() == 0, ERR_UNAVAILABLE, "No incoming packets available.");
325
326 _pop_current_packet();
327
328 current_packet = incoming_packets.front()->get();
329 incoming_packets.pop_front();
330
331 *r_buffer = (const uint8_t *)(current_packet.packet->data);
332 r_buffer_size = current_packet.packet->dataLength;
333
334 return OK;
335}
336
337Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
338 ERR_FAIL_COND_V_MSG(!_is_active(), ERR_UNCONFIGURED, "The multiplayer instance isn't currently active.");
339 ERR_FAIL_COND_V_MSG(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED, "The multiplayer instance isn't currently connected to any server or client.");
340 ERR_FAIL_COND_V_MSG(target_peer != 0 && !peers.has(ABS(target_peer)), ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer));
341 ERR_FAIL_COND_V(active_mode == MODE_CLIENT && !peers.has(1), ERR_BUG);
342
343 int packet_flags = 0;
344 int channel = SYSCH_RELIABLE;
345 int tr_channel = get_transfer_channel();
346 switch (get_transfer_mode()) {
347 case TRANSFER_MODE_UNRELIABLE: {
348 packet_flags = ENET_PACKET_FLAG_UNSEQUENCED | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT;
349 channel = SYSCH_UNRELIABLE;
350 } break;
351 case TRANSFER_MODE_UNRELIABLE_ORDERED: {
352 packet_flags = ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT;
353 channel = SYSCH_UNRELIABLE;
354 } break;
355 case TRANSFER_MODE_RELIABLE: {
356 packet_flags = ENET_PACKET_FLAG_RELIABLE;
357 channel = SYSCH_RELIABLE;
358 } break;
359 }
360 if (tr_channel > 0) {
361 channel = SYSCH_MAX + tr_channel - 1;
362 }
363
364#ifdef DEBUG_ENABLED
365 if ((packet_flags & ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT) && p_buffer_size > ENET_HOST_DEFAULT_MTU) {
366 WARN_PRINT_ONCE(vformat("Sending %d bytes unreliably which is above the MTU (%d), this will result in higher packet loss", p_buffer_size, ENET_HOST_DEFAULT_MTU));
367 }
368#endif
369
370 ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size, packet_flags);
371 memcpy(&packet->data[0], p_buffer, p_buffer_size);
372
373 if (is_server()) {
374 if (target_peer == 0) {
375 hosts[0]->broadcast(channel, packet);
376
377 } else if (target_peer < 0) {
378 // Send to all but one and make copies for sending.
379 int exclude = -target_peer;
380 for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
381 if (E.key == exclude) {
382 continue;
383 }
384 E.value->send(channel, packet);
385 }
386 _destroy_unused(packet);
387 } else {
388 peers[target_peer]->send(channel, packet);
389 }
390 ERR_FAIL_COND_V(!hosts.has(0), ERR_BUG);
391 hosts[0]->flush();
392
393 } else if (active_mode == MODE_CLIENT) {
394 peers[1]->send(channel, packet); // Send to server for broadcast.
395 ERR_FAIL_COND_V(!hosts.has(0), ERR_BUG);
396 hosts[0]->flush();
397
398 } else {
399 if (target_peer <= 0) {
400 int exclude = ABS(target_peer);
401 for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
402 if (E.key == exclude) {
403 continue;
404 }
405 E.value->send(channel, packet);
406 ERR_CONTINUE(!hosts.has(E.key));
407 hosts[E.key]->flush();
408 }
409 _destroy_unused(packet);
410 } else {
411 peers[target_peer]->send(channel, packet);
412 ERR_FAIL_COND_V(!hosts.has(target_peer), ERR_BUG);
413 hosts[target_peer]->flush();
414 }
415 }
416
417 return OK;
418}
419
420int ENetMultiplayerPeer::get_max_packet_size() const {
421 return 1 << 24; // Anything is good
422}
423
424void ENetMultiplayerPeer::_pop_current_packet() {
425 if (current_packet.packet) {
426 current_packet.packet->referenceCount--;
427 _destroy_unused(current_packet.packet);
428 current_packet.packet = nullptr;
429 current_packet.from = 0;
430 current_packet.channel = -1;
431 }
432}
433
434MultiplayerPeer::ConnectionStatus ENetMultiplayerPeer::get_connection_status() const {
435 return connection_status;
436}
437
438int ENetMultiplayerPeer::get_unique_id() const {
439 ERR_FAIL_COND_V_MSG(!_is_active(), 0, "The multiplayer instance isn't currently active.");
440 return unique_id;
441}
442
443void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enabled) {
444#ifdef GODOT_ENET
445 if (_is_active()) {
446 for (KeyValue<int, Ref<ENetConnection>> &E : hosts) {
447 E.value->refuse_new_connections(p_enabled);
448 }
449 }
450#endif
451 MultiplayerPeer::set_refuse_new_connections(p_enabled);
452}
453
454Ref<ENetConnection> ENetMultiplayerPeer::get_host() const {
455 ERR_FAIL_COND_V(!_is_active(), nullptr);
456 ERR_FAIL_COND_V(active_mode == MODE_MESH, nullptr);
457 return hosts[0];
458}
459
460Ref<ENetPacketPeer> ENetMultiplayerPeer::get_peer(int p_id) const {
461 ERR_FAIL_COND_V(!_is_active(), nullptr);
462 ERR_FAIL_COND_V(!peers.has(p_id), nullptr);
463 ERR_FAIL_COND_V(active_mode == MODE_CLIENT && p_id != 1, nullptr);
464 return peers[p_id];
465}
466
467void ENetMultiplayerPeer::_destroy_unused(ENetPacket *p_packet) {
468 if (p_packet->referenceCount == 0) {
469 enet_packet_destroy(p_packet);
470 }
471}
472
473void ENetMultiplayerPeer::_bind_methods() {
474 ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "max_channels", "in_bandwidth", "out_bandwidth"), &ENetMultiplayerPeer::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0), DEFVAL(0));
475 ClassDB::bind_method(D_METHOD("create_client", "address", "port", "channel_count", "in_bandwidth", "out_bandwidth", "local_port"), &ENetMultiplayerPeer::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0));
476 ClassDB::bind_method(D_METHOD("create_mesh", "unique_id"), &ENetMultiplayerPeer::create_mesh);
477 ClassDB::bind_method(D_METHOD("add_mesh_peer", "peer_id", "host"), &ENetMultiplayerPeer::add_mesh_peer);
478 ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &ENetMultiplayerPeer::set_bind_ip);
479
480 ClassDB::bind_method(D_METHOD("get_host"), &ENetMultiplayerPeer::get_host);
481 ClassDB::bind_method(D_METHOD("get_peer", "id"), &ENetMultiplayerPeer::get_peer);
482
483 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "host", PROPERTY_HINT_RESOURCE_TYPE, "ENetConnection", PROPERTY_USAGE_NONE), "", "get_host");
484}
485
486ENetMultiplayerPeer::ENetMultiplayerPeer() {
487 bind_ip = IPAddress("*");
488}
489
490ENetMultiplayerPeer::~ENetMultiplayerPeer() {
491 if (_is_active()) {
492 close();
493 }
494}
495
496// Sets IP for ENet to bind when using create_server or create_client
497// if no IP is set, then ENet bind to ENET_HOST_ANY
498void ENetMultiplayerPeer::set_bind_ip(const IPAddress &p_ip) {
499 ERR_FAIL_COND_MSG(!p_ip.is_valid() && !p_ip.is_wildcard(), vformat("Invalid bind IP address: %s", String(p_ip)));
500
501 bind_ip = p_ip;
502}
503