lsalzman / enet Goto Github PK
View Code? Open in Web Editor NEWENet reliable UDP networking library
License: MIT License
ENet reliable UDP networking library
License: MIT License
Please visit the ENet homepage at http://sauerbraten.org/enet/ for installation and usage instructions. If you obtained this package from github, the quick description on how to build is: # Generate the build system. autoreconf -vfi # Compile and install the library. ./configure && make && make install
I'm Maintainer for enet for
openSUSE
https://build.opensuse.org/package/users/network/libenet
https://build.opensuse.org/package/users/games/libenet
and FreeBSD
http://www.freshports.org/net/enet/
Please change unix.c
cat files/patch-unix.c
--- unix.c.orig 2014-04-24 09:49:05.000000000 +0200
+++ unix.c 2015-02-14 11:32:25.346006823 +0100
@@ -104,7 +104,7 @@
char buffer [2048];
int errnum;
-#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
#else
hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum);
@@ -162,7 +162,7 @@
in.s_addr = address -> host;
-#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
#else
hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum);
I am not finding any way to obtain a unique ID for each peer and host.
I know I can do it myself, but it's considerable work and complexity, as I have to delay all peer connected notifications until I receive the unique ID for each one, and more points of failure for every one that has to do it.
This makes a lot more sense as part of ENet internal protocol than something users have to make themselves.
Hi , every body.
I am making a project internet video media transmission with enet.
The server peers are working fine.
But sometimes, the client peer can not receive any data, and the same time, the connection's status is ENET_PEER_STATE_CONNECTED. Only a matter of enet_host_service can not fire ENET_EVENT_TYPE_RECEIVE event.
Thanks and i need your help.
Can enet support WP8 ?
The library depends on WINMM.Lib, which could not be found in WP8 development.
Is it possible to give support for WP8.1 and greater ?
Thanks for all the good work you create!
I use enet on iOS, and met some error.
When I connect to a server by enet, and lock the screen, the application enter background. And then I unlock the screen, the socket is closed, but no disconnect message notify. So I always met SIGPIPE error.
I think enet need notify the user all peer is disconnect in such a situation.
I've only connected to a host and then started reading my ENetPeer.packetsSent
property. It counts from 0 to 21, and then resets to zero.
Is this expected behavior? packetsSent
is a 32 bit unsigned integer, so shouldn't this count up to the billions before rolling over?
During my build with clang, a few innocuous warnings popped up:
enet/peer.c:227:59: warning: equality comparison with extraneous parentheses [-Wparentheses-equality]
if ((((& peer -> dispatchedCommands) -> sentinel.next) == (& (& peer -> dispatchedCommands) -> sentinel)))
enet/protocol.c:92:67: warning: equality comparison with extraneous parentheses [-Wparentheses-equality]
if ((((& peer -> dispatchedCommands) -> sentinel.next) == (& (& peer -> dispatchedCommands) -> sentinel)))
enet/protocol.c:264:62: warning: equality comparison with extraneous parentheses [-Wparentheses-equality]
if ((((& peer -> sentReliableCommands) -> sentinel.next) == (& (& peer -> sentReliableCommands) -> sentinel)))
enet/protocol.c:1546:65: warning: equality comparison with extraneous parentheses [-Wparentheses-equality]
if ((((& peer -> sentReliableCommands) -> sentinel.next) == (& (& peer -> sentReliableCommands) -> sentinel)))
Nothing critical, but I like keeping the warnings as low as possible (if any at all) :)
@lsalzman A tutorial In the documentation for basic ENetCompressor creation and usage would be most appreciated. How to properly inherit from and create your own ENetCompressor (not actual compression just creating the object and getting a host to use it) with more detailed information/descriptions about the compressor's functions.
Hi,
sorry I am asking here, but I couldn't find anywhere else to ask.
How do I get the file descriptor(s) used by enet so I can poll them simultaneously with any other file descriptors/event loops in my program?
I don't mean to be rude, but running the enet_host_service() with a zero timeout every so often is a bit lame and really doesn't work fantastically well with an event driven model. I generally prefer to write single threaded applications except where there is an actual benefit other than general architectural laziness (e.g. blocking hardware access such as file IO to hard drive), and to do that effectively requires a single event loop which polls all possible event sources simultaneously. Hence I need to obtain the file descriptor(s).
I was planning on writing a GUI app using this library (which I have to say looks amazing - I was very sceptical at first, but it actually looks so cool) and passing networking file descriptors to the X/motif event loop for monitoring along with X events. Thus my code can spring to life whenever an event occurs rather than having to poll X events with a timeout and then call enet_host_service() which is not very responsive to network activity. Also polling a socket with an infinite timeout is much more efficient than repeatedly polling with a zero timeout.
Thanks.
JX.
Hi.
I had a lot of peers allowed for host - say 1000
And i see one good improvements inside enet_host_bandwidth_throttle function
I did performance measurements and i see:
A lot of cpu cycles used (i see at least 2 full loops for full list of peers) inside enet_host_bandwidth_throttle function - even in case when bandwith limiting disabled.
Looks like code
// skip bandwidth throttle processig in case if unlimited in&out bandwidth
if (host -> outgoingBandwidth == 0 && host -> incomingBandwidth == 0 )
return;
after
if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
return;
in enet_host_bandwidth_throttle function solved my problem
Only one question still left - is it safe way or not?
enet_protocol_send_acknowledgements (nor anything else) does not set the host->command.header. reliableSequenceNumber. The value at the time it is sent over the network is either that of a previous command or uninitialized data which triggers static code analyzer tools or runtime analyzers like valgrind.
IE: If a peer connects then sends a 9k reliable message valgrind will report:
==4852== Syscall param sendmsg(msg.msg_iov[3]) points to uninitialised byte(s)
==4852== at 0x63EB2CD: ??? (syscall-template.S:82)
==4852== by 0x8FC75BD: enet_socket_send (unix.c:298)
==4852== by 0x8FC53A3: enet_protocol_send_outgoing_commands (protocol.c:1658)
==4852== by 0x8FC6A75: enet_host_service (protocol.c:1783)
==4852== by 0x8DAC080: ENetServer::DoRunLoop() (enet_server.cc:314)
==4852== by 0x8DAB06A: ENetServer::ThreadFunction(void*) (enet_server.cc:104)
==4852== by 0x63E2D8B: start_thread (pthread_create.c:304)
==4852== by 0x66E0C2C: clone (clone.S:112)
==4852== Address 0x7d2f22c is 204 bytes inside a block of size 10,976 alloc'd
==4852== at 0x4C2A66E: malloc (vg_replace_malloc.c:270)
==4852== by 0x8FC1139: enet_malloc (callbacks.c:34)
==4852== by 0x8FC2579: enet_host_create (host.c:38)
==4852== by 0x8DAC20E: ENetServer::Start(unsigned short, unsigned long) (enet_server.cc:417)
Where previously host->commands[0], 1, and 2 were used for the initial connect and still had reliableSequenceNumber set, 3 hadn't been used before and as such is uninitialised.
Enet used timeout algorithm is too simple, when use it on the Internet, disconnection often happen.
Possibly a harmless warning, but thought you should know:
compress.c(303): warning C4146: unary minus operator applied to unsigned type, result still unsigned
is it possible to use git tags to mark specific versions in the future ? That makes it easier for authors of bindings for other languages to diff two versions.
I fail to find a public API to obtain the size of the reliable outgoing packet queue.
Thanks
With our application using enet with win32, we were able to connect over LAN address, but we were unable to connect to the host when using internet IP address.
The ports are forwarded correctly, and putting break points / logging shows the packets are arriving.
However, the first packet that arrives is addressed with the router IP address, rather than the client peers address. Subsequent packets arrive with the correct IP address, just the first packet is addressed from the router.
This means that on the host, enet rejects all packets except for the first one.
Interestingly, on the host, all packets get sent to the routers IP, and they reach the destination without problem.
Removing the check on the host in protocol.c that checks the packets IP matches the peers IP resolves the issue, but obviously that check is useful for security.
The router is an ASUS RT-AC68U.
I don't think the router is behaving correctly by re-addressing the first packet to be from the router, but regardless, I think Enet should work even with strange behaviors on routers. It is also possible that a peer changes IP address during the connection for other reasons and I think Enet should be able to handle this.
I wanna use ENet to speed the file transfer between two hosts which have worse network connection (packet loss ratio over 5%).
I am disappointed by the performance, it is only 110KB/S, however 'scp' can be over 1024KB/S.
I do not think ENet fails to do such task, It must be my fault.
The following code is very simple:
I use 3 channels to finish the task:
In server side:
1)Ignite file sync by channel 0 (CONNECT event)
2) Send packet by channel 2 (Would send max 4 packets to speed the transfer and take into account of RECEIVE event delay issue)
3) Send finished message by channel 1
In client side:
1) Ignite file sync by channel 0 ( RECEIVE event)
2) Receive packet by channel 2 and send the received packet count by channel 0 , Server will consume the packet and reply file packet with channel 2.
3) Close file by channel 1 (RECEIVE event)
I found some RECEIVE interval of server could be very huge( over 10s).
Why? because such huge delay could degrade the file transfer speed.
The following is my example code:
Server.c
`#include <stdio.h>
static char file_buffer[256*1024];
int main (int argc, char *argv[])
{
ENetAddress address;
ENetHost *server;
ENetPacket *packet;
ENetEvent event;
char host_ip[32] = {0};
char peer_info[32] = {0};
char msg_notify[64] = {0};
int lastEvent = -1;
int enableDebug = 0;
FILE *fp = fopen(FILENAME, "rb");
if (!fp) {
fprintf(stderr, "Fail to open file.\n");
exit(0);
}
/* Initialize the ENet */
if (enet_initialize() != 0) {
fprintf(stderr, "An error (%s) occured while initializing ENet.\n", strerror(errno));
return EXIT_FAILURE;
}
atexit(enet_deinitialize);
/* Create the server */
address.host = ENET_HOST_ANY;
address.port = SHUTTLE_SERVER_PORT;
server = enet_host_create(&address, 64, 6, 0, 0);
if (server == NULL) {
fprintf(stderr, "An error (%s) occured while trying to create ENet server host.\n", strerror(errno));
exit(EXIT_FAILURE);
}
enet_uint32 time0 = 0, time1 = 0, time2 = 0;
uint64_t packet_size = 0;
uint64_t packet_count = 0;
int connected = 0;
int finished = 0;
printf("(Slice) Server is running.\n");
while (1) {
/* Event dispatcher: MUST not be hanged up. */
int eventStatus = enet_host_service(server, &event, 2);
if (eventStatus >= 0) {
switch (event.type) {
case ENET_EVENT_TYPE_NONE:
/* Silence huge repeated NONE events. */
if (lastEvent != ENET_EVENT_TYPE_NONE) {
if (enableDebug)
printf("(Slice) No event.\n");
}
break;
case ENET_EVENT_TYPE_CONNECT:
/* Store any relevant server information here. */
enet_address_get_host_ip(&event.peer->address, host_ip, sizeof(host_ip) - 1);
snprintf(peer_info, sizeof(peer_info), "[%s:%d]", host_ip, event.peer->address.port);
if (event.peer->data)
free(event.peer->data);
event.peer->data = malloc(strlen(peer_info) + 1);
if (event.peer->data)
strcpy(event.peer->data, peer_info);
snprintf(msg_notify, sizeof(msg_notify), "%s has connected to server", peer_info);
connected = 1;
finished = 0;
time0 = enet_time_get();
/* Ignite packet sync */
packet = enet_packet_create(msg_notify, strlen(msg_notify) + 1, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, 0, packet);
enet_host_flush(server);
printf("(Slice) Got a connection from peer: %s:%d.\n", host_ip, event.peer->address.port);
break;
case ENET_EVENT_TYPE_RECEIVE:
time1 = enet_time_get() - time0;
printf("(Slice) Time: %d, Channel: %d.\n", time1 - time2, event.channelID);
time2 = time1;
if (connected) {
int64_t received_count = atoi((char*)event.packet->data);
while (!finished && received_count + 4 > packet_count) {
int ret = fread(file_buffer, 1, sizeof(file_buffer), fp);
if (!ret) {
printf("(Slice) File sync has finished.\n");
if (received_count == packet_count) {
finished = 1;
snprintf(file_buffer, sizeof(file_buffer), "%d", 1);
packet = enet_packet_create(file_buffer, strlen(file_buffer) + 1, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, 1, packet);
enet_host_flush(server);
}
break;
}
packet_size += ret;
packet = enet_packet_create(file_buffer, ret, ENET_PACKET_FLAG_RELIABLE);
packet_count++;
enet_peer_send(event.peer, 2, packet);
enet_host_flush(server);
}
printf("(Slice) packet: received:%d, send: %d, speed: %dKB/S.\n",
(int)received_count, (int)packet_count, (int)(packet_size*1000/(time1 * 1024)));
}
/* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
/* A connected peer has either explicitly disconnected or timed out. */
if (event.peer->data) {
printf("(Slice) %s is disconnected.\n", (char*)event.peer->data);
free(event.peer->data);
} else {
enet_address_get_host_ip(&event.peer->address, host_ip, sizeof(host_ip) - 1);
snprintf(peer_info, sizeof(peer_info), "[%s:%d]", host_ip, event.peer->address.port);
printf("(Slice) Unknown (%s) connection is disconnected.\n", peer_info);
}
/* Reset the peer's information. */
event.peer->data = NULL;
enet_peer_reset(event.peer);
lastEvent = -1;
break;
default:
assert(0);
break;
}
lastEvent = event.type;
} else {
fprintf(stderr, "(Slice) Something went wrong: %d.\n", eventStatus);
lastEvent = -1;
}
}
enet_host_flush(server);
fclose(fp);
enet_host_destroy(server);
printf("Server is terminated.\n");
return 0;
}
`
Clinet.c
`#include <stdio.h>
typedef struct ChatContext {
ENetHost *client;
ENetPeer *peer;
volatile int connected;
volatile int terminated;
} ChatContext;
int main (int argc, char *argv[])
{
ENetAddress address;
ENetEvent event;
ChatContext cc, *pcc = &cc;
char host_ip[32] = {0};
char peer_info[32] = {0};
int lastEvent = -1;
int enableDebug = 0;
int trycount = 0;
int ret;
memset(pcc, 0, sizeof(*pcc));
/* Initialize the ENet */
if (enet_initialize() != 0) {
fprintf(stderr, "An error (%s) occured while initializing ENet.\n", strerror(errno));
return EXIT_FAILURE;
}
atexit(enet_deinitialize);
/* Create the client host */
pcc->client = enet_host_create(NULL, 64, 6, 0, 0);
if (pcc->client == NULL) {
fprintf(stderr, "An error (%s) occured while trying to create an ENet client host.\n", strerror(errno));
exit(EXIT_FAILURE);
}
/* Connect to the server */
enet_address_set_host(&address, SHUTTLE_SERVER_HOST);
address.port = SHUTTLE_SERVER_PORT;
pcc->peer = enet_host_connect(pcc->client, &address, 6, 0);
if (pcc->peer == NULL) {
fprintf(stderr, "No available peers for initializing an ENet connection.\n");
exit(EXIT_FAILURE);
}
do {
trycount++;
printf("(Peer) Try to connect to server: the %dth tryouts.\n", trycount);
if (enet_host_service(pcc->client, &event, 1000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
/* We can send packet to server only after we have received ENET_EVENT_TYPE_CONNECT */
pcc->connected = 1;
enet_address_get_host_ip(&event.peer->address, host_ip, sizeof(host_ip) - 1);
snprintf(peer_info, sizeof(peer_info), "[%s:%d]", host_ip, event.peer->address.port);
if (event.peer->data)
free(event.peer->data);
event.peer->data = malloc(strlen(peer_info) + 1);
if (event.peer->data)
strcpy(event.peer->data, peer_info);
printf("(Peer) Connected to server (%s:%d).\n", host_ip, event.peer->address.port);
}
} while (trycount < 4 && !pcc->connected);
if (!pcc->connected) {
fprintf(stderr, "Fail to connect to server.\n");
enet_peer_reset(pcc->peer);
enet_host_destroy(pcc->client);
exit(EXIT_FAILURE);
}
FILE *fp = fopen("/mnt/sdc/tmp/file_sync.bin", "wb");
if (!fp) {
fprintf(stderr, "Fail to write file.\n");
exit(0);
}
enet_uint32 time0 = 0, time1 = 0, time2 = 0;
int64_t packet_size = 0;
int64_t packet_count = 0;
char packet_info[32] = {0};
while (1) {
/* Event dispatcher: MUST not be hanged up */
int eventStatus = enet_host_service(pcc->client, &event, 2);
if (eventStatus >= 0) {
switch (event.type) {
case ENET_EVENT_TYPE_NONE:
/* Silence huge repeated NONE events */
if (lastEvent != ENET_EVENT_TYPE_NONE) {
if (enableDebug)
printf("(Peer) No event.\n");
}
break;
case ENET_EVENT_TYPE_CONNECT:
/* Store any relevant client information here. */
pcc->connected = 1;
enet_address_get_host_ip(&event.peer->address, host_ip, sizeof(host_ip) - 1);
snprintf(peer_info, sizeof(peer_info), "[%s:%d]", host_ip, event.peer->address.port);
if (event.peer->data)
free(event.peer->data);
event.peer->data = malloc(strlen(peer_info));
if (event.peer->data)
strcpy(event.peer->data, peer_info);
printf("(Peer) Connected to server (%s:%d).\n", host_ip, event.peer->address.port);
break;
case ENET_EVENT_TYPE_RECEIVE:
if (time0 != 0) {
time1 = enet_time_get() - time0;
printf("(Peer) Time: %d, Channel: %d.\n", time1 - time2, event.channelID);
time2 = time1;
}
if (event.channelID == 0) {
/* Ignite packet sync */
packet_count = 0;
snprintf(packet_info, sizeof(packet_info), "%d", (int)packet_count);
ENetPacket *packet = enet_packet_create(packet_info, strlen(packet_info) + 1, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, 0, packet);
enet_host_flush(pcc->client);
time0 = enet_time_get();
}
else if (event.channelID == 2) {
packet_count++;
time1 = enet_time_get() - time0;
packet_size += event.packet->dataLength;
if (fp) {
printf("(Peer) channelID:%d, len:%ld.\n", event.channelID, event.packet->dataLength);
fwrite(event.packet->data, 1, event.packet->dataLength, fp);
}
printf("(Peer) Receive speed: %d KB/S.\n", (int)(packet_size*1000/(time1*1024)));
snprintf(packet_info, sizeof(packet_info), "%d", (int)packet_count);
ENetPacket *packet = enet_packet_create(packet_info, strlen(packet_info) + 1, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(event.peer, 0, packet);
enet_host_flush(pcc->client);
} else if (event.channelID == 1) {
if (fp) {
fclose(fp);
fp = 0;
}
}
else
printf("(Peer) Got a chat message: %s.\n", (char*)event.packet->data);
/* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
/* A connected peer has either explicitly disconnected or timed out. */
printf("(Peer) Connection status: %d.\n", pcc->connected);
if (event.peer->data) {
printf("(Peer) %s is disconnected.\n", (char*)event.peer->data);
free(event.peer->data);
} else {
/* We fail to receive CONNECT event becasue the server is down. */
enet_address_get_host_ip(&event.peer->address, host_ip, sizeof(host_ip) - 1);
snprintf(peer_info, sizeof(peer_info), "[%s:%d]", host_ip, event.peer->address.port);
printf("(Peer) Unknown (%s) connection is disconnected.\n", peer_info);
}
/* Reset the peer's information. */
event.peer->data = NULL;
pcc->connected = 0;
lastEvent = -1;
enet_peer_reset(event.peer);
/* Reconnect the server */
pcc->peer = enet_host_connect(pcc->client, &address, 6, 0);
if (pcc->peer == NULL) {
fprintf(stderr, "No available peers for initializing an ENet connection.\n");
enet_host_destroy(pcc->client);
ret = EXIT_FAILURE;
goto cleanup_pos;
}
break;
default:
assert(0);
break;
}
lastEvent = event.type;
} else {
fprintf(stderr, "(Peer) Something went wrong: %d.\n", eventStatus);
lastEvent = -1;
pcc->connected = 0;
enet_peer_reset(pcc->peer);
ret = eventStatus;
goto cleanup_pos;
}
}
ret = 0;
cleanup_pos:
if (fp)
fclose(fp);
pcc->terminated = 1;
enet_host_destroy(pcc->client);
printf("Client is terminated.\n");
return ret;
}
`
After I switched previous ENet version (1.3.9) to the latest version of ENet (1.3.10) I get an error when I try to compile it as a DLL.
...\external\enet\host.c | 102 | error: 'ENetHost' has no member named 'duplicatePeers'
Used softwares:
Code::Blocks 12.11, Mingw GCC 4.8.1
As the title says, I have tried compiling and using enet in my side project, but it was throwing linker stage errors, so I looked into code and found that in win32.c where the code calls time* functions never actually includes the headers for windows.h and winmm.h
I made a quick fix, and would make a pull-request or whatever, if I knew how...
Please add an option to link Enet as a shared library. It would greatly help my use case (loading Enet with LuaJIT's FFI, which only loads shared libraries)
I am developing an application that stream archive files from user file system .Can I use this library for this purpose .the video file size ~500mb
Would you be willing to have enet.h
split into, lets say enet.h
and enet_internal.h
, with former only containing the ENET_API
routines (and the types needed for those routines), and the latter containing everything else?
I am making Haskell bindings right now, and its somewhat cumbersome that the internal and external interfaces are all jumbled together in one header file. I imagine that would anyone writing bindings. I could submit a pull request with the split if you'd like, too.
In various cases I want to want to send a message over an ENetHost or destroy it while another thread is waiting in enet_host_service. Currently this requires waiting for the timeout to expire, which is a waste of time and requires setting a low timeout, which wastes CPU. It would be better to provide a way to abort it, such as having a local pipe/socket that is also selected on.
After I received ENET_EVENT_TYPE_CONNECT from server, How can I find my outgoing connection's IP: PORT?
Thanks
anybody has some ideas?
We have a function to send packets to individual peer's and a function to broadcast a packet to all peer's however we need a function to broadcast a packet to all peers except for a specified peer or peer's
Something like enet_peer_send_omit() which accepts a peer or vector of peer's which will NOT receive the packet.
Hi,
would it be possible to rename the time.h header to something, that does not conflict with the ISO-C time.h (e.g., enet_time.h)?
I just hunted compiler-errors for half an hour, simply because the enet time.h was included instead of the system header file...
best reagrds,
Gabriel
I encountered a possible memory leak. Here is a short outline of an extreme case:
ENet is extremely fast and efficient all though bandwidth is always the main bottleneck of any networking application. Why not allow it to handle even more data with extremely fast and efficient compression like LZ4?
We could implement this ourselves and compress the data going into the packet at the top level, however since ENet fragments packets over a certain threshold, it would only make sense to add compression into that aspect of the library for the best possible outcome.
it's must be a bug:
when enet call 'enet_protocol_receive_incoming_commands' in routine ' enet_host_serive', if it received disconnect command(ENET_PROTOCOL_COMMAND_DISCONNECT), in the handler 'enet_protocol_handle_disconnect' , enet would reset all of queues of the ENetPeer, and also changed the peer's status from ENET_PEER_STATE_CONNECTED to ENET_PEER_STATE_ZOMBIE! and some commands that was in peer's dispatchedCommands, queues, would be discarded forever!
and then in 'enet_protocol_dispatch_incoming_commands' , enet would just fire the disconnect event according to peer's status(ENET_PEER_STATE_ZOMBIE),
anybody found this ?
Your MSVC checks in protocol.h look like a typo, you are checking for MSC_VER, but it should be _MSC_VER.
https://github.com/lsalzman/enet/blob/master/include/enet/protocol.h#L57
https://github.com/lsalzman/enet/blob/master/include/enet/protocol.h#L194
In win32.h it appears to be correct:
https://github.com/lsalzman/enet/blob/master/include/enet/win32.h#L8
IOS ENetPeer.roundTripTime always 1
Compiling on Visual Studio 2013 outputs the following compiler errors:
src\enet\win32.c(67): error C4996: 'gethostbyname': Use getaddrinfo() or GetAddrInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
src\enet\win32.c(71): error C4996: 'inet_addr': Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
src\enet\win32.c(86): error C4996: 'inet_ntoa': Use inet_ntop() or InetNtop() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
src\enet\win32.c(107): error C4996: 'gethostbyaddr': Use getnameinfo() or GetNameInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
I of course can define that preprocessor macro, but I wanted to make sure you were aware depreciated function calls were being used.
The maximum value ENet can take for ENET_PROTOCOL_MAXIMUM_PEER_ID appears to be the default of 0xFFF, enforcing a maximum concurrent value of 4096 users, despite this field being a UINT 16 with a theoretical maximum of 65536. This is probably related to the fact the field is reused to store some header flags, ENET_PROTOCOL_HEADER_FLAG_SENT_TIME on bit 16 and ENET_PROTOCOL_HEADER_FLAG_COMPRESSED on bit 15. But this still leaves us with 14 bits, although for some reason it doesn't work with 2^14 bytes either, only with 2^12, so I'm thinking it also has anything to do with ENET_PROTOCOL_HEADER_SESSION_SHIFT which is set to 12.
A little guidance would be appreciated about how to go about increasing the limit, I could tinker myself and figure it out but I'm scared of introducing any potential security exploits.
Once it's done, is there any possibility a patch that uses a 32-bit peer id could be incorporated? There could be a define MASS_PEERS_MODE that allows you to have more peers.
Nowadays a single server can easily take tens of thousands of clients, so I think this limitation is a big problem.
Please add the toolchain requirements to the projects readme.md, otherwise it might be difficult to detect compilation errors (m4 is a bit cryptic on that).
The depencies on Ubuntu 14.04 are:
something simple like void enet_host_userdata(ENetHost *host, char *data, size_t dataLength)
where the userdata would be sent back (with some rate limits I guess) to anyone who is not connected and sends a magic packet to the host. If the data is too big there could be an initial first header packet that would contain size info.
Usages would be retrieving list of current players on a server and other server parameters.
$ make
C:/Devel/MinGW/msys/1.0/bin/sh.exe ./libtool --tag=CC --mode=compile gcc -DPAC
KAGE_NAME="libenet" -DPACKAGE_TARNAME="libenet" -DPACKAGE_VERSION="1.3.4"
-DPACKAGE_STRING="libenet\ 1.3.4" -DPACKAGE_BUGREPORT="" -DPACKAGE_URL=""
-DPACKAGE="libenet" -DVERSION="1.3.4" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1
-DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE
_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DLT_OBJDIR
=".libs/" -I. -I./include -g -O2 -MT callbacks.lo -MD -MP -MF .deps/callbac
ks.Tpo -c -o callbacks.lo callbacks.c
Xcallbacks.Tpo -c -o callbacks.lo callbacks.lo
libtool: compile: warning: libobj name callbacks.Tpo -c -o callbacks.lo callbac ks.lo' may not contain shell special characters. rm: invalid option -- c Try
rm --help' for more information.
libtool: compile: gcc "-DPACKAGE_NAME=\libenet" -DPACKAGE_TARNAME="libenet"
-DPACKAGE_VERSION="1.3.4" -DPACKAGE_STRING=\libenet 1.3.4"" "-DPACKAGE_BUGR
EPORT=\" -DPACKAGE_URL="" -DPACKAGE="libenet" -DVERSION="1.3.4" -DSTDC_H
EADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRIN
G_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1
-DHAVE_UNISTD_H=1 -DLT_OBJDIR=".libs/" -I. -I./include -g -O2 -MT callbacks.l
o -MD -MP -MF .deps/callbacks.Tpo -c -o callbacks.lo callbacks.c" -DDLL_EXPORT
-DPIC -o .libs/callbacks.Tpo -c -o callbacks.lo callbacks.o
gcc.exe: error: callbacks.o: No such file or directory
gcc.exe: fatal error: no input files
compilation terminated.
make: *** [callbacks.lo] Error 1
Per the documentation:
as long as the application guards access to [ENetHost], then ENet should operate fine in a multi-threaded environment.
The problem is accessing the peer
field of ENetEvent
actually boils down to accessing ENetHost
.
Consider this:
Thread 1
while(enet_host_service(host, &event, ...) >= 0)
{
events.enqueue(event);
}
Thread 2
auto event = events.dequeue();
/* process event... */
enet_peer_send(event.peer, ...);
Now, under contention on the peers
, it can happen that Thread 2 will not send to the right peer.
By the time Thread 2 calls enet_peer_send
, enet_host_service
may have recycled the peer
for a different client, and Thread 2 will be none the wiser and happily send to the wrongful client.
Now maybe this is a wrongful usage, but the docs never warn about it.
Maybe I missed something in the library that handles however :)
... in case the buffer has the same size or less than the resulting hostname.
Consider the following code:
#include <enet/enet.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
ENetAddress addr = { htonl(1043283462), 0 }; /* 62.47.62.6 */
const char *hostname = "62-47-62-6.adsl.highway.telekom.at";
size_t len = strlen(hostname);
char *buf = malloc(len);
if (enet_address_get_host(&addr, buf, len) == 0)
{
if (memcmp(buf, hostname, len))
abort();
if (buf[len-1] != '\0')
printf("not null terminated\n");
}
return 0;
}
$ cc enet.c -lenet && ./a.out
not null terminated
While the documentation cleary states null terminated.
From what I understand currently one can only control memory alloc/free via two functions at startup, and also specify if the buffers passed to the packet creation for sending are owned by the application and thus shouldn't be freed on packet destruction.
While this allows some control I suggest this would be much improved if at startup the following user specified alloc/free callback functions could be passed in:
I'm not sure on the allocation behaviour of the range encoder right now, and how it would fit into this scheme.
It's the potential memory fragmentation from (3) I am most concerned about as ideally it needs a different kind of allocator behaviour. For that case I would like to hook in a custom allocator that can use to it's advantage frame based behaviour of a game - where individual blocks don't need to be freed, but instead rolling frame based ranges can be tracked, and wiped clean efficiently assuming normal operation. But I can't do this if all of enets allocations are done through the same callbacks as (1) & (2) for example.
I'm making an extension(dll) for game maker.
But if i use precompiled lib file in enet 1.3.13 make next error.
main.obj : error LNK2019: unresolved external symbol enet_initialize referenced in function gmenet_initialize
So i decide to compile lib file and work with it.
precompiled lib has 50kb and mine has 623kb.
I'm using VS 2017 and v141 toolset.
Very minor detail: there is no need for list.c to include enet/enet.h when enet/list.h is enough.
It should be a struct timeval, but is specified as an int.
When opening a connection using enet_host_connect(), a single packet is sent. If it's lost, the connection will fail. This seems a bit strange, and only happens in this case (the receiving end will retry sending its reply).
packet 1 ---> only sent once
<--- packet 2 sent several times as necessary
packet 3 ---> sent several times as necessary
We are developing a server-client application where the download bandwidth of the server is severely throttled, but not the upload. As a result of this, if we use enet_host_connect() to connect the client to the server, it either never succeeds or takes a long time. However, the client IPs are fixed and known beforehand. Is there a way to have the server pre-poulate its peer data structure without using enet_host_connect()? That way, the server can broadcast the information to all its clients without needing to wait to receive a connect event from the client.
Does enet has some performance index?
It would be nice if there were github release tags, at least for the most recent version. As is, I'm not sure which commit corresponds to v1.3.13
Last version from git compile but can't be used because linking error :
Error 1 error LNK2001: unresolved external symbol _enet_peer_notify_disconnect enet.lib(peer.obj)
It's due cause :
1>peer.c(549): warning C4013: 'enet_peer_notify_disconnect' undefined; assuming extern returning int
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.