Skip to content

Commit

Permalink
code: added up to 65k peers support as optional feature, fixed possib…
Browse files Browse the repository at this point in the history
…le read out of bounds and small sizeof readability improvement, tests adjustments
  • Loading branch information
emcifuntik committed Jan 6, 2025
1 parent e8a7dfa commit 57a5d42
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 16 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ jobs:
run: cmake --build build
- name: Run unit tests
run: cd build ; .\Debug\enet_test.exe
- name: Run unit tests with extra peers
run: cd build ; .\Debug\enet_test_extra_peers.exe

build-lin:
name: Test Linux
Expand All @@ -54,6 +56,8 @@ jobs:
run: cmake --build build
- name: Test build on Linux
run: build/enet_test
- name: Test build on Linux with extra peers
run: build/enet_test_extra_peers

build-mac:
name: Test macOS
Expand All @@ -67,6 +71,8 @@ jobs:
run: cmake --build build
- name: Test build on macOS
run: build/enet_test
- name: Test build on macOS with extra peers
run: build/enet_test_extra_peers

done:
name: Notify about status
Expand Down
32 changes: 25 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ project(enet C)
option(ENET_STATIC "Build enet as a static library" ON)
option(ENET_SHARED "Build enet as a shared library" OFF)
option(ENET_TEST "Build enet tests" ON)
option(ENET_USE_MORE_PEERS "Build enet with up to 65k peers support" OFF)

if (ENET_USE_MORE_PEERS)
add_definitions(-DENET_USE_MORE_PEERS)
endif()

# -----------------------------
# 2) Static library
Expand Down Expand Up @@ -59,18 +64,31 @@ endif()
# 4) Tests (optional)
# -----------------------------
if(ENET_TEST)
add_executable(enet_test test/build.c)
target_include_directories(enet_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(enet_test_interface INTERFACE)

if(WIN32)
target_link_libraries(enet_test PUBLIC winmm ws2_32)
endif()
target_include_directories(enet_test_interface INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include
)

if(TARGET enet_static)
target_link_libraries(enet_test PRIVATE enet_static)
target_link_libraries(enet_test_interface INTERFACE enet_static)
elseif(TARGET enet_shared)
target_link_libraries(enet_test PRIVATE enet_shared)
target_link_libraries(enet_test_interface INTERFACE enet_shared)
endif()

if(WIN32)
target_link_libraries(enet_test_interface INTERFACE winmm ws2_32)
endif()

# Default test
add_executable(enet_test test/build.c)
target_link_libraries(enet_test PRIVATE enet_test_interface)

# Test with more peers
add_executable(enet_test_extra_peers test/build.c)
target_link_libraries(enet_test_extra_peers PRIVATE enet_test_interface)
target_compile_definitions(enet_test_extra_peers PRIVATE ENET_USE_MORE_PEERS)

endif()

# -----------------------------
Expand Down
76 changes: 72 additions & 4 deletions include/enet.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,11 @@ extern "C" {
ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536,
ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1,
ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255,
#ifdef ENET_USE_MORE_PEERS
ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFFF,
#else
ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF,
#endif
ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024
};

Expand All @@ -332,12 +336,22 @@ extern "C" {
ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7),
ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6),

#ifdef ENET_USE_MORE_PEERS
ENET_PROTOCOL_HEADER_FLAG_PEER_EXTRA = (1 << 13),
ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14),
ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15),
ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_PEER_EXTRA | ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME,

ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 11),
ENET_PROTOCOL_HEADER_SESSION_SHIFT = 11
#else
ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14),
ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15),
ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME,

ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12),
ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12
#endif
} ENetProtocolFlag;

#ifdef _MSC_VER
Expand All @@ -354,6 +368,10 @@ extern "C" {
enet_uint16 sentTime;
} ENET_PACKED ENetProtocolHeader;

typedef struct _ENetProtocolHeaderMinimal {
enet_uint16 peerID;
} ENET_PACKED ENetProtocolHeaderMinimal;

