Git Product home page Git Product logo

enet's Introduction

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


enet's People

Contributors

arvid-norlander avatar croydon avatar cuppajoeman avatar cxong avatar daichifukui avatar jonnyptn avatar jroweboy avatar lsalzman avatar metaquarx avatar seragh avatar skyfloogle avatar stephanecharette avatar subv avatar vincenz099 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

enet's Issues

Compiler warning in Visual Studio

Possibly a harmless warning, but thought you should know:

compress.c(303): warning C4146: unary minus operator applied to unsigned type, result still unsigned

Internal Compression

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?

http://code.google.com/p/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.

No retry for connect packets

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

ENetCompressor Tutorial

@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.

Possible memory leak

I encountered a possible memory leak. Here is a short outline of an extreme case:

  • 2000 clients connected to a host
  • All clients disconnect using enet_peer_disconnect and then do enet_host_flush
  • If the clients now do not call enet_host_service or crash or the (physical) connection is lost for whatever reason, this results in about 1GB of extra memory usage (on the host). This memory is never freed up, even if the clients are later on disconnected by the host because of the missing ping.
  • On the otherhand, if the clients are disconnected by the host using enet_peer_disconnect, the problem does not exist. Same for the case that the clients call enet_host_service afterwards.
  • So I guess in this case its possible that the host keeps some data waiting for an Acknowledgement that never arrives and does not free this data even after disconnecting the client.

How to get file descriptor to poll.

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.

git tags for releases ?

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.

WP8 support

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!

Add shared library link option?

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)

Overzealous parenthesis

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) :)

Populating the client information without using enet_host_connect()

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.

Increasing ENET_PROTOCOL_MAXIMUM_PEER_ID beyond 4096

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.

Precompiled lib file make link error

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.

enet_address_get_host() (and possibly others) do not null terminate the buffer

... 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.

the client peer can not receive data

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.

is it a bug? enet discarded some command that were not dispatched in queue when it received disconnect command

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 ?

No way to abort enet_host_service

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.

win32.c lacks windows includes

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...

Memory allocation behaviour

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:

  1. setup_alloc()/setup_free() // for memory allocated during setup/shutdown
  2. session_alloc()/session_free() // for memory allocated during a any kind of play/connection session
  3. packet_alloc()/packet_free() // for memory continually allocated during communication (packets)

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.

Seperating Internal and External interface

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.

Issue in multi-thread with ENetEvent?

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 :)

Git Version[master] : Linking Error

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

VS2013 Compilation Error

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.

command header reliableSequenceNumber is uninitialized for acknowledgements

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 SIGPIPE error on iOS

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.

Enet File sync simulation: The performance (file transfer speed) is far worse than 'scp'

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>

include <errno.h>

include <string.h>

include <stdlib.h>

include <assert.h>

include <enet/enet.h>

include "config.h"

define FILENAME "/relay/100MB-tokyo.bin"

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>

include <errno.h>

include <string.h>

include <stdlib.h>

include <assert.h>

include <pthread.h>

include <enet/enet.h>

include "config.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;

}
`

Way to optimize host performance with a lot of peers and unlimited in&out bandwidth

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_peer_send_omit()

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.

Add support for DragonFly

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);

IP address change on peer causes messages to fail in 1 direction behind some routers

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.

error compiling with mingw32

$ 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 Tryrm --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

error: 'ENetHost' has no member named 'duplicatePeers'

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

Github release tag

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

time.h naming conflict

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

Provide consistent peer/host ID

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.

IPv6 support

There are currently 3 pull request concerning IPv6:

@lsalzman , can we get any info on what's the current status is? Will any of these ever get merged? What are your plans about IPv6 support?

ENetPeer.packetsSent resets after 21

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?

a way to send userdata to a non connected client

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.