login

<     >

2023-11-09 18:02:59 (UTC-03:00)

Marcel Rodrigues <marcelgmr@gmail.com>

add basic ENet support

diff --git a/lib/arco.lua b/lib/arco.lua
index 60b1491..8d2522e 100644
--- a/lib/arco.lua
+++ b/lib/arco.lua
@@ -1,3 +1,4 @@
 local arco = {}
 arco.sdl      = require "arco.sdl2"
+arco.net      = require "arco.enet"
 return arco

diff --git a/lib/arco/cdef_enet.h b/lib/arco/cdef_enet.h
new file mode 100644
index 0000000..430efd7
--- /dev/null
+++ b/lib/arco/cdef_enet.h
@@ -0,0 +1,292 @@
+/* API defs from enet enet 1.3.17 */
+
+typedef uint8_t enet_uint8;
+typedef uint16_t enet_uint16;
+typedef uint32_t enet_uint32;
+typedef enet_uint32 ENetVersion;
+typedef struct _ENetAddress
+{
+   enet_uint32 host;
+   enet_uint16 port;
+} ENetAddress;
+typedef struct ENetHost ENetHost;
+/*
+typedef struct _ENetHost
+{
+   ENetSocket           socket;
+   ENetAddress          address;
+   enet_uint32          incomingBandwidth;
+   enet_uint32          outgoingBandwidth;
+   enet_uint32          bandwidthThrottleEpoch;
+   enet_uint32          mtu;
+   enet_uint32          randomSeed;
+   int                  recalculateBandwidthLimits;
+   ENetPeer *           peers;
+   size_t               peerCount;
+   size_t               channelLimit;
+   enet_uint32          serviceTime;
+   ENetList             dispatchQueue;
+   int                  continueSending;
+   size_t               packetSize;
+   enet_uint16          headerFlags;
+   ENetProtocol         commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS];
+   size_t               commandCount;
+   ENetBuffer           buffers [ENET_BUFFER_MAXIMUM];
+   size_t               bufferCount;
+   ENetChecksumCallback checksum;
+   ENetCompressor       compressor;
+   enet_uint8           packetData [2][ENET_PROTOCOL_MAXIMUM_MTU];
+   ENetAddress          receivedAddress;
+   enet_uint8 *         receivedData;
+   size_t               receivedDataLength;
+   enet_uint32          totalSentData;
+   enet_uint32          totalSentPackets;
+   enet_uint32          totalReceivedData;
+   enet_uint32          totalReceivedPackets;
+   ENetInterceptCallback intercept;
+   size_t               connectedPeers;
+   size_t               bandwidthLimitedPeers;
+   size_t               duplicatePeers;
+   size_t               maximumPacketSize;
+   size_t               maximumWaitingData;
+} ENetHost;
+*/
+typedef struct _ENetListNode
+{
+   struct _ENetListNode * next;
+   struct _ENetListNode * previous;
+} ENetListNode;
+typedef ENetListNode * ENetListIterator;
+typedef struct _ENetList
+{
+   ENetListNode sentinel;
+} ENetList;
+typedef enum _ENetPeerState
+{
+   ENET_PEER_STATE_DISCONNECTED                = 0,
+   ENET_PEER_STATE_CONNECTING                  = 1,
+   ENET_PEER_STATE_ACKNOWLEDGING_CONNECT       = 2,
+   ENET_PEER_STATE_CONNECTION_PENDING          = 3,
+   ENET_PEER_STATE_CONNECTION_SUCCEEDED        = 4,
+   ENET_PEER_STATE_CONNECTED                   = 5,
+   ENET_PEER_STATE_DISCONNECT_LATER            = 6,
+   ENET_PEER_STATE_DISCONNECTING               = 7,
+   ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT    = 8,
+   ENET_PEER_STATE_ZOMBIE                      = 9 
+} ENetPeerState;
+enum
+{
+   ENET_HOST_RECEIVE_BUFFER_SIZE          = 256 * 1024,
+   ENET_HOST_SEND_BUFFER_SIZE             = 256 * 1024,
+   ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL  = 1000,
+   ENET_HOST_DEFAULT_MTU                  = 1400,
+   ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE  = 32 * 1024 * 1024,
+   ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024,
+
+   ENET_PEER_DEFAULT_ROUND_TRIP_TIME      = 500,
+   ENET_PEER_DEFAULT_PACKET_THROTTLE      = 32,
+   ENET_PEER_PACKET_THROTTLE_SCALE        = 32,
+   ENET_PEER_PACKET_THROTTLE_COUNTER      = 7, 
+   ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2,
+   ENET_PEER_PACKET_THROTTLE_DECELERATION = 2,
+   ENET_PEER_PACKET_THROTTLE_INTERVAL     = 5000,
+   ENET_PEER_PACKET_LOSS_SCALE            = (1 << 16),
+   ENET_PEER_PACKET_LOSS_INTERVAL         = 10000,
+   ENET_PEER_WINDOW_SIZE_SCALE            = 64 * 1024,
+   ENET_PEER_TIMEOUT_LIMIT                = 32,
+   ENET_PEER_TIMEOUT_MINIMUM              = 5000,
+   ENET_PEER_TIMEOUT_MAXIMUM              = 30000,
+   ENET_PEER_PING_INTERVAL                = 500,
+   ENET_PEER_UNSEQUENCED_WINDOWS          = 64,
+   ENET_PEER_UNSEQUENCED_WINDOW_SIZE      = 1024,
+   ENET_PEER_FREE_UNSEQUENCED_WINDOWS     = 32,
+   ENET_PEER_RELIABLE_WINDOWS             = 16,
+   ENET_PEER_RELIABLE_WINDOW_SIZE         = 0x1000,
+   ENET_PEER_FREE_RELIABLE_WINDOWS        = 8
+};
+typedef struct _ENetChannel
+{
+   enet_uint16  outgoingReliableSequenceNumber;
+   enet_uint16  outgoingUnreliableSequenceNumber;
+   enet_uint16  usedReliableWindows;
+   enet_uint16  reliableWindows [ENET_PEER_RELIABLE_WINDOWS];
+   enet_uint16  incomingReliableSequenceNumber;
+   enet_uint16  incomingUnreliableSequenceNumber;
+   ENetList     incomingReliableCommands;
+   ENetList     incomingUnreliableCommands;
+} ENetChannel;
+typedef struct _ENetPeer
+{ 
+   ENetListNode  dispatchList;
+   ENetHost * host;
+   enet_uint16   outgoingPeerID;
+   enet_uint16   incomingPeerID;
+   enet_uint32   connectID;
+   enet_uint8    outgoingSessionID;
+   enet_uint8    incomingSessionID;
+   ENetAddress   address;
+   void *        data;
+   ENetPeerState state;
+   ENetChannel * channels;
+   size_t        channelCount;
+   enet_uint32   incomingBandwidth;
+   enet_uint32   outgoingBandwidth;
+   enet_uint32   incomingBandwidthThrottleEpoch;
+   enet_uint32   outgoingBandwidthThrottleEpoch;
+   enet_uint32   incomingDataTotal;
+   enet_uint32   outgoingDataTotal;
+   enet_uint32   lastSendTime;
+   enet_uint32   lastReceiveTime;
+   enet_uint32   nextTimeout;
+   enet_uint32   earliestTimeout;
+   enet_uint32   packetLossEpoch;
+   enet_uint32   packetsSent;
+   enet_uint32   packetsLost;
+   enet_uint32   packetLoss;
+   enet_uint32   packetLossVariance;
+   enet_uint32   packetThrottle;
+   enet_uint32   packetThrottleLimit;
+   enet_uint32   packetThrottleCounter;
+   enet_uint32   packetThrottleEpoch;
+   enet_uint32   packetThrottleAcceleration;
+   enet_uint32   packetThrottleDeceleration;
+   enet_uint32   packetThrottleInterval;
+   enet_uint32   pingInterval;
+   enet_uint32   timeoutLimit;
+   enet_uint32   timeoutMinimum;
+   enet_uint32   timeoutMaximum;
+   enet_uint32   lastRoundTripTime;
+   enet_uint32   lowestRoundTripTime;
+   enet_uint32   lastRoundTripTimeVariance;
+   enet_uint32   highestRoundTripTimeVariance;
+   enet_uint32   roundTripTime;
+   enet_uint32   roundTripTimeVariance;
+   enet_uint32   mtu;
+   enet_uint32   windowSize;
+   enet_uint32   reliableDataInTransit;
+   enet_uint16   outgoingReliableSequenceNumber;
+   ENetList      acknowledgements;
+   ENetList      sentReliableCommands;
+   ENetList      sentUnreliableCommands;
+   ENetList      outgoingCommands;
+   ENetList      dispatchedCommands;
+   enet_uint16   flags;
+   enet_uint16   reserved;
+   enet_uint16   incomingUnsequencedGroup;
+   enet_uint16   outgoingUnsequencedGroup;
+   enet_uint32   unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; 
+   enet_uint32   eventData;
+   size_t        totalWaitingData;
+} ENetPeer;
+typedef enum _ENetEventType
+{
+   ENET_EVENT_TYPE_NONE       = 0,  
+   ENET_EVENT_TYPE_CONNECT    = 1,  
+   ENET_EVENT_TYPE_DISCONNECT = 2,  
+   ENET_EVENT_TYPE_RECEIVE    = 3
+} ENetEventType;
+typedef struct _ENetPacket
+{
+   size_t                   referenceCount;
+   enet_uint32              flags;
+   enet_uint8 *             data;
+   size_t                   dataLength;
+   ENetPacketFreeCallback   freeCallback;
+   void *                   userData;
+} ENetPacket;
+typedef struct _ENetEvent 
+{
+   ENetEventType        type;
+   ENetPeer *           peer;
+   enet_uint8           channelID;
+   enet_uint32          data;
+   ENetPacket *         packet;
+} ENetEvent;
+
+typedef enum _ENetSocketType
+{
+   ENET_SOCKET_TYPE_STREAM   = 1,
+   ENET_SOCKET_TYPE_DATAGRAM = 2
+} ENetSocketType;
+typedef enum _ENetSocketOption
+{
+   ENET_SOCKOPT_NONBLOCK  = 1,
+   ENET_SOCKOPT_BROADCAST = 2,
+   ENET_SOCKOPT_RCVBUF    = 3,
+   ENET_SOCKOPT_SNDBUF    = 4,
+   ENET_SOCKOPT_REUSEADDR = 5,
+   ENET_SOCKOPT_RCVTIMEO  = 6,
+   ENET_SOCKOPT_SNDTIMEO  = 7,
+   ENET_SOCKOPT_ERROR     = 8,
+   ENET_SOCKOPT_NODELAY   = 9
+} ENetSocketOption;
+typedef enum _ENetSocketShutdown
+{
+    ENET_SOCKET_SHUTDOWN_READ       = 0,
+    ENET_SOCKET_SHUTDOWN_WRITE      = 1,
+    ENET_SOCKET_SHUTDOWN_READ_WRITE = 2
+} ENetSocketShutdown;
+
+int enet_initialize (void);
+int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits);
+void enet_deinitialize (void);
+ENetVersion enet_linked_version (void);
+
+enet_uint32 enet_time_get (void);
+void enet_time_set (enet_uint32);
+
+ENetSocket enet_socket_create (ENetSocketType);
+int        enet_socket_bind (ENetSocket, const ENetAddress *);
+int        enet_socket_get_address (ENetSocket, ENetAddress *);
+int        enet_socket_listen (ENetSocket, int);
+ENetSocket enet_socket_accept (ENetSocket, ENetAddress *);
+int        enet_socket_connect (ENetSocket, const ENetAddress *);
+int        enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t);
+int        enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t);
+int        enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32);
+int        enet_socket_set_option (ENetSocket, ENetSocketOption, int);
+int        enet_socket_get_option (ENetSocket, ENetSocketOption, int *);
+int        enet_socket_shutdown (ENetSocket, ENetSocketShutdown);
+void       enet_socket_destroy (ENetSocket);
+/* FIXME: ENetSocketSet is fd_set which is platform-dependent (see unix.h vs win32.h)
+          We only need pointers so let's give a stub definition for now */
+typedef struct ENetSocketSet ENetSocketSet;
+int        enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32);
+
+int enet_address_set_host_ip (ENetAddress * address, const char * hostName);
+int enet_address_set_host (ENetAddress * address, const char * hostName);
+int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength);
+int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength);
+
+ENetPacket * enet_packet_create (const void *, size_t, enet_uint32);
+void         enet_packet_destroy (ENetPacket *);
+int          enet_packet_resize  (ENetPacket *, size_t);
+enet_uint32  enet_crc32 (const ENetBuffer *, size_t);
+                
+ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32);
+void       enet_host_destroy (ENetHost *);
+ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32);
+int        enet_host_check_events (ENetHost *, ENetEvent *);
+int        enet_host_service (ENetHost *, ENetEvent *, enet_uint32);
+void       enet_host_flush (ENetHost *);
+void       enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *);
+void       enet_host_compress (ENetHost *, const ENetCompressor *);
+int        enet_host_compress_with_range_coder (ENetHost * host);
+void       enet_host_channel_limit (ENetHost *, size_t);
+void       enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32);
+
+int                 enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *);
+ENetPacket *        enet_peer_receive (ENetPeer *, enet_uint8 * channelID);
+void                enet_peer_ping (ENetPeer *);
+void                enet_peer_ping_interval (ENetPeer *, enet_uint32);
+void                enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
+void                enet_peer_reset (ENetPeer *);
+void                enet_peer_disconnect (ENetPeer *, enet_uint32);
+void                enet_peer_disconnect_now (ENetPeer *, enet_uint32);
+void                enet_peer_disconnect_later (ENetPeer *, enet_uint32);
+void                enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
+
+void * enet_range_coder_create (void);
+void   enet_range_coder_destroy (void *);
+size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t);
+size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t);