typedef struct _ENetProtocolCommandHeader {
enet_uint8 command;
enet_uint8 channelID;
Expand Down Expand Up @@ -2483,7 +2501,7 @@ extern "C" {
enet_uint16 peerID, flags;
enet_uint8 sessionID;

if (host->receivedDataLength < (size_t) &((ENetProtocolHeader *) 0)->sentTime) {
if (host->receivedDataLength < sizeof(ENetProtocolHeaderMinimal)) {
return 0;
}

Expand All @@ -2494,8 +2512,27 @@ extern "C" {
flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK;
peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK);

headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : (size_t) &((ENetProtocolHeader *) 0)->sentTime);
headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : sizeof(ENetProtocolHeaderMinimal));

#ifdef ENET_USE_MORE_PEERS
if (flags & ENET_PROTOCOL_HEADER_FLAG_PEER_EXTRA) {
if (host->receivedDataLength < headerSize + sizeof(enet_uint8)) {
return 0;
}

enet_uint8 * headerExtraPeerID = (enet_uint8 *) & host -> receivedData [headerSize];
enet_uint8 peerIDExtra = *headerExtraPeerID;
peerID = (peerID & 0x07FF) | ((enet_uint16)peerIDExtra << 11);

headerSize += sizeof (enet_uint8);
}
#endif

if (host->checksum != NULL) {
if (host->receivedDataLength < headerSize + sizeof(enet_uint32)) {
return 0;
}

headerSize += sizeof(enet_uint32);
}

Expand Down Expand Up @@ -3081,7 +3118,13 @@ extern "C" {
} /* enet_protocol_send_reliable_outgoing_commands */

static int enet_protocol_send_outgoing_commands(ENetHost *host, ENetEvent *event, int checkForTimeouts) {
enet_uint8 headerData[sizeof(ENetProtocolHeader) + sizeof(enet_uint32)];
enet_uint8 headerData[
sizeof(ENetProtocolHeader)
#ifdef ENET_USE_MORE_PEERS
+ sizeof(enet_uint8) // additional peer id byte
#endif
+ sizeof(enet_uint32)
];
ENetProtocolHeader *header = (ENetProtocolHeader *) headerData;
ENetPeer *currentPeer;
int sentLength;
Expand Down Expand Up @@ -3171,7 +3214,7 @@ extern "C" {
header->sentTime = ENET_HOST_TO_NET_16(host->serviceTime & 0xFFFF);
host->buffers[0].dataLength = sizeof(ENetProtocolHeader);
} else {
host->buffers[0].dataLength = (size_t) &((ENetProtocolHeader *) 0)->sentTime;
host->buffers[0].dataLength = sizeof(ENetProtocolHeaderMinimal);
}

shouldCompress = 0;
Expand All @@ -3190,7 +3233,32 @@ extern "C" {
if (currentPeer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID) {
host->headerFlags |= currentPeer->outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT;
}

#ifdef ENET_USE_MORE_PEERS
{
enet_uint16 basePeerID = (enet_uint16)(currentPeer->outgoingPeerID & 0x07FF);
enet_uint16 flagsAndSession = (enet_uint16)(host->headerFlags & 0xF800); /* top bits only */

if (currentPeer->outgoingPeerID > 0x07FF)
{
flagsAndSession |= ENET_PROTOCOL_HEADER_FLAG_PEER_EXTRA;
header->peerID = ENET_HOST_TO_NET_16(basePeerID | flagsAndSession);
{
enet_uint8 overflowByte = (enet_uint8)((currentPeer->outgoingPeerID >> 11) & 0xFF);
enet_uint8 *extraPeerIDByte = &headerData[host->buffers[0].dataLength];
*extraPeerIDByte = overflowByte;
host->buffers[0].dataLength += sizeof(enet_uint8);
}
}
else
{
header->peerID = ENET_HOST_TO_NET_16(basePeerID | flagsAndSession);
}
}
#else
header->peerID = ENET_HOST_TO_NET_16(currentPeer->outgoingPeerID | host->headerFlags);
#endif

if (host->checksum != NULL) {
enet_uint32 *checksum = (enet_uint32 *) &headerData[host->buffers[0].dataLength];
*checksum = currentPeer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer->connectID : 0;
Expand Down
21 changes: 16 additions & 5 deletions test/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@ typedef struct {
ENetPeer *peer;
} Client;

#ifdef ENET_USE_MORE_PEERS
#define MAX_CLIENTS 5000
#else
#define MAX_CLIENTS 32
#endif

unsigned long long counter = 0;

void host_server(ENetHost *server) {
ENetEvent event;
while (enet_host_service(server, &event, 2) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT:
printf("A new client connected from ::1:%u.\n", event.peer->address.port);
printf("A new peer with ID %u connected from ::1:%u.\n", event.peer->incomingPeerID , event.peer->address.port);
/* Store any relevant client information here. */
event.peer->data = "Client information";
event.peer->data = (void*)(counter++);
break;
case ENET_EVENT_TYPE_RECEIVE:
printf("A packet of length %zu containing %s was received from %s on channel %u.\n",
Expand All @@ -30,7 +38,7 @@ void host_server(ENetHost *server) {
break;

case ENET_EVENT_TYPE_DISCONNECT:
printf ("%s disconnected.\n", (char *)event.peer->data);
printf ("Peer with ID %u disconnected.\n", event.peer->incomingPeerID);
/* Reset the peer's client information. */
event.peer->data = NULL;
break;
Expand All @@ -51,8 +59,6 @@ int main() {
return 1;
}

#define MAX_CLIENTS 32

int i = 0;
ENetHost *server;
Client clients[MAX_CLIENTS];
Expand Down Expand Up @@ -81,6 +87,8 @@ int main() {
}
}

printf("running server...\n");

// program will make N iterations, and then exit
static int counter = 1000;

Check notice

Code scanning / CodeQL

Local variable hides global variable Note test

Local variable counter hides a
global variable
with the same name.

Expand All @@ -95,9 +103,12 @@ int main() {
counter--;
} while (counter > 0);

printf("stopping clients...\n");

for (i = 0; i < MAX_CLIENTS; ++i) {
enet_peer_disconnect_now(clients[i].peer, 0);
enet_host_destroy(clients[i].host);
host_server(server);
}

host_server(server);
Expand Down

0 comments on commit 57a5d42

Please # to comment.