Skip to content

Commit

Permalink
[Net] ENet poll now only service the connection once.
Browse files Browse the repository at this point in the history
It used to call `enet_host_service` until all events were consumed, but
that also meant constantly polling the connection leading to potentially
unbounded processing time.

It now only service the connection once, and instead consumes all the
retrieved events via `enet_host_check_events`.
  • Loading branch information
jordo authored and Faless committed Dec 15, 2021
1 parent 397d895 commit 373d5ea
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 164 deletions.
88 changes: 52 additions & 36 deletions modules/enet/enet_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,58 +117,36 @@ Ref<ENetPacketPeer> ENetConnection::connect_to_host(const String &p_address, int
return out;
}

ENetConnection::EventType ENetConnection::service(int p_timeout, Event &r_event) {
ERR_FAIL_COND_V_MSG(!host, EVENT_ERROR, "The ENetConnection instance isn't currently active.");
ERR_FAIL_COND_V(r_event.peer.is_valid(), EVENT_ERROR);

// Drop peers that have already been disconnected.
// NOTE: Forcibly disconnected peers (i.e. peers disconnected via
// enet_peer_disconnect*) do not trigger DISCONNECTED events.
List<Ref<ENetPacketPeer>>::Element *E = peers.front();
while (E) {
if (!E->get()->is_active()) {
peers.erase(E->get());
}
E = E->next();
}

ENetEvent event;
int ret = enet_host_service(host, &event, p_timeout);

if (ret < 0) {
return EVENT_ERROR;
} else if (ret == 0) {
return EVENT_NONE;
}
switch (event.type) {
ENetConnection::EventType ENetConnection::_parse_event(const ENetEvent &p_event, Event &r_event) {
switch (p_event.type) {
case ENET_EVENT_TYPE_CONNECT: {
if (event.peer->data == nullptr) {
Ref<ENetPacketPeer> pp = memnew(ENetPacketPeer(event.peer));
if (p_event.peer->data == nullptr) {
Ref<ENetPacketPeer> pp = memnew(ENetPacketPeer(p_event.peer));
peers.push_back(pp);
}
r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data);
r_event.data = event.data;
r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data);
r_event.data = p_event.data;
return EVENT_CONNECT;
} break;
case ENET_EVENT_TYPE_DISCONNECT: {
// A peer disconnected.
if (event.peer->data != nullptr) {
Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data);
if (p_event.peer->data != nullptr) {
Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data);
pp->_on_disconnect();
peers.erase(pp);
r_event.peer = pp;
r_event.data = event.data;
r_event.data = p_event.data;
return EVENT_DISCONNECT;
}
return EVENT_ERROR;
} break;
case ENET_EVENT_TYPE_RECEIVE: {
// Packet reveived.
if (event.peer->data != nullptr) {
Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data);
r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data);
r_event.channel_id = event.channelID;
r_event.packet = event.packet;
if (p_event.peer->data != nullptr) {
Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data);
r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data);
r_event.channel_id = p_event.channelID;
r_event.packet = p_event.packet;
return EVENT_RECEIVE;
}
return EVENT_ERROR;
Expand All @@ -180,6 +158,44 @@ ENetConnection::EventType ENetConnection::service(int p_timeout, Event &r_event)
}
}

ENetConnection::EventType ENetConnection::service(int p_timeout, Event &r_event) {
ERR_FAIL_COND_V_MSG(!host, EVENT_ERROR, "The ENetConnection instance isn't currently active.");
ERR_FAIL_COND_V(r_event.peer.is_valid(), EVENT_ERROR);

// Drop peers that have already been disconnected.
// NOTE: Forcibly disconnected peers (i.e. peers disconnected via
// enet_peer_disconnect*) do not trigger DISCONNECTED events.
List<Ref<ENetPacketPeer>>::Element *E = peers.front();
while (E) {
if (!E->get()->is_active()) {
peers.erase(E->get());
}
E = E->next();
}

ENetEvent event;
int ret = enet_host_service(host, &event, p_timeout);

if (ret < 0) {
return EVENT_ERROR;
} else if (ret == 0) {
return EVENT_NONE;
}
return _parse_event(event, r_event);
}

int ENetConnection::check_events(EventType &r_type, Event &r_event) {
ERR_FAIL_COND_V_MSG(!host, -1, "The ENetConnection instance isn't currently active.");
ENetEvent event;
int ret = enet_host_check_events(host, &event);
if (ret < 0) {
r_type = EVENT_ERROR;
return ret;
}
r_type = _parse_event(event, r_event);
return ret;
}

void ENetConnection::flush() {
ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active.");
enet_host_flush(host);
Expand Down
2 changes: 2 additions & 0 deletions modules/enet/enet_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class ENetConnection : public RefCounted {
ENetHost *host = nullptr;
List<Ref<ENetPacketPeer>> peers;

EventType _parse_event(const ENetEvent &p_event, Event &r_event);
Error _create(ENetAddress *p_address, int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth);
Array _service(int p_timeout = 0);
void _broadcast(int p_channel, PackedByteArray p_packet, int p_flags);
Expand Down Expand Up @@ -110,6 +111,7 @@ class ENetConnection : public RefCounted {
void destroy();
Ref<ENetPacketPeer> connect_to_host(const String &p_address, int p_port, int p_channels, int p_data = 0);
EventType service(int p_timeout, Event &r_event);
int check_events(EventType &r_type, Event &r_event);
void flush();
void bandwidth_limit(int p_in_bandwidth = 0, int p_out_bandwidth = 0);
void channel_limit(int p_max_channels);
Expand Down
Loading

0 comments on commit 373d5ea

Please sign in to comment.