-
-
Save dennisjenkins75/2d8e1cc5591a877583336ddfa62fa758 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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