From 36633a3bef0402b6d4354a7d7165c798562f3990 Mon Sep 17 00:00:00 2001 From: Melissa Geels Date: Sat, 1 Aug 2020 19:07:09 +0200 Subject: [PATCH] First progress --- Readme.md | 7 + address.go | 66 ++++ enet.go | 5 - enet/enet.lib | Bin 0 -> 52768 bytes enet/include/enet/callbacks.h | 27 ++ enet/include/enet/enet.h | 614 ++++++++++++++++++++++++++++++++++ enet/include/enet/list.h | 43 +++ enet/include/enet/protocol.h | 198 +++++++++++ enet/include/enet/time.h | 18 + enet/include/enet/types.h | 13 + enet/include/enet/unix.h | 48 +++ enet/include/enet/utility.h | 13 + enet/include/enet/win32.h | 57 ++++ enetc.go | 17 + event.go | 60 ++++ host.go | 50 +++ peer.go | 19 ++ 17 files changed, 1250 insertions(+), 5 deletions(-) create mode 100644 Readme.md create mode 100644 address.go create mode 100644 enet/enet.lib create mode 100644 enet/include/enet/callbacks.h create mode 100644 enet/include/enet/enet.h create mode 100644 enet/include/enet/list.h create mode 100644 enet/include/enet/protocol.h create mode 100644 enet/include/enet/time.h create mode 100644 enet/include/enet/types.h create mode 100644 enet/include/enet/unix.h create mode 100644 enet/include/enet/utility.h create mode 100644 enet/include/enet/win32.h create mode 100644 enetc.go create mode 100644 event.go create mode 100644 host.go create mode 100644 peer.go diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..49fd411 --- /dev/null +++ b/Readme.md @@ -0,0 +1,7 @@ +# go-enet +Enet bindings for Go using cgo. + +## Installation +``` +$ go get github.com/codecat/go-enet +``` diff --git a/address.go b/address.go new file mode 100644 index 0000000..ad78f02 --- /dev/null +++ b/address.go @@ -0,0 +1,66 @@ +package enet + +import ( + "unsafe" +) + +// #include +import "C" + +// Address specifies a portable internet address structure. +type Address interface { + SetHostAny() + SetHost(ip string) + SetPort(port uint16) + + String() string +} + +type enetAddress struct { + cAddr C.struct__ENetAddress +} + +func (addr *enetAddress) SetHostAny() { + addr.cAddr.host = C.ENET_HOST_ANY +} + +func (addr *enetAddress) SetHost(hostname string) { + cHostname := C.CString(hostname) + C.enet_address_set_host( + &addr.cAddr, + cHostname, + ) + C.free(unsafe.Pointer(cHostname)) +} + +func (addr *enetAddress) SetPort(port uint16) { + addr.cAddr.port = (C.enet_uint16)(port) +} + +func (addr *enetAddress) String() string { + buffer := C.malloc(32) + C.enet_address_get_host_ip( + &addr.cAddr, + (*C.char)(buffer), + 32, + ) + ret := C.GoString((*C.char)(buffer)) + C.free(buffer) + return ret +} + +// NewAddress creates a new address +func NewAddress(ip string, port uint16) Address { + ret := enetAddress{} + ret.SetHost(ip) + ret.SetPort(port) + return &ret +} + +// NewListenAddress makes a new address ready for listening on ENET_HOST_ANY +func NewListenAddress(port uint16) Address { + ret := enetAddress{} + ret.SetHostAny() + ret.SetPort(port) + return &ret +} diff --git a/enet.go b/enet.go index 6dcc8fe..15045ba 100644 --- a/enet.go +++ b/enet.go @@ -1,6 +1 @@ package enet - -// Initialize enet. -func Initialize() { - // -} diff --git a/enet/enet.lib b/enet/enet.lib new file mode 100644 index 0000000000000000000000000000000000000000..602870621b734df2bb35899a998c2d3c7b18325f GIT binary patch literal 52768 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 literal 0 HcmV?d00001 diff --git a/enet/include/enet/callbacks.h b/enet/include/enet/callbacks.h new file mode 100644 index 0000000..340a4a9 --- /dev/null +++ b/enet/include/enet/callbacks.h @@ -0,0 +1,27 @@ +/** + @file callbacks.h + @brief ENet callbacks +*/ +#ifndef __ENET_CALLBACKS_H__ +#define __ENET_CALLBACKS_H__ + +#include + +typedef struct _ENetCallbacks +{ + void * (ENET_CALLBACK * malloc) (size_t size); + void (ENET_CALLBACK * free) (void * memory); + void (ENET_CALLBACK * no_memory) (void); +} ENetCallbacks; + +/** @defgroup callbacks ENet internal callbacks + @{ + @ingroup private +*/ +extern void * enet_malloc (size_t); +extern void enet_free (void *); + +/** @} */ + +#endif /* __ENET_CALLBACKS_H__ */ + diff --git a/enet/include/enet/enet.h b/enet/include/enet/enet.h new file mode 100644 index 0000000..54d91b5 --- /dev/null +++ b/enet/include/enet/enet.h @@ -0,0 +1,614 @@ +/** + @file enet.h + @brief ENet public header file +*/ +#ifndef __ENET_ENET_H__ +#define __ENET_ENET_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef _WIN32 +#include "enet/win32.h" +#else +#include "enet/unix.h" +#endif + +#include "enet/types.h" +#include "enet/protocol.h" +#include "enet/list.h" +#include "enet/callbacks.h" + +#define ENET_VERSION_MAJOR 1 +#define ENET_VERSION_MINOR 3 +#define ENET_VERSION_PATCH 15 +#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) +#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) +#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) +#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) +#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) + +typedef enet_uint32 ENetVersion; + +struct _ENetHost; +struct _ENetEvent; +struct _ENetPacket; + +typedef enum _ENetSocketType +{ + ENET_SOCKET_TYPE_STREAM = 1, + ENET_SOCKET_TYPE_DATAGRAM = 2 +} ENetSocketType; + +typedef enum _ENetSocketWait +{ + ENET_SOCKET_WAIT_NONE = 0, + ENET_SOCKET_WAIT_SEND = (1 << 0), + ENET_SOCKET_WAIT_RECEIVE = (1 << 1), + ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) +} ENetSocketWait; + +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; + +#define ENET_HOST_ANY 0 +#define ENET_HOST_BROADCAST 0xFFFFFFFFU +#define ENET_PORT_ANY 0 + +/** + * Portable internet address structure. + * + * The host must be specified in network byte-order, and the port must be in host + * byte-order. The constant ENET_HOST_ANY may be used to specify the default + * server host. The constant ENET_HOST_BROADCAST may be used to specify the + * broadcast address (255.255.255.255). This makes sense for enet_host_connect, + * but not for enet_host_create. Once a server responds to a broadcast, the + * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. + */ +typedef struct _ENetAddress +{ + enet_uint32 host; + enet_uint16 port; +} ENetAddress; + +/** + * Packet flag bit constants. + * + * The host must be specified in network byte-order, and the port must be in + * host byte-order. The constant ENET_HOST_ANY may be used to specify the + * default server host. + + @sa ENetPacket +*/ +typedef enum _ENetPacketFlag +{ + /** packet must be received by the target peer and resend attempts should be + * made until the packet is delivered */ + ENET_PACKET_FLAG_RELIABLE = (1 << 0), + /** packet will not be sequenced with other packets + * not supported for reliable packets + */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), + /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), + /** packet will be fragmented using unreliable (instead of reliable) sends + * if it exceeds the MTU */ + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), + + /** whether the packet has been sent from all queues it has been entered into */ + ENET_PACKET_FLAG_SENT = (1<<8) +} ENetPacketFlag; + +typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); + +/** + * ENet packet structure. + * + * An ENet data packet that may be sent to or received from a peer. The shown + * fields should only be read and never modified. The data field contains the + * allocated data for the packet. The dataLength fields specifies the length + * of the allocated data. The flags field is either 0 (specifying no flags), + * or a bitwise-or of any combination of the following flags: + * + * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer + * and resend attempts should be made until the packet is delivered + * + * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets + * (not supported for reliable packets) + * + * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead + * + * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable + * (instead of reliable) sends if it exceeds the MTU + * + * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into + @sa ENetPacketFlag + */ +typedef struct _ENetPacket +{ + size_t referenceCount; /**< internal use only */ + enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ + enet_uint8 * data; /**< allocated data for packet */ + size_t dataLength; /**< length of data */ + ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ + void * userData; /**< application private data, may be freely modified */ +} ENetPacket; + +typedef struct _ENetAcknowledgement +{ + ENetListNode acknowledgementList; + enet_uint32 sentTime; + ENetProtocol command; +} ENetAcknowledgement; + +typedef struct _ENetOutgoingCommand +{ + ENetListNode outgoingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + enet_uint32 sentTime; + enet_uint32 roundTripTimeout; + enet_uint32 roundTripTimeoutLimit; + enet_uint32 fragmentOffset; + enet_uint16 fragmentLength; + enet_uint16 sendAttempts; + ENetProtocol command; + ENetPacket * packet; +} ENetOutgoingCommand; + +typedef struct _ENetIncomingCommand +{ + ENetListNode incomingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + ENetProtocol command; + enet_uint32 fragmentCount; + enet_uint32 fragmentsRemaining; + enet_uint32 * fragments; + ENetPacket * packet; +} ENetIncomingCommand; + +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; + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +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 enum _ENetPeerFlag +{ + ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0) +} ENetPeerFlag; + +/** + * An ENet peer which data packets may be sent or received from. + * + * No fields should be modified unless otherwise specified. + */ +typedef struct _ENetPeer +{ + ENetListNode dispatchList; + struct _ENetHost * host; + enet_uint16 outgoingPeerID; + enet_uint16 incomingPeerID; + enet_uint32 connectID; + enet_uint8 outgoingSessionID; + enet_uint8 incomingSessionID; + ENetAddress address; /**< Internet address of the peer */ + void * data; /**< Application private data, may be freely modified */ + ENetPeerState state; + ENetChannel * channels; + size_t channelCount; /**< Number of channels allocated for communication with peer */ + enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + 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; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + 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; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ + enet_uint32 roundTripTimeVariance; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 reliableDataInTransit; + enet_uint16 outgoingReliableSequenceNumber; + ENetList acknowledgements; + ENetList sentReliableCommands; + ENetList sentUnreliableCommands; + ENetList outgoingReliableCommands; + ENetList outgoingUnreliableCommands; + ENetList dispatchedCommands; + enet_uint16 flags; + enet_uint8 roundTripTimeRemainder; + enet_uint8 roundTripTimeVarianceRemainder; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; + enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 eventData; + size_t totalWaitingData; +} ENetPeer; + +/** An ENet packet compressor for compressing UDP packets before socket sends or receives. + */ +typedef struct _ENetCompressor +{ + /** Context data for the compressor. Must be non-NULL. */ + void * context; + /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); + /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ + void (ENET_CALLBACK * destroy) (void * context); +} ENetCompressor; + +/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ +typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); + +/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ +typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event); + +/** An ENet host for communicating with peers. + * + * No fields should be modified unless otherwise stated. + + @sa enet_host_create() + @sa enet_host_destroy() + @sa enet_host_connect() + @sa enet_host_service() + @sa enet_host_flush() + @sa enet_host_broadcast() + @sa enet_host_compress() + @sa enet_host_compress_with_range_coder() + @sa enet_host_channel_limit() + @sa enet_host_bandwidth_limit() + @sa enet_host_bandwidth_throttle() + */ +typedef struct _ENetHost +{ + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + enet_uint32 randomSeed; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + size_t channelLimit; /**< maximum number of channels allowed for connected peers */ + 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; /**< callback the user can set to enable packet checksums for this host */ + ENetCompressor compressor; + enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; + ENetAddress receivedAddress; + enet_uint8 * receivedData; + size_t receivedDataLength; + enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ + ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ + size_t connectedPeers; + size_t bandwidthLimitedPeers; + size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ + size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */ + size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */ +} ENetHost; + +/** + * An ENet event type, as specified in @ref ENetEvent. + */ +typedef enum _ENetEventType +{ + /** no event occurred within the specified time limit */ + ENET_EVENT_TYPE_NONE = 0, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + ENET_EVENT_TYPE_CONNECT = 1, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_peer_disconnect, if + * a peer has timed out, or if a connection request intialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + ENET_EVENT_TYPE_DISCONNECT = 2, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + ENET_EVENT_TYPE_RECEIVE = 3 +} ENetEventType; + +/** + * An ENet event as returned by enet_host_service(). + + @sa enet_host_service + */ +typedef struct _ENetEvent +{ + ENetEventType type; /**< type of the event */ + ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ + enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ + enet_uint32 data; /**< data associated with the event, if appropriate */ + ENetPacket * packet; /**< packet associated with the event, if appropriate */ +} ENetEvent; + +/** @defgroup global ENet global functions + @{ +*/ + +/** + Initializes ENet globally. Must be called prior to using any functions in + ENet. + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize (void); + +/** + Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. + + @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use + @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults + @returns 0 on success, < 0 on failure +*/ +ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); + +/** + Shuts down ENet globally. Should be called when a program that has + initialized ENet exits. +*/ +ENET_API void enet_deinitialize (void); + +/** + Gives the linked version of the ENet library. + @returns the version number +*/ +ENET_API ENetVersion enet_linked_version (void); + +/** @} */ + +/** @defgroup private ENet private implementation functions */ + +/** + Returns the wall-time in milliseconds. Its initial value is unspecified + unless otherwise set. + */ +ENET_API enet_uint32 enet_time_get (void); +/** + Sets the current wall-time in milliseconds. + */ +ENET_API void enet_time_set (enet_uint32); + +/** @defgroup socket ENet socket functions + @{ +*/ +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *); +ENET_API int enet_socket_listen (ENetSocket, int); +ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); +ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *); +ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown); +ENET_API void enet_socket_destroy (ENetSocket); +ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); + +/** @} */ + +/** @defgroup Address ENet address functions + @{ +*/ + +/** Attempts to parse the printable form of the IP address in the parameter hostName + and sets the host field in the address parameter if successful. + @param address destination to store the parsed IP address + @param hostName IP address to parse + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostName); + +/** Attempts to resolve the host named by the parameter hostName and sets + the host field in the address parameter if successful. + @param address destination to store resolved address + @param hostName host name to lookup + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); + +/** Gives the printable form of the IP address specified in the address parameter. + @param address address printed + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); + +/** Attempts to do a reverse lookup of the host field in the address parameter. + @param address address used for reverse lookup + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); + +/** @} */ + +ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); +ENET_API void enet_packet_destroy (ENetPacket *); +ENET_API int enet_packet_resize (ENetPacket *, size_t); +ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t); + +ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); +ENET_API void enet_host_destroy (ENetHost *); +ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); +ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); +ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); +ENET_API void enet_host_flush (ENetHost *); +ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); +ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); +ENET_API int enet_host_compress_with_range_coder (ENetHost * host); +ENET_API void enet_host_channel_limit (ENetHost *, size_t); +ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); +extern void enet_host_bandwidth_throttle (ENetHost *); +extern enet_uint32 enet_host_random_seed (void); + +ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); +ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); +ENET_API void enet_peer_ping (ENetPeer *); +ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32); +ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +ENET_API void enet_peer_reset (ENetPeer *); +ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); +ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +extern int enet_peer_throttle (ENetPeer *, enet_uint32); +extern void enet_peer_reset_queues (ENetPeer *); +extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); +extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); +extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); +extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); +extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); +extern void enet_peer_on_connect (ENetPeer *); +extern void enet_peer_on_disconnect (ENetPeer *); + +ENET_API void * enet_range_coder_create (void); +ENET_API void enet_range_coder_destroy (void *); +ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); +ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#endif /* __ENET_ENET_H__ */ + diff --git a/enet/include/enet/list.h b/enet/include/enet/list.h new file mode 100644 index 0000000..d7b2600 --- /dev/null +++ b/enet/include/enet/list.h @@ -0,0 +1,43 @@ +/** + @file list.h + @brief ENet list management +*/ +#ifndef __ENET_LIST_H__ +#define __ENET_LIST_H__ + +#include + +typedef struct _ENetListNode +{ + struct _ENetListNode * next; + struct _ENetListNode * previous; +} ENetListNode; + +typedef ENetListNode * ENetListIterator; + +typedef struct _ENetList +{ + ENetListNode sentinel; +} ENetList; + +extern void enet_list_clear (ENetList *); + +extern ENetListIterator enet_list_insert (ENetListIterator, void *); +extern void * enet_list_remove (ENetListIterator); +extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); + +extern size_t enet_list_size (ENetList *); + +#define enet_list_begin(list) ((list) -> sentinel.next) +#define enet_list_end(list) (& (list) -> sentinel) + +#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) + +#define enet_list_next(iterator) ((iterator) -> next) +#define enet_list_previous(iterator) ((iterator) -> previous) + +#define enet_list_front(list) ((void *) (list) -> sentinel.next) +#define enet_list_back(list) ((void *) (list) -> sentinel.previous) + +#endif /* __ENET_LIST_H__ */ + diff --git a/enet/include/enet/protocol.h b/enet/include/enet/protocol.h new file mode 100644 index 0000000..f8c73d8 --- /dev/null +++ b/enet/include/enet/protocol.h @@ -0,0 +1,198 @@ +/** + @file protocol.h + @brief ENet protocol +*/ +#ifndef __ENET_PROTOCOL_H__ +#define __ENET_PROTOCOL_H__ + +#include "enet/types.h" + +enum +{ + ENET_PROTOCOL_MINIMUM_MTU = 576, + ENET_PROTOCOL_MAXIMUM_MTU = 4096, + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, + ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 +}; + +typedef enum _ENetProtocolCommand +{ + ENET_PROTOCOL_COMMAND_NONE = 0, + ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, + ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, + ENET_PROTOCOL_COMMAND_COUNT = 13, + + ENET_PROTOCOL_COMMAND_MASK = 0x0F +} ENetProtocolCommand; + +typedef enum _ENetProtocolFlag +{ + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), + + ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, + + ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 +} ENetProtocolFlag; + +#ifdef _MSC_VER +#pragma pack(push, 1) +#define ENET_PACKED +#elif defined(__GNUC__) || defined(__clang__) +#define ENET_PACKED __attribute__ ((packed)) +#else +#define ENET_PACKED +#endif + +typedef struct _ENetProtocolHeader +{ + enet_uint16 peerID; + enet_uint16 sentTime; +} ENET_PACKED ENetProtocolHeader; + +typedef struct _ENetProtocolCommandHeader +{ + enet_uint8 command; + enet_uint8 channelID; + enet_uint16 reliableSequenceNumber; +} ENET_PACKED ENetProtocolCommandHeader; + +typedef struct _ENetProtocolAcknowledge +{ + ENetProtocolCommandHeader header; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENET_PACKED ENetProtocolAcknowledge; + +typedef struct _ENetProtocolConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; + enet_uint32 data; +} ENET_PACKED ENetProtocolConnect; + +typedef struct _ENetProtocolVerifyConnect +{ + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; +} ENET_PACKED ENetProtocolVerifyConnect; + +typedef struct _ENetProtocolBandwidthLimit +{ + ENetProtocolCommandHeader header; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; +} ENET_PACKED ENetProtocolBandwidthLimit; + +typedef struct _ENetProtocolThrottleConfigure +{ + ENetProtocolCommandHeader header; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENET_PACKED ENetProtocolThrottleConfigure; + +typedef struct _ENetProtocolDisconnect +{ + ENetProtocolCommandHeader header; + enet_uint32 data; +} ENET_PACKED ENetProtocolDisconnect; + +typedef struct _ENetProtocolPing +{ + ENetProtocolCommandHeader header; +} ENET_PACKED ENetProtocolPing; + +typedef struct _ENetProtocolSendReliable +{ + ENetProtocolCommandHeader header; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendReliable; + +typedef struct _ENetProtocolSendUnreliable +{ + ENetProtocolCommandHeader header; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnreliable; + +typedef struct _ENetProtocolSendUnsequenced +{ + ENetProtocolCommandHeader header; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnsequenced; + +typedef struct _ENetProtocolSendFragment +{ + ENetProtocolCommandHeader header; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; + enet_uint32 fragmentCount; + enet_uint32 fragmentNumber; + enet_uint32 totalLength; + enet_uint32 fragmentOffset; +} ENET_PACKED ENetProtocolSendFragment; + +typedef union _ENetProtocol +{ + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolConnect connect; + ENetProtocolVerifyConnect verifyConnect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolThrottleConfigure throttleConfigure; +} ENET_PACKED ENetProtocol; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +#endif /* __ENET_PROTOCOL_H__ */ + diff --git a/enet/include/enet/time.h b/enet/include/enet/time.h new file mode 100644 index 0000000..c82a546 --- /dev/null +++ b/enet/include/enet/time.h @@ -0,0 +1,18 @@ +/** + @file time.h + @brief ENet time constants and macros +*/ +#ifndef __ENET_TIME_H__ +#define __ENET_TIME_H__ + +#define ENET_TIME_OVERFLOW 86400000 + +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) + +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +#endif /* __ENET_TIME_H__ */ + diff --git a/enet/include/enet/types.h b/enet/include/enet/types.h new file mode 100644 index 0000000..ab010a4 --- /dev/null +++ b/enet/include/enet/types.h @@ -0,0 +1,13 @@ +/** + @file types.h + @brief type definitions for ENet +*/ +#ifndef __ENET_TYPES_H__ +#define __ENET_TYPES_H__ + +typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ +typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ +typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ + +#endif /* __ENET_TYPES_H__ */ + diff --git a/enet/include/enet/unix.h b/enet/include/enet/unix.h new file mode 100644 index 0000000..b55be33 --- /dev/null +++ b/enet/include/enet/unix.h @@ -0,0 +1,48 @@ +/** + @file unix.h + @brief ENet Unix header +*/ +#ifndef __ENET_UNIX_H__ +#define __ENET_UNIX_H__ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef MSG_MAXIOVLEN +#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN +#endif + +typedef int ENetSocket; + +#define ENET_SOCKET_NULL -1 + +#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ +#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ + +typedef struct +{ + void * data; + size_t dataLength; +} ENetBuffer; + +#define ENET_CALLBACK + +#define ENET_API extern + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_UNIX_H__ */ + diff --git a/enet/include/enet/utility.h b/enet/include/enet/utility.h new file mode 100644 index 0000000..b04bb7a --- /dev/null +++ b/enet/include/enet/utility.h @@ -0,0 +1,13 @@ +/** + @file utility.h + @brief ENet utility header +*/ +#ifndef __ENET_UTILITY_H__ +#define __ENET_UTILITY_H__ + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) +#define ENET_DIFFERENCE(x, y) ((x) < (y) ? (y) - (x) : (x) - (y)) + +#endif /* __ENET_UTILITY_H__ */ + diff --git a/enet/include/enet/win32.h b/enet/include/enet/win32.h new file mode 100644 index 0000000..e73ca9d --- /dev/null +++ b/enet/include/enet/win32.h @@ -0,0 +1,57 @@ +/** + @file win32.h + @brief ENet Win32 header +*/ +#ifndef __ENET_WIN32_H__ +#define __ENET_WIN32_H__ + +#ifdef _MSC_VER +#ifdef ENET_BUILDING_LIB +#pragma warning (disable: 4267) // size_t to int conversion +#pragma warning (disable: 4244) // 64bit to 32bit int +#pragma warning (disable: 4018) // signed/unsigned mismatch +#pragma warning (disable: 4146) // unary minus operator applied to unsigned type +#endif +#endif + +#include +#include + +typedef SOCKET ENetSocket; + +#define ENET_SOCKET_NULL INVALID_SOCKET + +#define ENET_HOST_TO_NET_16(value) (htons (value)) +#define ENET_HOST_TO_NET_32(value) (htonl (value)) + +#define ENET_NET_TO_HOST_16(value) (ntohs (value)) +#define ENET_NET_TO_HOST_32(value) (ntohl (value)) + +typedef struct +{ + size_t dataLength; + void * data; +} ENetBuffer; + +#define ENET_CALLBACK __cdecl + +#ifdef ENET_DLL +#ifdef ENET_BUILDING_LIB +#define ENET_API __declspec( dllexport ) +#else +#define ENET_API __declspec( dllimport ) +#endif /* ENET_BUILDING_LIB */ +#else /* !ENET_DLL */ +#define ENET_API extern +#endif /* ENET_DLL */ + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_WIN32_H__ */ + + diff --git a/enetc.go b/enetc.go new file mode 100644 index 0000000..c342c6b --- /dev/null +++ b/enetc.go @@ -0,0 +1,17 @@ +package enet + +// #cgo LDFLAGS: -lenet +// #cgo windows CFLAGS: -Ienet/include/ +// #cgo windows LDFLAGS: -Lenet/ -lWs2_32 -lWinmm +// #include +import "C" + +// Initialize enet +func Initialize() { + C.enet_initialize() +} + +// Deinitialize enet +func Deinitialize() { + C.enet_deinitialize() +} diff --git a/event.go b/event.go new file mode 100644 index 0000000..ef05cbd --- /dev/null +++ b/event.go @@ -0,0 +1,60 @@ +package enet + +// #include +import "C" + +// EventType is a type of event +type EventType int + +const ( + // EventNone means that no event occurred within the specified time limit + EventNone EventType = iota + + // EventConnect means that a connection request initiated by Host.Connect has completed + // The peer field contains the peer which successfully connected + EventConnect + + // EventDisconnect means that a peer has disconnected. This event is generated on a + // successful completion of a disconnect initiated by Peer.Disconnect, if a peer has + // timed out, or if a connection request intialized by Host.Connect has timed out. The + // peer field contains the peer which disconnected. The data field contains user supplied + // data describing the disconnection, or 0, if none is available. + EventDisconnect + + // EventReceive means that a packet has been received from a peer. The peer field + // specifies the peer which sent the packet. The channelID field specifies the channel + // number upon which the packet was received. The packet field contains the packet that + // was received; this packet must be destroyed with Packet.Destroy after use. + EventReceive +) + +// Event as returned by Host.Service() +type Event interface { + GetType() EventType + GetPeer() Peer + GetChannelID() uint8 + GetData() uint32 + //GetPacket() Packet +} + +type enetEvent struct { + cEvent C.struct__ENetEvent +} + +func (event *enetEvent) GetType() EventType { + return (EventType)(event.cEvent._type) +} + +func (event *enetEvent) GetPeer() Peer { + return enetPeer{ + cPeer: event.cEvent.peer, + } +} + +func (event *enetEvent) GetChannelID() uint8 { + return (uint8)(event.cEvent.channelID) +} + +func (event *enetEvent) GetData() uint32 { + return (uint32)(event.cEvent.data) +} diff --git a/host.go b/host.go new file mode 100644 index 0000000..af3929e --- /dev/null +++ b/host.go @@ -0,0 +1,50 @@ +package enet + +// #include +import "C" +import ( + "errors" +) + +// Host for communicating with peers +type Host interface { + Destroy() + Service(timeout uint32) Event +} + +type enetHost struct { + cHost *C.struct__ENetHost +} + +func (host *enetHost) Destroy() { + C.enet_host_destroy(host.cHost) +} + +func (host *enetHost) Service(timeout uint32) Event { + ret := &enetEvent{} + C.enet_host_service( + host.cHost, + &ret.cEvent, + (C.enet_uint32)(timeout), + ) + return ret +} + +// NewHost creats a host for communicating to peers +func NewHost(addr Address, peerCount, channelLimit uint64, incomingBandwidth, outgoingBandwidth uint32) (Host, error) { + host := C.enet_host_create( + &(addr.(*enetAddress)).cAddr, + (C.size_t)(peerCount), + (C.size_t)(channelLimit), + (C.enet_uint32)(incomingBandwidth), + (C.enet_uint32)(outgoingBandwidth), + ) + + if host == nil { + return nil, errors.New("unable to create host") + } + + return &enetHost{ + cHost: host, + }, nil +} diff --git a/peer.go b/peer.go new file mode 100644 index 0000000..0354900 --- /dev/null +++ b/peer.go @@ -0,0 +1,19 @@ +package enet + +// #include +import "C" + +// Peer is a peer which data packets may be sent or received from +type Peer interface { + GetAddress() Address +} + +type enetPeer struct { + cPeer *C.struct__ENetPeer +} + +func (peer enetPeer) GetAddress() Address { + return &enetAddress{ + cAddr: peer.cPeer.address, + } +}