diff --git a/lib/arco/enet.lua b/lib/arco/enet.lua
new file mode 100644
index 0000000..1b0fa43
--- /dev/null
+++ b/lib/arco/enet.lua
@@ -0,0 +1,62 @@
+local ffi = require "ffi"
+
+cdefs_callbacks = [[
+struct _ENetPacket;
+typedef void (__cdecl * ENetPacketFreeCallback) (struct _ENetPacket *);
+typedef struct _ENetCallbacks
+{
+    void * (__cdecl * malloc) (size_t size);
+    void (__cdecl * free) (void * memory);
+    void (__cdecl * no_memory) (void);
+} ENetCallbacks;
+typedef struct _ENetCompressor
+{
+   void * context;
+   size_t (__cdecl * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, uint8_t * outData, size_t outLimit);
+   size_t (__cdecl * decompress) (void * context, const uint8_t * inData, size_t inLimit, uint8_t * outData, size_t outLimit);
+   void (__cdecl * destroy) (void * context);
+} ENetCompressor;
+]]
+if ffi.os == "Windows" then
+    ffi.cdef[[
+    typedef SOCKET ENetSocket;
+    typedef struct
+    {
+        size_t dataLength;
+        void * data;
+    } ENetBuffer;
+    ]]
+else
+    ffi.cdef[[
+    typedef int ENetSocket;
+    typedef struct
+    {
+        void * data;
+        size_t dataLength;
+    } ENetBuffer;
+    ]]
+    cdefs_callbacks = cdefs_callbacks:gsub("__cdecl", "")
+end
+ffi.cdef(cdefs_callbacks)
+
+local here = debug.getinfo(1).source:match("@?(.*/)") or ""
+local cdefs = io.open(here.."cdef_enet.h", "r"):read("*a")
+ffi.cdef(cdefs)
+
+local enet = ffi.load("enet")
+
+local consts = {
+    ENET_HOST_ANY = 0,
+    ENET_HOST_BROADCAST = 0xFFFFFFFF,
+    ENET_PORT_ANY = 0,
+}
+
+return setmetatable(consts, {
+    __index = function (t, k)
+        local ok, obj = pcall(function () return enet["enet_"..k] end)
+        if not ok then
+            obj = enet[k]
+        end
+        return obj
+    end
+})