From a339bf51c8679db383343b8353e99256e4dd6c34 Mon Sep 17 00:00:00 2001 From: zoeyjodon <76182954+zoeyjodon@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:23:03 -0500 Subject: [PATCH] Prevent Polling from Blocking on 3DS (#15) --- include/enet/enet.h | 75 ++++++++++++++++++++++++--------------------- unix.c | 19 +++++++++--- 2 files changed, 55 insertions(+), 39 deletions(-) diff --git a/include/enet/enet.h b/include/enet/enet.h index de136ffb..fd48edd5 100644 --- a/include/enet/enet.h +++ b/include/enet/enet.h @@ -1,4 +1,4 @@ -/** +/** @file enet.h @brief ENet public header file */ @@ -75,7 +75,7 @@ typedef enum _ENetSocketShutdown } ENetSocketShutdown; /** - * Portable internet address structure. + * Portable internet address structure. */ typedef struct _ENetAddress { @@ -89,7 +89,7 @@ typedef struct _ENetAddress * 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 @@ -116,16 +116,16 @@ 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), + * 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 + * 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 @@ -169,7 +169,7 @@ typedef struct _ENetOutgoingCommand } ENetOutgoingCommand; typedef struct _ENetIncomingCommand -{ +{ ENetListNode incomingCommandList; enet_uint16 reliableSequenceNumber; enet_uint16 unreliableSequenceNumber; @@ -191,7 +191,7 @@ typedef enum _ENetPeerState ENET_PEER_STATE_DISCONNECT_LATER = 6, ENET_PEER_STATE_DISCONNECTING = 7, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, - ENET_PEER_STATE_ZOMBIE = 9 + ENET_PEER_STATE_ZOMBIE = 9 } ENetPeerState; #ifndef ENET_BUFFER_MAXIMUM @@ -200,8 +200,13 @@ typedef enum _ENetPeerState enum { +#ifdef __3DS__ + ENET_HOST_RECEIVE_BUFFER_SIZE = 0x20000, + ENET_HOST_SEND_BUFFER_SIZE = 0x20000, +#else ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, +#endif ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, ENET_HOST_DEFAULT_MTU = 900, ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, @@ -210,7 +215,7 @@ enum 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_COUNTER = 7, ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, @@ -248,12 +253,12 @@ typedef enum _ENetPeerFlag } ENetPeerFlag; /** - * An ENet peer which data packets may be sent or received from. + * An ENet peer which data packets may be sent or received from. * - * No fields should be modified unless otherwise specified. + * No fields should be modified unless otherwise specified. */ typedef struct _ENetPeer -{ +{ ENetListNode dispatchList; struct _ENetHost * host; enet_uint16 outgoingPeerID; @@ -312,7 +317,7 @@ typedef struct _ENetPeer enet_uint16 reserved; enet_uint16 incomingUnsequencedGroup; enet_uint16 outgoingUnsequencedGroup; - enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; enet_uint32 eventData; size_t totalWaitingData; } ENetPeer; @@ -336,7 +341,7 @@ typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * b /** 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. @@ -399,21 +404,21 @@ typedef struct _ENetHost typedef enum _ENetEventType { /** no event occurred within the specified time limit */ - ENET_EVENT_TYPE_NONE = 0, + ENET_EVENT_TYPE_NONE = 0, - /** a connection request initiated by enet_host_connect has completed. - * The peer field contains the peer which successfully connected. + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. */ - ENET_EVENT_TYPE_CONNECT = 1, + 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 + /** 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, + 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 @@ -426,10 +431,10 @@ typedef enum _ENetEventType /** * An ENet event as returned by enet_host_service(). - + @sa enet_host_service */ -typedef struct _ENetEvent +typedef struct _ENetEvent { ENetEventType type; /**< type of the event */ ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ @@ -439,17 +444,17 @@ typedef struct _ENetEvent } 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 @@ -458,7 +463,7 @@ ENET_API int enet_initialize (void); */ 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. */ @@ -466,7 +471,7 @@ ENET_API void enet_deinitialize (void); /** Gives the linked version of the ENet library. - @returns the version number + @returns the version number */ ENET_API ENetVersion enet_linked_version (void); @@ -526,7 +531,7 @@ 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 (int, 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); @@ -567,7 +572,7 @@ 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 diff --git a/unix.c b/unix.c index ac60aca0..111b9bda 100644 --- a/unix.c +++ b/unix.c @@ -226,16 +226,16 @@ enet_address_make_v4mapped (ENetAddress * address) ENetAddress oldAddress = *address; struct sockaddr_in *sin = ((struct sockaddr_in *)&oldAddress.address); struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&address->address; - + memset(sin6, 0, sizeof(*sin6)); sin6->sin6_family = AF_INET6; sin6->sin6_len = sizeof(*sin6); sin6->sin6_port = sin->sin_port; - + sin6->sin6_addr.s6_addr[10] = 0xFF; sin6->sin6_addr.s6_addr[11] = 0xFF; memcpy(&sin6->sin6_addr.s6_addr[12], &sin->sin_addr, 4); - + address->addressLength = sizeof(*sin6); } #endif @@ -768,7 +768,7 @@ enet_socket_receive (ENetSocket socket, if (peerAddress != NULL) { peerAddress -> addressLength = msgHdr.msg_namelen; - + #ifdef __APPLE__ // HACK: Apple platforms return AF_INET addresses in msg_name from recvmsg() on dual-stack sockets // instead of AF_INET6 addresses then rejects those same addresses when they are passed to sendmsg(). @@ -811,7 +811,18 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou if (* condition & ENET_SOCKET_WAIT_RECEIVE) pollSocket.events |= POLLIN; +#if defined(__3DS__) + uint64_t poll_start = osGetTime(); + for (uint64_t i = poll_start; (i - poll_start) < timeout; i = osGetTime()) { + pollCount = poll(& pollSocket, 1, 0); // need to do this on 3ds since poll will block even if socket is ready before + if (pollCount) { + break; + } + svcSleepThread(1000); + } +#else pollCount = poll (& pollSocket, 1, timeout); +#endif if (pollCount < 0) {