Skip to content

Instantly share code, notes, and snippets.

@dennisjenkins75
Created March 30, 2022 06:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dennisjenkins75/2d8e1cc5591a877583336ddfa62fa758 to your computer and use it in GitHub Desktop.
Save dennisjenkins75/2d8e1cc5591a877583336ddfa62fa758 to your computer and use it in GitHub Desktop.
// Small multi-threaded C++11 program to reproduce the ENet bug reported in
// https://github.com/lsalzman/enet/issues/198
//
// Compile via:
//
// g++ -Wall --std=c++11 -Ienet ./enet_demo.cc -o ./enet_demo -lenet
#include <atomic>
#include <cassert>
#include <enet/enet.h>
#include <iostream>
#include <mutex>
#include <thread>
constexpr size_t kMaxConnections = 1;
constexpr size_t kMaxChannels = 1;
constexpr uint16_t kUdpPort = 49999;
constexpr uint32_t kConnectionSentinal = 0x50564500; // "PVE\000"
std::mutex enet_mutex;
std::atomic<bool> running(true);
void DumpEvent(const std::string &side, const ENetEvent *event) {
std::cout << side << " Event: type:" << event->type
<< ", data:" << event->data << ", channel:" << event->channelID
<< ", addr.port:" << event->peer->address.port;
if (event->packet) {
std::cout << ", packet.size:" << event->packet->dataLength;
} else {
std::cout << ", packet:NULL";
}
std::cout << "\n";
}
void DriveEnetHost(const std::string &side, ENetHost *host) {
while (running) {
// Allow other thread to have the mutex.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::unique_lock<std::mutex> lock(enet_mutex);
ENetEvent event;
while (enet_host_service(host, &event, 100) > 0) {
// We're holding the mutex, so its safe to use std::cout.
DumpEvent(side, &event);
switch (event.type) {
case ENET_EVENT_TYPE_NONE:
break;
case ENET_EVENT_TYPE_CONNECT:
if (event.data != kConnectionSentinal) {
std::cout << "CONNECT: event.data = " << event.data
<< " has the wrong value.\n";
}
break;
case ENET_EVENT_TYPE_DISCONNECT:
break;
case ENET_EVENT_TYPE_RECEIVE:
enet_packet_destroy(event.packet);
break;
}
}
}
}
void ClientThread() {
std::unique_lock<std::mutex> lock(enet_mutex);
std::cout << "ClientThread() entry.\n";
ENetHost *client =
enet_host_create(NULL, kMaxConnections, kMaxChannels, 0, 0);
assert(client);
ENetAddress server_address;
enet_address_set_host_ip(&server_address, "127.0.0.1");
server_address.port = kUdpPort;
ENetPeer *peer = enet_host_connect(client, &server_address, kMaxChannels,
kConnectionSentinal);
assert(peer);
lock.unlock();
DriveEnetHost("client", client);
lock.lock();
enet_host_destroy(client);
std::cout << "ClientThread() exit.\n";
}
void ServerThread() {
ENetAddress address;
address.host = ENET_HOST_ANY;
address.port = kUdpPort;
std::unique_lock<std::mutex> lock(enet_mutex);
std::cout << "ServerThread() entry.\n";
ENetHost *server =
enet_host_create(&address, kMaxConnections, kMaxChannels, 0, 0);
assert(server);
lock.unlock();
DriveEnetHost("server", server);
lock.lock();
enet_host_destroy(server);
std::cout << "ServerThread() exit.\n";
}
int main(int argc, char *argv[]) {
enet_initialize();
std::cout << "ENet version: " << enet_linked_version() << "\n";
// Create the server, give it time to start up.
std::thread thd_server(ServerThread);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// Create the client.
std::thread thd_client(ClientThread);
// Give the client time to attempt to connect to the server.
// Since its over loopback, its very fast on Linux.
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
running = false;
thd_server.join();
thd_client.join();
enet_deinitialize();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment