96 Commits

Author SHA1 Message Date
ReenigneArcher 0eb84dcca8 Add NXDK (Xbox) support
CMake / CMake ubuntu-latest Debug (push) Cancelled after 0s
CMake / CMake windows-latest Debug (push) Cancelled after 0s
CMake / CMake macos-latest Release (push) Cancelled after 0s
CMake / CMake ubuntu-latest Release (push) Cancelled after 0s
CMake / CMake windows-latest Release (push) Cancelled after 0s
CMake / CMake macos-latest Debug (push) Cancelled after 0s
2026-05-23 18:45:48 -05:00
MrCreativ3001 c7353c0593 Use lowercase windows headers for easier cross-compilation 2026-02-20 19:32:47 -06:00
Cameron Gutman 78cc9b4b03 Only pass the peer's local address if the host was wildcard bound 2026-02-06 23:20:39 -06:00
ReenigneArcher dea6fb5414 Add FreeBSD support for IP_RECVDSTADDR and IP_SENDSRCADDR
This commit adds compatibility for FreeBSD by using IP_RECVDSTADDR and IP_SENDSRCADDR in place of IP_PKTINFO for IPv4 socket operations. It ensures correct handling of source and destination addresses on FreeBSD systems where struct in_pktinfo is not available.
2025-11-09 20:29:40 -06:00
AorsiniYT 115a10baa1 Removes unnecessary definitions for PS Vita and ensures unavailability of the Messages API. 2025-07-04 16:58:56 -05:00
Cameron Gutman 44c85e1627 Further improve ping interval wait logic 2024-10-20 17:05:36 -05:00
Cameron Gutman badcd6c01d Fix waking early to send pings 2024-10-20 16:32:16 -05:00
Cameron Gutman b757dc7c28 Wake from the socket wait for a peer RTO 2024-10-20 16:16:57 -05:00
Cameron Gutman bbf71856bb Use SO_NONBLOCK on Haiku 2024-06-10 23:44:39 -05:00
Roberto Acevedo 76125b56b3 Update unix.c
Added check to compile in Haiku
2024-06-10 23:35:15 -05:00
Cameron Gutman 9e1cfe280a Fix -Wsign-compare warning 2024-05-25 17:08:01 -05:00
GaryOderNichts 0032f5e750 Implement support for userbuffers on Wii U
The Wii U socket implementation has limited memory available. To support larger receive buffers, application memory needs to be provided.
To make sockets use this user memory the `SO_RUSRBUF` option needs to be set on the socket.
2024-02-18 13:35:43 -06:00
Cameron Gutman d3a323fc8b Don't use VersionHelpers.h on UWP 2024-02-03 17:18:59 -06:00
Cameron Gutman 04e2759067 Enable ECN/L4S on Windows 10 2024-02-03 15:04:23 -06:00
Cameron Gutman a754295f42 Enable ECN/L4S on UNIX
Since this is enabled as a QoS option, it will benefit from the opportunistic
disablement code when ECN-intolerant networks are encountered.
2024-02-03 14:34:24 -06:00
Cameron Gutman a92d6960a6 Enable DSCP tagging in addition to using SO_NET_SERVICE_TYPE on macOS/iOS
It appears SO_NET_SERVICE_TYPE doesn't always enable DSCP tagging, so let's do it manually too.
2024-02-01 18:24:53 -06:00
zoeyjodon a339bf51c8 Prevent Polling from Blocking on 3DS (#15) 2024-02-01 18:23:03 -06:00
Cameron Gutman 061ce30163 Add IN6ADDR_V4MAPPEDPREFIX_INIT definition for MinGW 2024-02-01 01:14:56 -06:00
Cameron Gutman c76572875a Add workaround for qWAVE bug with IPv4-mapped IPv6 addresses 2024-02-01 01:11:41 -06:00
Cameron Gutman f6e67b1138 Automatically disable QoS tagging on the server-side too for blackhole router scenarios
Also bump the threshold for QoS disablement to 3 losses to avoid unnecessary fallbacks on the server side.
2024-01-31 23:31:04 -06:00
Cameron Gutman acf813c4aa Ignore some socket errors that may be caused by transient network interruptions
This allows the ENet connection to survive WiFi network roaming.
2024-01-24 23:22:19 -06:00
Cameron Gutman c6bb0e5011 Add workaround for Apple kernel bug 2023-12-28 16:07:39 -06:00
Cameron Gutman 43218d4de2 Add warning when IPv6 options are not defined on Apple platforms 2023-12-28 00:35:46 -06:00
zoeyjodon 89a7ebd63d Reduce 3DS MTU (#14) 2023-12-22 12:48:34 -06:00
zoeyjodon c07aa74c60 Add 3DS configuration (#13)
* Adds unix definitions for the 3DS
Guards AF_INET6 options for 3DS builds
2023-11-10 15:09:07 -06:00
Arthur Kasimov bbfe93c248 Add CMake option to disable installation of headers and libraries 2023-09-20 20:51:32 -05:00
Cameron Gutman 880e41f3ab Fix QOS_FLOWID detection with new MinGW headers 2023-07-30 13:58:58 -05:00
Cameron Gutman 50ab7907d8 Don't enable QoS marking on ENet connections by default
The caller will enable this itself if appropriate for the given usage.
2023-07-30 13:56:05 -05:00
Cameron Gutman 68ffba7d45 Adjust RTO logic to retransmit more quickly on links with high RTT variance
Since Moonlight uses ENet for highly latency sensitive but very low bandwidth traffic flows, we'd rather generate a little excess traffic than wait too long to retransmit.
2023-07-30 13:52:25 -05:00
Cameron Gutman bbed828aae Cap the retransmit timer at 1/5 of the max peer timeout
This helps avoiding spurious disconnections in cases of large RTT variance
2023-07-26 00:57:05 -05:00
Cameron Gutman bdda0eecc5 Merge remote-tracking branch 'upstream/master' into moonlight 2023-07-25 21:54:49 -05:00
Lee Salzman 2a85cd6445 better partial message handling 2023-07-23 21:05:47 -04:00
Cameron Gutman 4979b629c2 Fix build after removal of roundTripTimeoutLimit 2023-07-08 11:14:46 -05:00
Cameron Gutman 33c726ab73 Merge remote-tracking branch 'upstream/master' into moonlight 2023-07-08 10:59:10 -05:00
Elia Zammuto 441a6e9c5b UWP Support (#10)
* Fixed Build for UWP
2023-07-08 08:22:12 -05:00
Cameron Gutman 7914bc74a9 Switch from timeGetTime() to GetTickCount() which is available for UWP apps too 2023-07-07 21:42:28 -05:00
Cameron Gutman fc123218d3 Don't adjust timer period when ENet is initialized
We handle this elsewhere in Moonlight and Sunshine when actually streaming
2023-07-07 21:41:49 -05:00
Lee Salzman ea4607a90d lower default MTU to 1392 to avoid stressing certain VPNs 2023-04-02 16:48:09 -04:00
Lee Salzman 8ae0e85298 update connecting peer's mtu from host's current mtu 2023-04-01 14:49:22 -04:00
Michael Keck 07a40ef0f9 Add GitHub Actions CI (#188)
Add GitHub Actions CI
2023-03-21 09:24:33 -04:00
Lee Salzman eb89a34d66 Merge pull request #222 from seragh/server-mtu
Fix MTU negotiation on server side
2023-03-10 14:01:19 -05:00
Ralph Sennhauser 4faa11a243 Fix MTU negotiation on server side
On connect the MTU sent by the client gets stored and sent back
unchanged if within minimum and maximum of the protocol. Then on verify
connect a test is done if the returned MTU is smaller than the current
MTU and if so gets adjusted. So as long as the MTU is within boundaries
only the client specified MTU is relevant.

This patch adds a check for smaller MTU on server side.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2023-03-10 09:41:55 +01:00
Chris Pable 47e42dbf42 Fix overlooked address -> peerAddress rename (#9) 2023-03-05 14:30:18 -06:00
Lee Salzman 153e10f953 Relocate home to http://sauerbraten.org/enet/ 2023-03-02 22:43:35 -05:00
Cameron Gutman e790647a57 Correctly support hosts with multiple possible source addresses 2023-02-12 15:35:34 -06:00
Lee Salzman be7cefa39c avoid explicitly storing roundTripTimeoutLimit 2023-02-05 00:55:34 -05:00
Lee Salzman 9dde91d003 remove unnecessary sent unreliable list from peers 2023-02-04 23:20:39 -05:00
Lee Salzman ca18dfb8f8 avoid revisiting peers when continuing to send 2023-02-04 22:48:18 -05:00
Lee Salzman d7e5470cf7 maintain a separate queue for outgoing send reliable packets 2023-02-04 22:16:19 -05:00
Lee Salzman bb788ea48b Merge pull request #217 from skyfloogle/ttl
Add ENET_SOCKOPT_TTL
2023-01-08 14:08:39 -05:00
Floogle 4e69c700d6 added ENET_SOCKOPT_TTL 2023-01-08 15:58:31 +01:00
Lee Salzman 311360dbdd Merge pull request #82 from JonnyPtn/master
Add install target to CMakeLists.txt
2022-10-17 14:21:53 -04:00
Lee Salzman b06d154579 Merge pull request #209 from daichifukui/dfukui/allow-build-on-hurd-i386
allow build on hurd i386
2022-10-11 00:08:04 -04:00
Fukui Daichi 6800acd9c7 allow build on hurd i386
This patch originates with:
https://salsa.debian.org/games-team/enet/-/commit/88648f10bd19d658167b0d303bef05e9e6144278
2022-10-10 12:36:16 +00:00
Lee Salzman 4f8e9bdc4c use a hard-coded crc32 table 2022-08-12 08:46:05 -04:00
Lee Salzman 3340d1cf85 more enet_peer_send notes 2022-02-20 15:05:33 -05:00
Lee Salzman bd0115c907 enet_peer_send note about failure and enet_packet_destroy 2022-02-20 15:03:09 -05:00
Lee Salzman 987cd0650f Merge pull request #187 from metaquarx/master
Future proof cmake minimum version
2022-01-19 14:41:45 -05:00
metaquarx 92ef50a080 future proof cmake minimum version 2022-01-19 19:22:50 +00:00
Lee Salzman 498b9e3571 silence analyzer warning about peer->channels 2021-11-11 10:05:49 -05:00
Mariotaku 4cde9cc3dc Fixed build with MinGW (#8)
* Fixed build with MinGW

* improved typedef check for MinGW

* added include dir to enet lib
2021-09-15 23:02:02 -05:00
Lee Salzman 74cea7abf5 switch irc channel 2021-06-13 16:15:37 -04:00
Cameron Gutman 8d69c5abe4 Avoid statically linking to qwave.dll
It's not present on Server SKUs by default.
2021-06-12 12:14:46 -05:00
Cameron Gutman ad5bf95397 fix excessive retransmissions when average RTT variance is 0 2021-05-16 15:35:02 -05:00
Cameron Gutman ab9d471cec fix SRTT calculations when RTT < 8 ms and SRTT >= 8 ms 2021-05-16 14:15:38 -05:00
Cameron Gutman c20ca391e2 fix RTO limit being exceeded 2021-05-14 18:46:49 -05:00
jonathan.r.paton@googlemail.com 9fda19e54b Add install target to CMakeLists.txt 2021-05-14 10:54:52 +01:00
Cameron Gutman 70ce1c3e0b Merge remote-tracking branch 'upstream/master' into moonlight 2021-04-29 09:40:57 -05:00
Cameron Gutman d8976c4fcc Merge pull request #6 from GaryOderNichts/wiiu
Wii U changes
2021-04-17 23:27:01 -05:00
GaryOderNichts bdfdb8b85d Wii U changes 2021-04-12 13:56:21 +02:00
Cameron Gutman d9e561938f Merge pull request #5 from lsalzman/master
Rebase to lsalzman/enet: update to 1.3.17
2021-01-09 18:38:33 -06:00
Cameron Gutman 2a788029bf Enable poll() for Linux/BSD 2020-07-27 00:01:51 -07:00
Cameron Gutman 757933e7bc Enable poll() on macOS and iOS 2020-07-26 20:06:38 -07:00
Cameron Gutman 8d794daa7c Merge branch 'master' of https://github.com/lsalzman/enet into moonlight
# Conflicts:
#	unix.c
#	win32.c
2020-06-12 21:46:42 -07:00
Cameron Gutman 9bf55a3433 Disable QoS tagging if 2 connect packets in a row are dropped 2020-06-12 21:16:46 -07:00
Cameron Gutman 5c96da29c2 Enable QoS prioritization on Windows 2020-04-09 17:42:12 -07:00
Cameron Gutman d988023971 Use EF instead of CS7 for DSCP
Some security guidelines recommend dropping CS7 tagged packets at the edge,
since CS7 is reserved for network control. EF seems to be the standard for
telephony applications and is fairly well preserved across the Internet per
https://www.sciencedirect.com/science/article/pii/S0166531619300203
2020-04-03 16:58:18 -07:00
Cameron Gutman 637cd52e96 Enable QoS prioritization on Linux 2020-03-29 15:44:14 -07:00
Cameron Gutman 512b3f26f9 Enable QOS prioritization on macOS 2020-03-29 15:21:26 -07:00
Cameron Gutman 5503534362 Fix Linux build 2019-10-12 19:41:41 -07:00
Sunguk Lee 93b080b053 vita: No more need vita specific codesets (#4)
* vita: No more need to define sockaddr_storage

* vita: Remove everything and combine unix codeset

* unix: Remove HACK for the specialized code of the vita nonblock IO
2019-10-12 15:10:59 -07:00
Cameron Gutman cf38f85e08 Be more lenient with the expected peer address for multi-homed hosts 2019-09-14 14:05:05 -07:00
Cameron Gutman e770a52bca Merge pull request #3 from d3m3vilurr/fix-vita-error-code
vita: No more use self defined net error code
2019-02-17 09:49:11 -08:00
Sunguk Lee 42891f6919 vita: No more use self defined net error code 2018-07-28 21:50:59 +09:00
Antonio Aloisio eb38c3c737 Fixed build with latest VitaSDK (#2) 2018-07-25 21:27:12 -07:00
Sunguk Lee e33ca1dc47 Add vita environment (#1)
* vita: Initial port

* vita: add debug logging and reduce max number of IOV (caused errors)

* vita: now using newlib's socket apis

* vita: Refactoring for cgutman/enet

* Fix review things

https://github.com/cgutman/enet/pull/1#pullrequestreview-2436331
2016-10-02 00:56:59 -07:00
Cameron Gutman 7546b505c1 Lower ENet's MTU to 900 because some ISPs will drop the RTSP DESCRIBE response packets with the default MTU 2016-05-21 18:01:31 -05:00
Cameron Gutman 2bc07bb50d Add enet_address_set_address() function to allow ENetAddress to be populated from sockaddr directly 2016-04-02 14:04:31 -04:00
Cameron Gutman a602abf244 Switch to gettimeofday() for seeding on UNIX 2016-03-31 11:22:06 -04:00
Cameron Gutman 167f41aa2b Fix build with NO_MSGAPI undefined 2016-03-27 22:47:50 -04:00
Cameron Gutman b2ee3b7b48 Add support for building with PNaCl's newlibc 2016-03-11 00:27:48 -08:00
Cameron Gutman 8b24595dbd Require an address family to be specified when creating a host 2016-03-07 14:26:13 -08:00
Cameron Gutman b3e34fa1db Fix some IPv6 compatibility issues 2016-03-06 23:22:59 -08:00
Cameron Gutman 4f7ef11c23 Fix some compilation warnings 2016-03-06 15:33:32 -08:00
Cameron Gutman a39d3bb49c Wake up every once in a while to see if any retransmissions or pings need to be sent 2016-03-06 14:56:08 -08:00
Cameron Gutman ae9002fe19 Protocol agnostic socket address to fix IPv6 and remove broadcast support 2016-03-06 14:47:01 -08:00
13 changed files with 1460 additions and 688 deletions
+21
View File
@@ -0,0 +1,21 @@
on: [push, pull_request]
name: CMake
jobs:
cmake-build:
name: CMake ${{ matrix.os }} ${{ matrix.build_type }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
build_type: ["Debug", "Release"]
steps:
- uses: actions/checkout@v3
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{ matrix.build_type }}
+28 -1
View File
@@ -1,12 +1,15 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 2.8.12...3.20)
project(enet)
option(ENET_NO_INSTALL "Disable installation of headers and libraries" OFF)
# The "configure" step.
include(CheckFunctionExists)
include(CheckStructHasMember)
include(CheckTypeSize)
check_function_exists("fcntl" HAS_FCNTL)
check_function_exists("ioctl" HAS_IOCTL)
check_function_exists("poll" HAS_POLL)
check_function_exists("getaddrinfo" HAS_GETADDRINFO)
check_function_exists("getnameinfo" HAS_GETNAMEINFO)
@@ -18,6 +21,10 @@ check_struct_has_member("struct msghdr" "msg_flags" "sys/types.h;sys/socket.h" H
set(CMAKE_EXTRA_INCLUDE_FILES "sys/types.h" "sys/socket.h")
check_type_size("socklen_t" HAS_SOCKLEN_T BUILTIN_TYPES_ONLY)
unset(CMAKE_EXTRA_INCLUDE_FILES)
set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;qos2.h")
check_type_size("QOS_FLOWID" HAS_QOS_FLOWID BUILTIN_TYPES_ONLY)
check_type_size("PQOS_FLOWID" HAS_PQOS_FLOWID BUILTIN_TYPES_ONLY)
unset(CMAKE_EXTRA_INCLUDE_FILES)
if(MSVC)
add_definitions(-W3)
else()
@@ -27,6 +34,9 @@ endif()
if(HAS_FCNTL)
add_definitions(-DHAS_FCNTL=1)
endif()
if(HAS_IOCTL)
add_definitions(-DHAS_IOCTL=1)
endif()
if(HAS_POLL)
add_definitions(-DHAS_POLL=1)
endif()
@@ -54,6 +64,12 @@ endif()
if(HAS_SOCKLEN_T)
add_definitions(-DHAS_SOCKLEN_T=1)
endif()
if(HAS_QOS_FLOWID)
add_definitions(-DHAS_QOS_FLOWID=1)
endif()
if(HAS_PQOS_FLOWID)
add_definitions(-DHAS_PQOS_FLOWID=1)
endif()
include_directories(${PROJECT_SOURCE_DIR}/include)
@@ -88,7 +104,18 @@ add_library(enet STATIC
${INCLUDE_FILES}
${SOURCE_FILES}
)
target_include_directories(enet SYSTEM PUBLIC include)
if (MINGW)
target_link_libraries(enet winmm ws2_32)
endif()
if(NOT ENET_NO_INSTALL)
install(TARGETS enet
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib/static
LIBRARY DESTINATION lib)
install(DIRECTORY include/
DESTINATION include)
endif()
+1 -1
View File
@@ -1,4 +1,4 @@
Please visit the ENet homepage at http://enet.bespin.org for installation
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
+1 -1
View File
@@ -53,7 +53,7 @@ The <a class="el" href="http://lists.cubik.org/mailman/listinfo/enet-discuss">en
/**
@page IRCChannel IRC Channel
Join the \#enet channel on the <a class="el" href="http://freenode.net">freenode IRC network (irc.freenode.net)</a> for real-time discussion about the ENet library.
Join the \#enet channel on the <a class="el" href="https://libera.chat">Libera Chat IRC network (irc.libera.chat)</a> for real-time discussion about the ENet library.
*/
+10 -30
View File
@@ -12,6 +12,7 @@
/** Creates a host for communicating to peers.
@param addressFamily the address family of the socket that should be created (ex: PF_INET/PF_INET6)
@param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host.
@param peerCount the maximum number of peers that should be allocated for the host.
@param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
@@ -26,7 +27,7 @@
at any given time.
*/
ENetHost *
enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
enet_host_create (int addressFamily, const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
{
ENetHost * host;
ENetPeer * currentPeer;
@@ -48,7 +49,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
}
memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
host -> socket = enet_socket_create (addressFamily, ENET_SOCKET_TYPE_DATAGRAM);
if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0))
{
if (host -> socket != ENET_SOCKET_NULL)
@@ -60,8 +61,9 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
return NULL;
}
host -> wildcardBind = address && enet_address_wildcard (address);
enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1);
enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1);
enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
@@ -87,8 +89,8 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
host -> commandCount = 0;
host -> bufferCount = 0;
host -> checksum = NULL;
host -> receivedAddress.host = ENET_HOST_ANY;
host -> receivedAddress.port = 0;
memset(& host -> receivedPeerAddress, 0, sizeof (host -> receivedPeerAddress));
memset(& host -> receivedLocalAddress, 0, sizeof (host -> receivedLocalAddress));
host -> receivedData = NULL;
host -> receivedDataLength = 0;
@@ -96,6 +98,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
host -> totalSentPackets = 0;
host -> totalReceivedData = 0;
host -> totalReceivedPackets = 0;
host -> totalQueued = 0;
host -> connectedPeers = 0;
host -> bandwidthLimitedPeers = 0;
@@ -123,8 +126,8 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
enet_list_clear (& currentPeer -> acknowledgements);
enet_list_clear (& currentPeer -> sentReliableCommands);
enet_list_clear (& currentPeer -> sentUnreliableCommands);
enet_list_clear (& currentPeer -> outgoingCommands);
enet_list_clear (& currentPeer -> outgoingSendReliableCommands);
enet_list_clear (& currentPeer -> dispatchedCommands);
enet_peer_reset (currentPeer);
@@ -210,6 +213,7 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC
currentPeer -> state = ENET_PEER_STATE_CONNECTING;
currentPeer -> address = * address;
currentPeer -> connectID = enet_host_random (host);
currentPeer -> mtu = host -> mtu;
if (host -> outgoingBandwidth == 0)
currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
@@ -261,30 +265,6 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC
return currentPeer;
}
/** Queues a packet to be sent to all peers associated with the host.
@param host host on which to broadcast the packet
@param channelID channel on which to broadcast
@param packet packet to broadcast
*/
void
enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet)
{
ENetPeer * currentPeer;
for (currentPeer = host -> peers;
currentPeer < & host -> peers [host -> peerCount];
++ currentPeer)
{
if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
continue;
enet_peer_send (currentPeer, channelID, packet);
}
if (packet -> referenceCount == 0)
enet_packet_destroy (packet);
}
/** Sets the packet compressor the host should use to compress and decompress packets.
@param host host to enable or disable compression for
@param compressor callbacks for for the packet compressor; if NULL, then compression is disabled
+34 -58
View File
@@ -12,7 +12,7 @@ extern "C"
#include <stdlib.h>
#ifdef _WIN32
#if defined(_WIN32) && !defined(NXDK)
#include "enet/win32.h"
#else
#include "enet/unix.h"
@@ -62,7 +62,9 @@ typedef enum _ENetSocketOption
ENET_SOCKOPT_RCVTIMEO = 6,
ENET_SOCKOPT_SNDTIMEO = 7,
ENET_SOCKOPT_ERROR = 8,
ENET_SOCKOPT_NODELAY = 9
ENET_SOCKOPT_NODELAY = 9,
ENET_SOCKOPT_TTL = 10,
ENET_SOCKOPT_QOS = 11,
} ENetSocketOption;
typedef enum _ENetSocketShutdown
@@ -72,24 +74,13 @@ typedef enum _ENetSocketShutdown
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;
socklen_t addressLength;
struct sockaddr_storage address;
} ENetAddress;
/**
@@ -169,7 +160,7 @@ typedef struct _ENetOutgoingCommand
enet_uint16 unreliableSequenceNumber;
enet_uint32 sentTime;
enet_uint32 roundTripTimeout;
enet_uint32 roundTripTimeoutLimit;
enet_uint32 queueTime;
enet_uint32 fragmentOffset;
enet_uint16 fragmentLength;
enet_uint16 sendAttempts;
@@ -209,10 +200,19 @@ typedef enum _ENetPeerState
enum
{
#if defined(__WIIU__)
ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024,
// Send buffer size is limited since it cannot use userbuffers
ENET_HOST_SEND_BUFFER_SIZE = 0x10000 - 1,
#elif defined(__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 = 1400,
ENET_HOST_DEFAULT_MTU = 900,
ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024,
ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024,
@@ -252,7 +252,8 @@ typedef struct _ENetChannel
typedef enum _ENetPeerFlag
{
ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0)
ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0),
ENET_PEER_FLAG_CONTINUE_SENDING = (1 << 1)
} ENetPeerFlag;
/**
@@ -270,6 +271,7 @@ typedef struct _ENetPeer
enet_uint8 outgoingSessionID;
enet_uint8 incomingSessionID;
ENetAddress address; /**< Internet address of the peer */
ENetAddress localAddress;
void * data; /**< Application private data, may be freely modified */
ENetPeerState state;
ENetChannel * channels;
@@ -312,7 +314,7 @@ typedef struct _ENetPeer
enet_uint16 outgoingReliableSequenceNumber;
ENetList acknowledgements;
ENetList sentReliableCommands;
ENetList sentUnreliableCommands;
ENetList outgoingSendReliableCommands;
ENetList outgoingCommands;
ENetList dispatchedCommands;
enet_uint16 flags;
@@ -353,7 +355,6 @@ typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, st
@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()
@@ -363,6 +364,7 @@ typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, st
typedef struct _ENetHost
{
ENetSocket socket;
int wildcardBind;
ENetAddress address; /**< Internet address of the host */
enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */
enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */
@@ -375,7 +377,7 @@ typedef struct _ENetHost
size_t channelLimit; /**< maximum number of channels allowed for connected peers */
enet_uint32 serviceTime;
ENetList dispatchQueue;
int continueSending;
enet_uint32 totalQueued;
size_t packetSize;
enet_uint16 headerFlags;
ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS];
@@ -385,7 +387,8 @@ typedef struct _ENetHost
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;
ENetAddress receivedPeerAddress;
ENetAddress receivedLocalAddress;
enet_uint8 * receivedData;
size_t receivedDataLength;
enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */
@@ -494,14 +497,14 @@ ENET_API void enet_time_set (enet_uint32);
/** @defgroup socket ENet socket functions
@{
*/
ENET_API ENetSocket enet_socket_create (ENetSocketType);
ENET_API ENetSocket enet_socket_create (int, 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_send (ENetSocket, const ENetAddress *, const ENetAddress *, const ENetBuffer *, size_t);
ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, 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 *);
@@ -514,17 +517,6 @@ ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSock
/** @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
@@ -534,26 +526,10 @@ ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostN
@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 int enet_address_set_address (ENetAddress * address, struct sockaddr * addr, socklen_t addrlen);
ENET_API int enet_address_set_port (ENetAddress * address, enet_uint16 port);
ENET_API int enet_address_wildcard (const ENetAddress * address);
ENET_API int enet_address_equal (ENetAddress * address1, ENetAddress * address2);
/** @} */
@@ -562,13 +538,12 @@ 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 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);
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);
@@ -589,6 +564,7 @@ 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 int enet_peer_has_outgoing_commands (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);
+4
View File
@@ -10,7 +10,11 @@
enum
{
ENET_PROTOCOL_MINIMUM_MTU = 576,
#if defined(__WIIU__) || defined(__3DS__)
ENET_PROTOCOL_MAXIMUM_MTU = 1400,
#else
ENET_PROTOCOL_MAXIMUM_MTU = 4096,
#endif
ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32,
ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096,
ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536,
+1
View File
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <winsock2.h>
#include <ws2tcpip.h>
typedef SOCKET ENetSocket;
+34 -41
View File
@@ -98,54 +98,47 @@ enet_packet_resize (ENetPacket * packet, size_t dataLength)
return 0;
}
static int initializedCRC32 = 0;
static enet_uint32 crcTable [256];
static enet_uint32
reflect_crc (int val, int bits)
static const enet_uint32 crcTable [256] =
{
int result = 0, bit;
for (bit = 0; bit < bits; bit ++)
{
if(val & 1) result |= 1 << (bits - 1 - bit);
val >>= 1;
}
return result;
}
static void
initialize_crc32 (void)
{
int byte;
for (byte = 0; byte < 256; ++ byte)
{
enet_uint32 crc = reflect_crc (byte, 8) << 24;
int offset;
for(offset = 0; offset < 8; ++ offset)
{
if (crc & 0x80000000)
crc = (crc << 1) ^ 0x04c11db7;
else
crc <<= 1;
}
crcTable [byte] = reflect_crc (crc, 32);
}
initializedCRC32 = 1;
}
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x5005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
enet_uint32
enet_crc32 (const ENetBuffer * buffers, size_t bufferCount)
{
enet_uint32 crc = 0xFFFFFFFF;
if (! initializedCRC32) initialize_crc32 ();
while (bufferCount -- > 0)
{
const enet_uint8 * data = (const enet_uint8 *) buffers -> data,
+29 -6
View File
@@ -90,6 +90,13 @@ enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt)
}
/** Queues a packet to be sent.
On success, ENet will assume ownership of the packet, and so enet_packet_destroy
should not be called on it thereafter. On failure, the caller still must destroy
the packet on its own as ENet has not queued the packet. The caller can also
check the packet's referenceCount field after sending to check if ENet queued
the packet and thus incremented the referenceCount.
@param peer destination for the packet
@param channelID channel on which to send
@param packet packet to send
@@ -321,8 +328,8 @@ enet_peer_reset_queues (ENetPeer * peer)
enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements)));
enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands);
enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands);
enet_peer_reset_outgoing_commands (& peer -> outgoingCommands);
enet_peer_reset_outgoing_commands (& peer -> outgoingSendReliableCommands);
enet_peer_reset_incoming_commands (& peer -> dispatchedCommands);
if (peer -> channels != NULL && peer -> channelCount > 0)
@@ -564,6 +571,17 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data)
}
}
int
enet_peer_has_outgoing_commands (ENetPeer * peer)
{
if (enet_list_empty (& peer -> outgoingCommands) &&
enet_list_empty (& peer -> outgoingSendReliableCommands) &&
enet_list_empty (& peer -> sentReliableCommands))
return 0;
return 1;
}
/** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
@param peer peer to request a disconnection
@param data data describing the disconnection
@@ -574,8 +592,7 @@ void
enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data)
{
if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) &&
! (enet_list_empty (& peer -> outgoingCommands) &&
enet_list_empty (& peer -> sentReliableCommands)))
enet_peer_has_outgoing_commands (peer))
{
peer -> state = ENET_PEER_STATE_DISCONNECT_LATER;
peer -> eventData = data;
@@ -619,8 +636,6 @@ enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command,
void
enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand)
{
ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID];
peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength;
if (outgoingCommand -> command.header.channelID == 0xFF)
@@ -631,6 +646,9 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
outgoingCommand -> unreliableSequenceNumber = 0;
}
else
{
ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID];
if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
{
++ channel -> outgoingReliableSequenceNumber;
@@ -655,12 +673,13 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
}
}
outgoingCommand -> sendAttempts = 0;
outgoingCommand -> sentTime = 0;
outgoingCommand -> roundTripTimeout = 0;
outgoingCommand -> roundTripTimeoutLimit = 0;
outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber);
outgoingCommand -> queueTime = ++ peer -> host -> totalQueued;
switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
{
@@ -676,6 +695,10 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
break;
}
if ((outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0 &&
outgoingCommand -> packet != NULL)
enet_list_insert (enet_list_end (& peer -> outgoingSendReliableCommands), outgoingCommand);
else
enet_list_insert (enet_list_end (& peer -> outgoingCommands), outgoingCommand);
}
+180 -94
View File
@@ -9,7 +9,7 @@
#include "enet/time.h"
#include "enet/enet.h"
static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
static const size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
{
0,
sizeof (ENetProtocolAcknowledge),
@@ -159,16 +159,16 @@ enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * e
}
static void
enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer)
enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer, ENetList * sentUnreliableCommands)
{
ENetOutgoingCommand * outgoingCommand;
if (enet_list_empty (& peer -> sentUnreliableCommands))
if (enet_list_empty (sentUnreliableCommands))
return;
do
{
outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands);
outgoingCommand = (ENetOutgoingCommand *) enet_list_front (sentUnreliableCommands);
enet_list_remove (& outgoingCommand -> outgoingCommandList);
@@ -185,14 +185,38 @@ enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer)
}
enet_free (outgoingCommand);
} while (! enet_list_empty (& peer -> sentUnreliableCommands));
} while (! enet_list_empty (sentUnreliableCommands));
if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
enet_list_empty (& peer -> outgoingCommands) &&
enet_list_empty (& peer -> sentReliableCommands))
! enet_peer_has_outgoing_commands (peer))
enet_peer_disconnect (peer, peer -> eventData);
}
static ENetOutgoingCommand *
enet_protocol_find_sent_reliable_command (ENetList * list, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
{
ENetListIterator currentCommand;
for (currentCommand = enet_list_begin (list);
currentCommand != enet_list_end (list);
currentCommand = enet_list_next (currentCommand))
{
ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) currentCommand;
if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE))
continue;
if (outgoingCommand -> sendAttempts < 1)
break;
if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
outgoingCommand -> command.header.channelID == channelID)
return outgoingCommand;
}
return NULL;
}
static ENetProtocolCommand
enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
{
@@ -214,24 +238,9 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliabl
if (currentCommand == enet_list_end (& peer -> sentReliableCommands))
{
for (currentCommand = enet_list_begin (& peer -> outgoingCommands);
currentCommand != enet_list_end (& peer -> outgoingCommands);
currentCommand = enet_list_next (currentCommand))
{
outgoingCommand = (ENetOutgoingCommand *) currentCommand;
if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE))
continue;
if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE;
if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
outgoingCommand -> command.header.channelID == channelID)
break;
}
if (currentCommand == enet_list_end (& peer -> outgoingCommands))
return ENET_PROTOCOL_COMMAND_NONE;
outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingCommands, reliableSequenceNumber, channelID);
if (outgoingCommand == NULL)
outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingSendReliableCommands, reliableSequenceNumber, channelID);
wasSent = 0;
}
@@ -309,10 +318,9 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
}
else
if (currentPeer -> state != ENET_PEER_STATE_CONNECTING &&
currentPeer -> address.host == host -> receivedAddress.host)
enet_address_equal (& currentPeer -> address, & host -> receivedPeerAddress))
{
if (currentPeer -> address.port == host -> receivedAddress.port &&
currentPeer -> connectID == command -> connect.connectID)
if (currentPeer -> connectID == command -> connect.connectID)
return NULL;
++ duplicatePeers;
@@ -330,7 +338,9 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
peer -> channelCount = channelCount;
peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT;
peer -> connectID = command -> connect.connectID;
peer -> address = host -> receivedAddress;
peer -> address = host -> receivedPeerAddress;
peer -> localAddress = host -> receivedLocalAddress;
peer -> mtu = host -> mtu;
peer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID);
peer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth);
peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth);
@@ -375,6 +385,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
if (mtu > ENET_PROTOCOL_MAXIMUM_MTU)
mtu = ENET_PROTOCOL_MAXIMUM_MTU;
if (mtu < peer -> mtu)
peer -> mtu = mtu;
if (host -> outgoingBandwidth == 0 &&
@@ -542,7 +553,8 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength);
* currentData += fragmentLength;
if (fragmentLength > host -> maximumPacketSize ||
if (fragmentLength <= 0 ||
fragmentLength > host -> maximumPacketSize ||
* currentData < host -> receivedData ||
* currentData > & host -> receivedData [host -> receivedDataLength])
return -1;
@@ -566,6 +578,7 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
fragmentNumber >= fragmentCount ||
totalLength > host -> maximumPacketSize ||
totalLength < fragmentCount ||
fragmentOffset >= totalLength ||
fragmentLength > totalLength - fragmentOffset)
return -1;
@@ -860,19 +873,19 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer *
{
enet_peer_throttle (peer, roundTripTime);
peer -> roundTripTimeVariance -= peer -> roundTripTimeVariance / 4;
peer -> roundTripTimeVariance -= (peer -> roundTripTimeVariance + 3) / 4;
if (roundTripTime >= peer -> roundTripTime)
{
enet_uint32 diff = roundTripTime - peer -> roundTripTime;
peer -> roundTripTimeVariance += diff / 4;
peer -> roundTripTime += diff / 8;
peer -> roundTripTimeVariance += (diff + 3) / 4;
peer -> roundTripTime += (diff + 7) / 8;
}
else
{
enet_uint32 diff = peer -> roundTripTime - roundTripTime;
peer -> roundTripTimeVariance += diff / 4;
peer -> roundTripTime -= diff / 8;
peer -> roundTripTimeVariance += (diff + 3) / 4;
peer -> roundTripTime -= (diff + 7) / 8;
}
}
else
@@ -921,8 +934,7 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer *
break;
case ENET_PEER_STATE_DISCONNECT_LATER:
if (enet_list_empty (& peer -> outgoingCommands) &&
enet_list_empty (& peer -> sentReliableCommands))
if (! enet_peer_has_outgoing_commands (peer))
enet_peer_disconnect (peer, peer -> eventData);
break;
@@ -1031,9 +1043,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (peer -> state == ENET_PEER_STATE_DISCONNECTED ||
peer -> state == ENET_PEER_STATE_ZOMBIE ||
((host -> receivedAddress.host != peer -> address.host ||
host -> receivedAddress.port != peer -> address.port) &&
peer -> address.host != ENET_HOST_BROADCAST) ||
/* ! enet_address_equal(& host -> receivedAddress, & peer -> address) || */
(peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
sessionID != peer -> incomingSessionID))
return 0;
@@ -1075,8 +1085,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (peer != NULL)
{
peer -> address.host = host -> receivedAddress.host;
peer -> address.port = host -> receivedAddress.port;
memcpy(& peer -> address, & host -> receivedPeerAddress, sizeof (host -> receivedPeerAddress));
memcpy(& peer -> localAddress, & host -> receivedLocalAddress, sizeof (host -> receivedLocalAddress));
peer -> incomingDataTotal += host -> receivedDataLength;
}
@@ -1227,10 +1237,14 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event)
buffer.dataLength = sizeof (host -> packetData [0]);
receivedLength = enet_socket_receive (host -> socket,
& host -> receivedAddress,
& host -> receivedPeerAddress,
& host -> receivedLocalAddress,
& buffer,
1);
if (receivedLength == -2)
continue;
if (receivedLength < 0)
return -1;
@@ -1294,7 +1308,7 @@ enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer)
buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] ||
peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge))
{
host -> continueSending = 1;
peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING;
break;
}
@@ -1334,10 +1348,12 @@ static int
enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event)
{
ENetOutgoingCommand * outgoingCommand;
ENetListIterator currentCommand, insertPosition;
ENetListIterator currentCommand, insertPosition, insertSendReliablePosition;
enet_uint32 roundTripTimeout;
currentCommand = enet_list_begin (& peer -> sentReliableCommands);
insertPosition = enet_list_begin (& peer -> outgoingCommands);
insertSendReliablePosition = enet_list_begin (& peer -> outgoingSendReliableCommands);
while (currentCommand != enet_list_end (& peer -> sentReliableCommands))
{
@@ -1354,7 +1370,7 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even
if (peer -> earliestTimeout != 0 &&
(ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMaximum ||
(outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit &&
((1U << (outgoingCommand -> sendAttempts - 1)) >= peer -> timeoutLimit &&
ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= peer -> timeoutMinimum)))
{
enet_protocol_notify_disconnect (host, peer, event);
@@ -1362,13 +1378,22 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even
return 1;
}
if (outgoingCommand -> packet != NULL)
peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
++ peer -> packetsLost;
outgoingCommand -> roundTripTimeout *= 2;
roundTripTimeout = peer -> roundTripTime + ENET_MIN (peer -> roundTripTime, 4 * ENET_MAX (1, peer -> roundTripTimeVariance));
roundTripTimeout = ENET_MIN (roundTripTimeout, peer->timeoutMaximum / 5);
if (outgoingCommand -> sendAttempts < peer -> timeoutLimit)
outgoingCommand -> roundTripTimeout = roundTripTimeout * ENET_MAX (1, outgoingCommand -> sendAttempts);
else
outgoingCommand -> roundTripTimeout = roundTripTimeout * peer -> timeoutLimit;
if (outgoingCommand -> packet != NULL)
{
peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
enet_list_insert (insertSendReliablePosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
}
else
enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) &&
@@ -1384,56 +1409,71 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even
}
static int
enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer, ENetList * sentUnreliableCommands)
{
ENetProtocol * command = & host -> commands [host -> commandCount];
ENetBuffer * buffer = & host -> buffers [host -> bufferCount];
ENetOutgoingCommand * outgoingCommand;
ENetListIterator currentCommand;
ENetListIterator currentCommand, currentSendReliableCommand;
ENetChannel *channel = NULL;
enet_uint16 reliableWindow = 0;
size_t commandSize;
int windowExceeded = 0, windowWrap = 0, canPing = 1;
int windowWrap = 0, canPing = 1;
currentCommand = enet_list_begin (& peer -> outgoingCommands);
currentSendReliableCommand = enet_list_begin (& peer -> outgoingSendReliableCommands);
while (currentCommand != enet_list_end (& peer -> outgoingCommands))
for (;;)
{
if (currentCommand != enet_list_end (& peer -> outgoingCommands))
{
outgoingCommand = (ENetOutgoingCommand *) currentCommand;
if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands) &&
ENET_TIME_LESS (((ENetOutgoingCommand *) currentSendReliableCommand) -> queueTime, outgoingCommand -> queueTime))
goto useSendReliableCommand;
currentCommand = enet_list_next (currentCommand);
}
else
if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands))
{
useSendReliableCommand:
outgoingCommand = (ENetOutgoingCommand *) currentSendReliableCommand;
currentSendReliableCommand = enet_list_next (currentSendReliableCommand);
}
else
break;
if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
{
channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL;
reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
if (channel != NULL)
{
if (! windowWrap &&
outgoingCommand -> sendAttempts < 1 &&
if (windowWrap)
continue;
else
if (outgoingCommand -> sendAttempts < 1 &&
! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) &&
(channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE ||
channel -> usedReliableWindows & ((((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) << reliableWindow) |
(((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow)))))
windowWrap = 1;
if (windowWrap)
{
currentCommand = enet_list_next (currentCommand);
windowWrap = 1;
currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands);
continue;
}
}
if (outgoingCommand -> packet != NULL)
{
if (! windowExceeded)
{
enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE;
if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu))
windowExceeded = 1;
}
if (windowExceeded)
{
currentCommand = enet_list_next (currentCommand);
currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands);
continue;
}
@@ -1449,13 +1489,11 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
(outgoingCommand -> packet != NULL &&
(enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength)))
{
host -> continueSending = 1;
peer -> flags |= ENET_PEER_FLAG_CONTINUE_SENDING;
break;
}
currentCommand = enet_list_next (currentCommand);
if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
{
if (channel != NULL && outgoingCommand -> sendAttempts < 1)
@@ -1466,10 +1504,9 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
++ outgoingCommand -> sendAttempts;
if (outgoingCommand -> roundTripTimeout == 0)
{
outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance;
outgoingCommand -> roundTripTimeoutLimit = peer -> timeoutLimit * outgoingCommand -> roundTripTimeout;
if (outgoingCommand -> roundTripTimeout == 0) {
outgoingCommand -> roundTripTimeout = peer -> roundTripTime + ENET_MIN (peer -> roundTripTime, 4 * ENET_MAX (1, peer -> roundTripTimeVariance));
outgoingCommand -> roundTripTimeout = ENET_MIN (outgoingCommand -> roundTripTimeout, peer->timeoutMaximum / 5);
}
if (enet_list_empty (& peer -> sentReliableCommands))
@@ -1523,7 +1560,7 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
enet_list_remove (& outgoingCommand -> outgoingCommandList);
if (outgoingCommand -> packet != NULL)
enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand);
enet_list_insert (enet_list_end (sentUnreliableCommands), outgoingCommand);
}
buffer -> data = command;
@@ -1556,9 +1593,8 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
host -> bufferCount = buffer - host -> buffers;
if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
enet_list_empty (& peer -> outgoingCommands) &&
enet_list_empty (& peer -> sentReliableCommands) &&
enet_list_empty (& peer -> sentUnreliableCommands))
! enet_peer_has_outgoing_commands (peer) &&
enet_list_empty (sentUnreliableCommands))
enet_peer_disconnect (peer, peer -> eventData);
return canPing;
@@ -1569,22 +1605,24 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
{
enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)];
ENetProtocolHeader * header = (ENetProtocolHeader *) headerData;
ENetPeer * currentPeer;
int sentLength;
int sentLength = 0;
size_t shouldCompress = 0;
ENetList sentUnreliableCommands;
host -> continueSending = 1;
enet_list_clear (& sentUnreliableCommands);
while (host -> continueSending)
for (host -> continueSending = 0,
currentPeer = host -> peers;
for (int sendPass = 0, continueSending = 0; sendPass <= continueSending; ++ sendPass)
for (ENetPeer * currentPeer = host -> peers;
currentPeer < & host -> peers [host -> peerCount];
++ currentPeer)
{
if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED ||
currentPeer -> state == ENET_PEER_STATE_ZOMBIE)
currentPeer -> state == ENET_PEER_STATE_ZOMBIE ||
(sendPass > 0 && ! (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING)))
continue;
currentPeer -> flags &= ~ ENET_PEER_FLAG_CONTINUE_SENDING;
host -> headerFlags = 0;
host -> commandCount = 0;
host -> bufferCount = 1;
@@ -1601,21 +1639,22 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE)
return 1;
else
continue;
goto nextPeer;
}
if ((enet_list_empty (& currentPeer -> outgoingCommands) ||
enet_protocol_check_outgoing_commands (host, currentPeer)) &&
if (((enet_list_empty (& currentPeer -> outgoingCommands) &&
enet_list_empty (& currentPeer -> outgoingSendReliableCommands)) ||
enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands)) &&
enet_list_empty (& currentPeer -> sentReliableCommands) &&
ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval &&
currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing))
{
enet_peer_ping (currentPeer);
enet_protocol_check_outgoing_commands (host, currentPeer);
enet_protocol_check_outgoing_commands (host, currentPeer, & sentUnreliableCommands);
}
if (host -> commandCount == 0)
continue;
goto nextPeer;
if (currentPeer -> packetLossEpoch == 0)
currentPeer -> packetLossEpoch = host -> serviceTime;
@@ -1626,7 +1665,7 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent;
#ifdef ENET_DEBUG
printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0);
printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingCommands) + enet_list_size (& currentPeer -> outgoingSendReliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0);
#endif
currentPeer -> packetLossVariance = (currentPeer -> packetLossVariance * 3 + ENET_DIFFERENCE (packetLoss, currentPeer -> packetLoss)) / 4;
@@ -1686,20 +1725,61 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
currentPeer -> lastSendTime = host -> serviceTime;
sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount);
if ((currentPeer -> state == ENET_PEER_STATE_CONNECTING || currentPeer -> state == ENET_PEER_STATE_ACKNOWLEDGING_CONNECT) && currentPeer -> packetsLost == 3) {
// Disable QoS tagging if we don't get a response to 3 connection requests/acks in a row.
// Some networks drop QoS tagged packets, so let's try without it.
enet_socket_set_option (host -> socket, ENET_SOCKOPT_QOS, 0);
}
enet_protocol_remove_sent_unreliable_commands (currentPeer);
sentLength = enet_socket_send (host -> socket, & currentPeer -> address,
host -> wildcardBind ? (& currentPeer -> localAddress) : NULL,
host -> buffers, host -> bufferCount);
enet_protocol_remove_sent_unreliable_commands (currentPeer, & sentUnreliableCommands);
if (sentLength < 0)
return -1;
host -> totalSentData += sentLength;
host -> totalSentPackets ++;
nextPeer:
if (currentPeer -> flags & ENET_PEER_FLAG_CONTINUE_SENDING)
continueSending = sendPass + 1;
}
return 0;
}
static enet_uint32
enet_protocol_compute_wait_timeout(ENetHost * host, enet_uint32 timeout)
{
for (ENetPeer * currentPeer = host -> peers;
currentPeer < & host -> peers [host -> peerCount];
++ currentPeer)
{
if (! ENET_TIME_LESS (currentPeer -> nextTimeout, host -> serviceTime)) {
timeout = ENET_MIN (timeout, ENET_TIME_DIFFERENCE (currentPeer -> nextTimeout, host -> serviceTime) + 1);
}
if (currentPeer -> lastReceiveTime && currentPeer -> lastSendTime) {
enet_uint32 timeSinceLastRecv = ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime);
enet_uint32 timeSinceLastSend = ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastSendTime);
enet_uint32 timeSinceLastComm = ENET_MIN(timeSinceLastSend, timeSinceLastRecv);
if (timeSinceLastComm >= currentPeer -> pingInterval) {
// Ping is due now for this peer
return 0;
} else {
timeout = ENET_MIN (timeout, currentPeer -> pingInterval - timeSinceLastComm);
}
} else {
timeout = ENET_MIN (timeout, currentPeer -> pingInterval);
}
}
return timeout;
}
/** Sends any queued packets on the host specified to its designated peers.
@param host host to flush
@@ -1780,7 +1860,7 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout)
timeout += host -> serviceTime;
do
for (;;)
{
if (ENET_TIME_DIFFERENCE (host -> serviceTime, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
enet_host_bandwidth_throttle (host);
@@ -1857,20 +1937,26 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout)
do
{
enet_uint32 waitTime;
host -> serviceTime = enet_time_get ();
if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout))
return 0;
waitTime = enet_protocol_compute_wait_timeout(host, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime));
if (waitTime == 0)
break;
waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT;
if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0)
if (enet_socket_wait (host -> socket, & waitCondition, waitTime) != 0)
return -1;
}
while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT);
host -> serviceTime = enet_time_get ();
} while (waitCondition & ENET_SOCKET_WAIT_RECEIVE);
}
return 0;
}
+566 -196
View File
@@ -2,11 +2,21 @@
@file unix.c
@brief ENet Unix system specific functions
*/
#ifndef _WIN32
#if !defined(_WIN32) || defined(NXDK)
// Required for IPV6_PKTINFO with Darwin headers
#ifndef __APPLE_USE_RFC_3542
#define __APPLE_USE_RFC_3542 1
#endif
// Required for in6_pktinfo with glibc headers
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <netdb.h>
@@ -18,9 +28,12 @@
#define ENET_BUILDING_LIB 1
#include "enet/enet.h"
#ifdef __APPLE__
#ifdef HAS_POLL
#undef HAS_POLL
#if defined(__APPLE__)
#if !defined(IPV6_RECVPKTINFO) || !defined(IPV6_PKTINFO)
#warning Missing IPv6 socket option definitions. Is __APPLE_USE_RFC_3542 defined?
#endif
#ifndef HAS_POLL
#define HAS_POLL 1
#endif
#ifndef HAS_FCNTL
#define HAS_FCNTL 1
@@ -43,20 +56,146 @@
#ifndef HAS_GETNAMEINFO
#define HAS_GETNAMEINFO 1
#endif
#elif defined(__vita__)
// PS Vita: No support for ancillary data or advanced message control
#ifndef NO_MSGAPI
#define NO_MSGAPI 1
#endif
#ifndef HAS_INET_PTON
#define HAS_INET_PTON 1
#endif
#ifndef HAS_INET_NTOP
#define HAS_INET_NTOP 1
#endif
#ifndef HAS_SOCKLEN_T
#define HAS_SOCKLEN_T 1
#endif
#ifndef HAS_GETADDRINFO
#define HAS_GETADDRINFO 1
#endif
#ifndef HAS_GETNAMEINFO
#define HAS_GETNAMEINFO 1
#endif
#elif defined(__WIIU__)
#ifndef HAS_POLL
#define HAS_POLL 1
#endif
#ifndef HAS_FCNTL
#define HAS_FCNTL 1
#endif
#ifndef HAS_IOCTL
#define HAS_IOCTL 1
#endif
#ifndef HAS_INET_PTON
#define HAS_INET_PTON 1
#endif
#ifndef HAS_INET_NTOP
#define HAS_INET_NTOP 1
#endif
#ifndef HAS_SOCKLEN_T
#define HAS_SOCKLEN_T 1
#endif
#ifndef HAS_GETADDRINFO
#define HAS_GETADDRINFO 1
#endif
#ifndef HAS_GETNAMEINFO
#define HAS_GETNAMEINFO 1
#endif
#ifndef NO_MSGAPI
#define NO_MSGAPI 1
#endif
#elif defined(NXDK)
#ifndef HAS_POLL
#define HAS_POLL 1
#endif
#ifndef HAS_FCNTL
#define HAS_FCNTL 1
#endif
#ifndef HAS_IOCTL
#define HAS_IOCTL 1
#endif
#ifndef HAS_INET_PTON
#define HAS_INET_PTON 1
#endif
#ifndef HAS_INET_NTOP
#define HAS_INET_NTOP 1
#endif
#ifndef HAS_SOCKLEN_T
#define HAS_SOCKLEN_T 1
#endif
#ifndef HAS_GETADDRINFO
#define HAS_GETADDRINFO 1
#endif
#ifndef HAS_GETNAMEINFO
#define HAS_GETNAMEINFO 1
#endif
#ifndef NO_MSGAPI
#define NO_MSGAPI 1
#endif
#elif defined(__3DS__)
#ifdef AF_INET6
#undef AF_INET6
#endif
#ifndef HAS_POLL
#define HAS_POLL 1
#endif
#ifndef HAS_FCNTL
#define HAS_FCNTL 1
#endif
#ifndef HAS_IOCTL
#define HAS_IOCTL 1
#endif
#ifndef HAS_INET_PTON
#define HAS_INET_PTON 1
#endif
#ifndef HAS_INET_NTOP
#define HAS_INET_NTOP 1
#endif
#ifndef HAS_SOCKLEN_T
#define HAS_SOCKLEN_T 1
#endif
#ifndef HAS_GETADDRINFO
#define HAS_GETADDRINFO 1
#endif
#ifndef HAS_GETNAMEINFO
#define HAS_GETNAMEINFO 1
#endif
#ifndef NO_MSGAPI
#define NO_MSGAPI 1
#endif
#elif defined(__HAIKU__)
#ifndef HAS_POLL
#define HAS_POLL 1
#endif
#else
#ifndef HAS_IOCTL
#define HAS_IOCTL 1
#endif
#ifndef HAS_POLL
#define HAS_POLL 1
#endif
#endif
#ifdef HAS_FCNTL
#include <fcntl.h>
#endif
#ifdef HAS_IOCTL
#include <sys/ioctl.h>
#endif
#ifdef HAS_POLL
#include <poll.h>
#endif
#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) && !defined(__HAIKU__)
typedef int socklen_t;
#endif
#ifndef SOMAXCONN
#define SOMAXCONN 128
#endif
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
@@ -77,7 +216,11 @@ enet_deinitialize (void)
enet_uint32
enet_host_random_seed (void)
{
return (enet_uint32) time (NULL);
struct timeval timeVal;
gettimeofday (& timeVal, NULL);
return (timeVal.tv_sec * 1000) ^ (timeVal.tv_usec / 1000);
}
enet_uint32
@@ -100,187 +243,162 @@ enet_time_set (enet_uint32 newTimeBase)
timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase;
}
int
enet_address_set_host_ip (ENetAddress * address, const char * name)
#ifdef __APPLE__
void
enet_address_make_v4mapped (ENetAddress * address)
{
#ifdef HAS_INET_PTON
if (! inet_pton (AF_INET, name, & address -> host))
#else
if (! inet_aton (name, (struct in_addr *) & address -> host))
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
int
enet_address_equal (ENetAddress * address1, ENetAddress * address2)
{
if (address1 -> address.ss_family != address2 -> address.ss_family)
return 0;
switch (address1 -> address.ss_family)
{
case AF_INET:
{
struct sockaddr_in *sin1, *sin2;
sin1 = (struct sockaddr_in *) & address1 -> address;
sin2 = (struct sockaddr_in *) & address2 -> address;
return sin1 -> sin_port == sin2 -> sin_port &&
sin1 -> sin_addr.s_addr == sin2 -> sin_addr.s_addr;
}
#ifdef AF_INET6
case AF_INET6:
{
struct sockaddr_in6 *sin6a, *sin6b;
sin6a = (struct sockaddr_in6 *) & address1 -> address;
sin6b = (struct sockaddr_in6 *) & address2 -> address;
return sin6a -> sin6_port == sin6b -> sin6_port &&
! memcmp (& sin6a -> sin6_addr, & sin6b -> sin6_addr, sizeof (sin6a -> sin6_addr));
}
#endif
default:
{
return 0;
}
}
}
int
enet_address_wildcard (const ENetAddress * address)
{
switch (address -> address.ss_family)
{
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *) & address -> address;
return sin -> sin_addr.s_addr == INADDR_ANY;
}
#ifdef AF_INET6
case AF_INET6:
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) & address -> address;
return ! memcmp (& sin6 -> sin6_addr, & in6addr_any, sizeof (in6addr_any));
}
#endif
default:
{
return 0;
}
}
}
int
enet_address_set_port (ENetAddress * address, enet_uint16 port)
{
if (address -> address.ss_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *) &address -> address;
sin -> sin_port = ENET_HOST_TO_NET_16 (port);
return 0;
}
#ifdef AF_INET6
else if (address -> address.ss_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &address -> address;
sin6 -> sin6_port = ENET_HOST_TO_NET_16 (port);
return 0;
}
#endif
else
{
return -1;
}
}
int
enet_address_set_address (ENetAddress * address, struct sockaddr * addr, socklen_t addrlen)
{
if (addrlen > sizeof(struct sockaddr_storage))
return -1;
memcpy (&address->address, addr, addrlen);
address->addressLength = addrlen;
return 0;
}
int
enet_address_set_host (ENetAddress * address, const char * name)
{
#ifdef HAS_GETADDRINFO
struct addrinfo hints, * resultList = NULL, * result = NULL;
memset (& hints, 0, sizeof (hints));
hints.ai_family = AF_INET;
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_ADDRCONFIG;
if (getaddrinfo (name, NULL, NULL, & resultList) != 0)
if (getaddrinfo (name, NULL, & hints, & resultList) != 0)
return -1;
for (result = resultList; result != NULL; result = result -> ai_next)
{
if (result -> ai_family == AF_INET && result -> ai_addr != NULL && result -> ai_addrlen >= sizeof (struct sockaddr_in))
{
struct sockaddr_in * sin = (struct sockaddr_in *) result -> ai_addr;
address -> host = sin -> sin_addr.s_addr;
memcpy (& address -> address, result -> ai_addr, result -> ai_addrlen);
address -> addressLength = result -> ai_addrlen;
freeaddrinfo (resultList);
return 0;
}
}
if (resultList != NULL)
freeaddrinfo (resultList);
#else
struct hostent * hostEntry = NULL;
#ifdef HAS_GETHOSTBYNAME_R
struct hostent hostData;
char buffer [2048];
int errnum;
#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);
#endif
#else
hostEntry = gethostbyname (name);
#endif
if (hostEntry != NULL && hostEntry -> h_addrtype == AF_INET)
{
address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
return 0;
}
#endif
return enet_address_set_host_ip (address, name);
}
int
enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
{
#ifdef HAS_INET_NTOP
if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL)
#else
char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
if (addr != NULL)
{
size_t addrLen = strlen(addr);
if (addrLen >= nameLength)
return -1;
memcpy (name, addr, addrLen + 1);
}
else
#endif
return -1;
return 0;
}
int
enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
{
#ifdef HAS_GETNAMEINFO
struct sockaddr_in sin;
int err;
memset (& sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
err = getnameinfo ((struct sockaddr *) & sin, sizeof (sin), name, nameLength, NULL, 0, NI_NAMEREQD);
if (! err)
{
if (name != NULL && nameLength > 0 && ! memchr (name, '\0', nameLength))
return -1;
return 0;
}
if (err != EAI_NONAME)
return -1;
#else
struct in_addr in;
struct hostent * hostEntry = NULL;
#ifdef HAS_GETHOSTBYADDR_R
struct hostent hostData;
char buffer [2048];
int errnum;
in.s_addr = address -> host;
#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);
#endif
#else
in.s_addr = address -> host;
hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
#endif
if (hostEntry != NULL)
{
size_t hostLen = strlen (hostEntry -> h_name);
if (hostLen >= nameLength)
return -1;
memcpy (name, hostEntry -> h_name, hostLen + 1);
return 0;
}
#endif
return enet_address_get_host_ip (address, name, nameLength);
}
int
enet_socket_bind (ENetSocket socket, const ENetAddress * address)
{
struct sockaddr_in sin;
memset (& sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
if (address != NULL)
{
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
}
else
{
sin.sin_port = 0;
sin.sin_addr.s_addr = INADDR_ANY;
}
return bind (socket,
(struct sockaddr *) & sin,
sizeof (struct sockaddr_in));
(struct sockaddr *) & address -> address,
address -> addressLength);
}
int
enet_socket_get_address (ENetSocket socket, ENetAddress * address)
{
struct sockaddr_in sin;
socklen_t sinLength = sizeof (struct sockaddr_in);
address -> addressLength = sizeof (address -> address);
if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
if (getsockname (socket, (struct sockaddr *) & address -> address, & address -> addressLength) == -1)
return -1;
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
return 0;
}
@@ -291,9 +409,53 @@ enet_socket_listen (ENetSocket socket, int backlog)
}
ENetSocket
enet_socket_create (ENetSocketType type)
enet_socket_create (int af, ENetSocketType type)
{
return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
ENetSocket sock = socket (af, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
if (sock < 0) {
return sock;
}
#ifdef IPV6_V6ONLY
if (af == AF_INET6) {
int off = 0;
// Some OSes don't support dual-stack sockets, so ignore failures
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
}
#endif
#ifdef IP_PKTINFO
{
// We turn this on for all sockets because it may be required for IPv4
// traffic on dual-stack sockets on some OSes.
int on = 1;
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, (char *)&on, sizeof(on));
}
#elif defined(IP_RECVDSTADDR)
// FreeBSD uses IP_RECVDSTADDR instead of IP_PKTINFO when struct in_pktinfo is not available
{
int on = 1;
setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, (char *)&on, sizeof(on));
}
#endif
#ifdef IPV6_RECVPKTINFO
if (af == AF_INET6) {
int on = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on, sizeof(on));
}
#endif
#ifdef __WIIU__
{
// Enable usage of userbuffers on Wii U
int on = 1;
setsockopt(sock, SOL_SOCKET, SO_RUSRBUF, (char *)&on, sizeof(on));
}
#endif
return sock;
}
int
@@ -304,14 +466,14 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
{
case ENET_SOCKOPT_NONBLOCK:
#ifdef HAS_FCNTL
result = fcntl (socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl (socket, F_GETFL) & ~O_NONBLOCK));
result = fcntl (socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl (socket, F_GETFL, 0) & ~O_NONBLOCK));
#else
#ifdef HAS_IOCTL
result = ioctl (socket, FIONBIO, & value);
#else
result = setsockopt (socket, SOL_SOCKET, SO_NONBLOCK, (char *) & value, sizeof(int));
#endif
#endif
break;
case ENET_SOCKOPT_BROADCAST:
result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int));
break;
case ENET_SOCKOPT_REUSEADDR:
@@ -326,6 +488,7 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int));
break;
#if !defined(__WIIU__) && !defined(__3DS__)
case ENET_SOCKOPT_RCVTIMEO:
{
struct timeval timeVal;
@@ -343,11 +506,39 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & timeVal, sizeof (struct timeval));
break;
}
#endif
case ENET_SOCKOPT_NODELAY:
result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int));
break;
case ENET_SOCKOPT_QOS:
#ifdef SO_NET_SERVICE_TYPE
// iOS/macOS
value = value ? NET_SERVICE_TYPE_VO : NET_SERVICE_TYPE_BE;
result = setsockopt (socket, SOL_SOCKET, SO_NET_SERVICE_TYPE, (char *) & value, sizeof (int));
#endif
#ifdef IP_TOS
// UNIX - IPv4
value = value ? (46 << 2 | 0x01) : 0; // DSCP: Expedited Forwarding + ECT(1) (L4S)
result = setsockopt (socket, IPPROTO_IP, IP_TOS, (char *) & value, sizeof (int));
#endif
#ifdef IPV6_TCLASS
// UNIX - IPv6
value = value ? (46 << 2 | 0x01): 0; // DSCP: Expedited Forwarding + ECT(1) (L4S)
result = setsockopt (socket, IPPROTO_IPV6, IPV6_TCLASS, (char *) & value, sizeof (int));
#endif
#ifdef SO_PRIORITY
// Linux
value = value ? 6 : 0; // Max priority without NET_CAP_ADMIN
result = setsockopt (socket, SOL_SOCKET, SO_PRIORITY, (char *) & value, sizeof (int));
#endif
break;
case ENET_SOCKOPT_TTL:
result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int));
break;
default:
break;
}
@@ -366,6 +557,11 @@ enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
result = getsockopt (socket, SOL_SOCKET, SO_ERROR, value, & len);
break;
case ENET_SOCKOPT_TTL:
len = sizeof (int);
result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len);
break;
default:
break;
}
@@ -375,16 +571,9 @@ enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
int
enet_socket_connect (ENetSocket socket, const ENetAddress * address)
{
struct sockaddr_in sin;
int result;
memset (& sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
result = connect (socket, (struct sockaddr *) & address -> address, address -> addressLength);
if (result == -1 && errno == EINPROGRESS)
return 0;
@@ -395,22 +584,17 @@ ENetSocket
enet_socket_accept (ENetSocket socket, ENetAddress * address)
{
int result;
struct sockaddr_in sin;
socklen_t sinLength = sizeof (struct sockaddr_in);
if (address != NULL)
address -> addressLength = sizeof (address -> address);
result = accept (socket,
address != NULL ? (struct sockaddr *) & sin : NULL,
address != NULL ? & sinLength : NULL);
address != NULL ? (struct sockaddr *) & address -> address : NULL,
address != NULL ? & address -> addressLength : NULL);
if (result == -1)
return ENET_SOCKET_NULL;
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
}
return result;
}
@@ -429,64 +613,191 @@ enet_socket_destroy (ENetSocket socket)
int
enet_socket_send (ENetSocket socket,
const ENetAddress * address,
const ENetAddress * peerAddress,
const ENetAddress * localAddress,
const ENetBuffer * buffers,
size_t bufferCount)
{
struct msghdr msgHdr;
struct sockaddr_in sin;
int sentLength;
#ifdef NO_MSGAPI
void* sendBuffer;
size_t sendLength;
if (bufferCount > 1)
{
size_t i;
sendLength = 0;
for (i = 0; i < bufferCount; i++)
{
sendLength += buffers[i].dataLength;
}
sendBuffer = malloc (sendLength);
if (sendBuffer == NULL)
return -1;
sendLength = 0;
for (i = 0; i < bufferCount; i++)
{
memcpy (& ((unsigned char *)sendBuffer)[sendLength], buffers[i].data, buffers[i].dataLength);
sendLength += buffers[i].dataLength;
}
}
else
{
sendBuffer = buffers[0].data;
sendLength = buffers[0].dataLength;
}
sentLength = sendto (socket, sendBuffer, sendLength, MSG_NOSIGNAL,
(struct sockaddr *) & peerAddress -> address, peerAddress -> addressLength);
if (bufferCount > 1)
free(sendBuffer);
#else
struct msghdr msgHdr;
char controlBufData[1024];
memset (& msgHdr, 0, sizeof (struct msghdr));
if (address != NULL)
if (peerAddress != NULL)
{
memset (& sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
msgHdr.msg_name = & sin;
msgHdr.msg_namelen = sizeof (struct sockaddr_in);
msgHdr.msg_name = (void*) & peerAddress -> address;
msgHdr.msg_namelen = peerAddress -> addressLength;
}
msgHdr.msg_iov = (struct iovec *) buffers;
msgHdr.msg_iovlen = bufferCount;
// We always send traffic from the same local address as we last received
// from this peer to ensure it correctly recognizes our responses as
// coming from the expected host.
if (localAddress != NULL) {
#ifdef IP_PKTINFO
if (localAddress->address.ss_family == AF_INET) {
struct in_pktinfo pktInfo;
pktInfo.ipi_spec_dst = ((struct sockaddr_in*)&localAddress->address)->sin_addr;
pktInfo.ipi_ifindex = 0; // Unspecified
msgHdr.msg_control = controlBufData;
msgHdr.msg_controllen = CMSG_SPACE(sizeof(pktInfo));
struct cmsghdr *chdr = CMSG_FIRSTHDR(&msgHdr);
chdr->cmsg_level = IPPROTO_IP;
chdr->cmsg_type = IP_PKTINFO;
chdr->cmsg_len = CMSG_LEN(sizeof(pktInfo));
memcpy(CMSG_DATA(chdr), &pktInfo, sizeof(pktInfo));
}
#elif defined(IP_SENDSRCADDR)
// FreeBSD uses IP_SENDSRCADDR with struct in_addr instead of IP_PKTINFO
if (localAddress->address.ss_family == AF_INET) {
struct in_addr srcAddr = ((struct sockaddr_in*)&localAddress->address)->sin_addr;
msgHdr.msg_control = controlBufData;
msgHdr.msg_controllen = CMSG_SPACE(sizeof(srcAddr));
struct cmsghdr *chdr = CMSG_FIRSTHDR(&msgHdr);
chdr->cmsg_level = IPPROTO_IP;
chdr->cmsg_type = IP_SENDSRCADDR;
chdr->cmsg_len = CMSG_LEN(sizeof(srcAddr));
memcpy(CMSG_DATA(chdr), &srcAddr, sizeof(srcAddr));
}
#endif
#ifdef IPV6_PKTINFO
if (localAddress->address.ss_family == AF_INET6) {
struct in6_pktinfo pktInfo;
pktInfo.ipi6_addr = ((struct sockaddr_in6*)&localAddress->address)->sin6_addr;
pktInfo.ipi6_ifindex = 0; // Unspecified
msgHdr.msg_control = controlBufData;
msgHdr.msg_controllen = CMSG_SPACE(sizeof(pktInfo));
struct cmsghdr *chdr = CMSG_FIRSTHDR(&msgHdr);
chdr->cmsg_level = IPPROTO_IPV6;
chdr->cmsg_type = IPV6_PKTINFO;
chdr->cmsg_len = CMSG_LEN(sizeof(pktInfo));
memcpy(CMSG_DATA(chdr), &pktInfo, sizeof(pktInfo));
}
#endif
}
sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL);
#endif
if (sentLength == -1)
{
if (errno == EWOULDBLOCK)
switch (errno)
{
case EWOULDBLOCK:
return 0;
// These errors are treated as possible transient
// conditions that could be caused by a network
// interruption. We'll ignore them and allow the
// socket timeout to kill us if the connection
// is permanently interrupted.
case EADDRNOTAVAIL:
case ENETDOWN:
case ENETUNREACH:
#if !defined(EHOSTDOWN) || (EHOSTDOWN != EHOSTUNREACH)
case EHOSTDOWN:
#endif
case EHOSTUNREACH:
return 0;
default:
return -1;
}
}
return sentLength;
}
int
enet_socket_receive (ENetSocket socket,
ENetAddress * address,
ENetAddress * peerAddress,
ENetAddress * localAddress,
ENetBuffer * buffers,
size_t bufferCount)
{
struct msghdr msgHdr;
struct sockaddr_in sin;
int recvLength;
#ifdef NO_MSGAPI
// This will ONLY work with a single buffer!
peerAddress -> addressLength = sizeof (peerAddress -> address);
recvLength = recvfrom (socket, buffers[0].data, buffers[0].dataLength, MSG_NOSIGNAL,
(struct sockaddr *) & peerAddress -> address, & peerAddress -> addressLength);
if (recvLength == -1)
{
if (errno == EWOULDBLOCK)
return 0;
return -1;
}
return recvLength;
#else
struct msghdr msgHdr;
char controlBufData[1024];
memset (& msgHdr, 0, sizeof (struct msghdr));
if (address != NULL)
if (peerAddress != NULL)
{
msgHdr.msg_name = & sin;
msgHdr.msg_namelen = sizeof (struct sockaddr_in);
msgHdr.msg_name = & peerAddress -> address;
msgHdr.msg_namelen = sizeof (peerAddress -> address);
}
msgHdr.msg_iov = (struct iovec *) buffers;
msgHdr.msg_iovlen = bufferCount;
msgHdr.msg_control = controlBufData;
msgHdr.msg_controllen = sizeof(controlBufData);
recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL);
@@ -500,16 +811,65 @@ enet_socket_receive (ENetSocket socket,
#ifdef HAS_MSGHDR_FLAGS
if (msgHdr.msg_flags & MSG_TRUNC)
return -1;
return -2;
#endif
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
// Retrieve the local address that this traffic was received on
// to ensure we respond from the correct address/interface.
if (localAddress != NULL) {
for (struct cmsghdr *chdr = CMSG_FIRSTHDR(&msgHdr); chdr != NULL; chdr = CMSG_NXTHDR(&msgHdr, chdr)) {
#ifdef IP_PKTINFO
if (chdr->cmsg_level == IPPROTO_IP && chdr->cmsg_type == IP_PKTINFO) {
struct sockaddr_in *localAddr = (struct sockaddr_in*)&localAddress->address;
localAddr->sin_family = AF_INET;
localAddr->sin_addr = ((struct in_pktinfo*)CMSG_DATA(chdr))->ipi_addr;
localAddress->addressLength = sizeof(*localAddr);
break;
}
#elif defined(IP_RECVDSTADDR)
// FreeBSD uses IP_RECVDSTADDR with struct in_addr instead of IP_PKTINFO
if (chdr->cmsg_level == IPPROTO_IP && chdr->cmsg_type == IP_RECVDSTADDR) {
struct sockaddr_in *localAddr = (struct sockaddr_in*)&localAddress->address;
localAddr->sin_family = AF_INET;
localAddr->sin_addr = *((struct in_addr*)CMSG_DATA(chdr));
localAddress->addressLength = sizeof(*localAddr);
break;
}
#endif
#ifdef IPV6_PKTINFO
if (chdr->cmsg_level == IPPROTO_IPV6 && chdr->cmsg_type == IPV6_PKTINFO) {
struct sockaddr_in6 *localAddr = (struct sockaddr_in6*)&localAddress->address;
localAddr->sin6_family = AF_INET6;
localAddr->sin6_addr = ((struct in6_pktinfo*)CMSG_DATA(chdr))->ipi6_addr;
localAddress->addressLength = sizeof(*localAddr);
break;
}
#endif
}
}
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().
// Strangely, this only happens when the socket is bound, and IPV6_PKTINFO properly returns v4-mapped
// addresses in the same call. This is probably a kernel bug, so we fix it up here.
if (peerAddress -> address.ss_family == AF_INET && localAddress -> address.ss_family == AF_INET6) {
enet_address_make_v4mapped(peerAddress);
}
#endif
}
return recvLength;
#endif
}
int
@@ -539,7 +899,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)
{
@@ -612,4 +983,3 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou
}
#endif
+448 -157
View File
@@ -2,179 +2,260 @@
@file win32.c
@brief ENet Win32 system specific functions
*/
#ifdef _WIN32
#if defined(_WIN32) && !defined(NXDK)
#define ENET_BUILDING_LIB 1
#include "enet/enet.h"
#include <windows.h>
#include <mmsystem.h>
#include <mswsock.h>
#ifndef HAS_QOS_FLOWID
typedef UINT32 QOS_FLOWID;
#endif
#ifndef HAS_PQOS_FLOWID
typedef UINT32 *PQOS_FLOWID;
#endif
#include <qos2.h>
#ifndef QOS_NON_ADAPTIVE_FLOW
#define QOS_NON_ADAPTIVE_FLOW 0x00000002
#endif
static enet_uint32 timeBase = 0;
#if !(defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP)
# define HAS_QWAVE
# include <versionhelpers.h>
#else
# define IsWindows10OrGreater() TRUE
#endif
#ifdef HAS_QWAVE
static HANDLE qosHandle = INVALID_HANDLE_VALUE;
static QOS_FLOWID qosFlowId;
static BOOL qosAddedFlow;
static HMODULE QwaveLibraryHandle;
BOOL (WINAPI *pfnQOSCreateHandle)(PQOS_VERSION Version, PHANDLE QOSHandle);
BOOL (WINAPI *pfnQOSCloseHandle)(HANDLE QOSHandle);
BOOL (WINAPI *pfnQOSAddSocketToFlow)(HANDLE QOSHandle, SOCKET Socket, PSOCKADDR DestAddr, QOS_TRAFFIC_TYPE TrafficType, DWORD Flags, PQOS_FLOWID FlowId);
#endif
static BOOL enableEcn;
static LPFN_WSARECVMSG pfnWSARecvMsg;
int
enet_initialize (void)
{
WORD versionRequested = MAKEWORD (1, 1);
WORD versionRequested = MAKEWORD (2, 0);
WSADATA wsaData;
if (WSAStartup (versionRequested, & wsaData))
return -1;
if (LOBYTE (wsaData.wVersion) != 1||
HIBYTE (wsaData.wVersion) != 1)
if (LOBYTE (wsaData.wVersion) != 2||
HIBYTE (wsaData.wVersion) != 0)
{
WSACleanup ();
return -1;
}
timeBeginPeriod (1);
#ifdef HAS_QWAVE
QwaveLibraryHandle = LoadLibraryA("qwave.dll");
if (QwaveLibraryHandle != NULL) {
pfnQOSCreateHandle = (void*)GetProcAddress(QwaveLibraryHandle, "QOSCreateHandle");
pfnQOSCloseHandle = (void*)GetProcAddress(QwaveLibraryHandle, "QOSCloseHandle");
pfnQOSAddSocketToFlow = (void*)GetProcAddress(QwaveLibraryHandle, "QOSAddSocketToFlow");
if (pfnQOSCreateHandle == NULL || pfnQOSCloseHandle == NULL || pfnQOSAddSocketToFlow == NULL) {
pfnQOSCreateHandle = NULL;
pfnQOSCloseHandle = NULL;
pfnQOSAddSocketToFlow = NULL;
FreeLibrary(QwaveLibraryHandle);
QwaveLibraryHandle = NULL;
}
}
#endif
return 0;
}
void
enet_deinitialize (void)
{
timeEndPeriod (1);
#ifdef HAS_QWAVE
qosAddedFlow = FALSE;
qosFlowId = 0;
enableEcn = FALSE;
if (qosHandle != INVALID_HANDLE_VALUE)
{
pfnQOSCloseHandle(qosHandle);
qosHandle = INVALID_HANDLE_VALUE;
}
if (QwaveLibraryHandle != NULL) {
pfnQOSCreateHandle = NULL;
pfnQOSCloseHandle = NULL;
pfnQOSAddSocketToFlow = NULL;
FreeLibrary(QwaveLibraryHandle);
QwaveLibraryHandle = NULL;
}
#endif
WSACleanup ();
}
enet_uint32
enet_host_random_seed (void)
{
return (enet_uint32) timeGetTime ();
return (enet_uint32) GetTickCount ();
}
enet_uint32
enet_time_get (void)
{
return (enet_uint32) timeGetTime () - timeBase;
return (enet_uint32) GetTickCount () - timeBase;
}
void
enet_time_set (enet_uint32 newTimeBase)
{
timeBase = (enet_uint32) timeGetTime () - newTimeBase;
timeBase = (enet_uint32) GetTickCount () - newTimeBase;
}
int
enet_address_set_host_ip (ENetAddress * address, const char * name)
enet_address_set_port (ENetAddress * address, enet_uint16 port)
{
enet_uint8 vals [4] = { 0, 0, 0, 0 };
int i;
for (i = 0; i < 4; ++ i)
if (address -> address.ss_family == AF_INET)
{
const char * next = name + 1;
if (* name != '0')
{
long val = strtol (name, (char **) & next, 10);
if (val < 0 || val > 255 || next == name || next - name > 3)
return -1;
vals [i] = (enet_uint8) val;
}
if (* next != (i < 3 ? '.' : '\0'))
return -1;
name = next + 1;
}
memcpy (& address -> host, vals, sizeof (enet_uint32));
struct sockaddr_in *sin = (struct sockaddr_in *) &address -> address;
sin -> sin_port = ENET_HOST_TO_NET_16 (port);
return 0;
}
else if (address -> address.ss_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &address -> address;
sin6 -> sin6_port = ENET_HOST_TO_NET_16 (port);
return 0;
}
else
{
return -1;
}
}
int
enet_address_set_address (ENetAddress * address, struct sockaddr * addr, socklen_t addrlen)
{
if (addrlen > sizeof(struct sockaddr_storage))
return -1;
memcpy (&address->address, addr, addrlen);
address->addressLength = addrlen;
return 0;
}
int
enet_address_equal (ENetAddress * address1, ENetAddress * address2)
{
if (address1 -> address.ss_family != address2 -> address.ss_family)
return 0;
switch (address1 -> address.ss_family)
{
case AF_INET:
{
struct sockaddr_in *sin1, *sin2;
sin1 = (struct sockaddr_in *) & address1 -> address;
sin2 = (struct sockaddr_in *) & address2 -> address;
return sin1 -> sin_port == sin2 -> sin_port &&
sin1 -> sin_addr.S_un.S_addr == sin2 -> sin_addr.S_un.S_addr;
}
case AF_INET6:
{
struct sockaddr_in6 *sin6a, *sin6b;
sin6a = (struct sockaddr_in6 *) & address1 -> address;
sin6b = (struct sockaddr_in6 *) & address2 -> address;
return sin6a -> sin6_port == sin6b -> sin6_port &&
! memcmp (& sin6a -> sin6_addr, & sin6b -> sin6_addr, sizeof (sin6a -> sin6_addr));
}
default:
{
return 0;
}
}
}
int
enet_address_wildcard (const ENetAddress * address)
{
switch (address -> address.ss_family)
{
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *) & address -> address;
return sin -> sin_addr.S_un.S_addr == INADDR_ANY;
}
case AF_INET6:
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) & address -> address;
return ! memcmp (& sin6 -> sin6_addr, & in6addr_any, sizeof (in6addr_any));
}
default:
{
return 0;
}
}
}
int
enet_address_set_host (ENetAddress * address, const char * name)
{
struct hostent * hostEntry;
struct addrinfo hints, * resultList = NULL, * result = NULL;
hostEntry = gethostbyname (name);
if (hostEntry == NULL ||
hostEntry -> h_addrtype != AF_INET)
return enet_address_set_host_ip (address, name);
memset (& hints, 0, sizeof (hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_ADDRCONFIG;
address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
if (getaddrinfo (name, NULL, & hints, & resultList) != 0)
return -1;
for (result = resultList; result != NULL; result = result -> ai_next)
{
memcpy (& address -> address, result -> ai_addr, result -> ai_addrlen);
address -> addressLength = result -> ai_addrlen;
freeaddrinfo (resultList);
return 0;
}
int
enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
{
char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
if (addr == NULL)
return -1;
else
{
size_t addrLen = strlen(addr);
if (addrLen >= nameLength)
return -1;
memcpy (name, addr, addrLen + 1);
}
return 0;
}
int
enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
{
struct in_addr in;
struct hostent * hostEntry;
in.s_addr = address -> host;
hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
if (hostEntry == NULL)
return enet_address_get_host_ip (address, name, nameLength);
else
{
size_t hostLen = strlen (hostEntry -> h_name);
if (hostLen >= nameLength)
return -1;
memcpy (name, hostEntry -> h_name, hostLen + 1);
}
return 0;
if (resultList != NULL)
freeaddrinfo (resultList);
return -1;
}
int
enet_socket_bind (ENetSocket socket, const ENetAddress * address)
{
struct sockaddr_in sin;
memset (& sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
if (address != NULL)
{
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
}
else
{
sin.sin_port = 0;
sin.sin_addr.s_addr = INADDR_ANY;
}
return bind (socket,
(struct sockaddr *) & sin,
sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
(struct sockaddr *) & address -> address,
address -> addressLength);
}
int
enet_socket_get_address (ENetSocket socket, ENetAddress * address)
{
struct sockaddr_in sin;
int sinLength = sizeof (struct sockaddr_in);
address -> addressLength = sizeof (address -> address);
if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
if (getsockname (socket, (struct sockaddr *) & address -> address, & address -> addressLength) == -1)
return -1;
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
return 0;
}
@@ -185,9 +266,48 @@ enet_socket_listen (ENetSocket socket, int backlog)
}
ENetSocket
enet_socket_create (ENetSocketType type)
enet_socket_create (int af, ENetSocketType type)
{
return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
SOCKET sock = socket (af, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
return INVALID_SOCKET;
DWORD bytesReturned;
GUID wsaRecvMsgGuid = WSAID_WSARECVMSG;
if (WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaRecvMsgGuid, sizeof(wsaRecvMsgGuid),
&pfnWSARecvMsg, sizeof(pfnWSARecvMsg), &bytesReturned, NULL, NULL) == SOCKET_ERROR) {
closesocket(sock);
return INVALID_SOCKET;
}
BOOL val;
// Enable dual-stack operation for IPv6 sockets
if (af == AF_INET6) {
val = FALSE;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
closesocket(sock);
return INVALID_SOCKET;
}
}
// Enable returning local address info for IPv4 and dual-stack sockets
val = TRUE;
if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
closesocket(sock);
return INVALID_SOCKET;
}
// Enable returning local address info for IPv6 and dual-stack sockets
if (af == AF_INET6) {
val = TRUE;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, (char*)&val, sizeof(val)) == SOCKET_ERROR) {
closesocket(sock);
return INVALID_SOCKET;
}
}
return sock;
}
int
@@ -203,10 +323,6 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
break;
}
case ENET_SOCKOPT_BROADCAST:
result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int));
break;
case ENET_SOCKOPT_REUSEADDR:
result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int));
break;
@@ -231,6 +347,40 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int));
break;
case ENET_SOCKOPT_QOS:
{
// Enable ECN marking on Windows 10 if QOS is enabled
enableEcn = value != 0 && IsWindows10OrGreater();
#ifdef HAS_QWAVE
if (value)
{
QOS_VERSION qosVersion;
qosVersion.MajorVersion = 1;
qosVersion.MinorVersion = 0;
if (pfnQOSCreateHandle == NULL || !pfnQOSCreateHandle(&qosVersion, &qosHandle))
{
qosHandle = INVALID_HANDLE_VALUE;
}
}
else if (qosHandle != INVALID_HANDLE_VALUE)
{
pfnQOSCloseHandle(qosHandle);
qosHandle = INVALID_HANDLE_VALUE;
}
qosAddedFlow = FALSE;
qosFlowId = 0;
#endif
result = 0;
break;
}
case ENET_SOCKOPT_TTL:
result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int));
break;
default:
break;
}
@@ -248,6 +398,11 @@ enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
result = getsockopt (socket, SOL_SOCKET, SO_ERROR, (char *) value, & len);
break;
case ENET_SOCKOPT_TTL:
len = sizeof(int);
result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len);
break;
default:
break;
}
@@ -257,16 +412,9 @@ enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
int
enet_socket_connect (ENetSocket socket, const ENetAddress * address)
{
struct sockaddr_in sin;
int result;
memset (& sin, 0, sizeof (struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
result = connect (socket, (struct sockaddr *) & address -> address, address -> addressLength);
if (result == SOCKET_ERROR && WSAGetLastError () != WSAEWOULDBLOCK)
return -1;
@@ -276,22 +424,17 @@ enet_socket_connect (ENetSocket socket, const ENetAddress * address)
ENetSocket
enet_socket_accept (ENetSocket socket, ENetAddress * address)
{
SOCKET result;
struct sockaddr_in sin;
int sinLength = sizeof (struct sockaddr_in);
result = accept (socket,
address != NULL ? (struct sockaddr *) & sin : NULL,
address != NULL ? & sinLength : NULL);
if (result == INVALID_SOCKET)
return ENET_SOCKET_NULL;
int result;
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
}
address -> addressLength = sizeof (address -> address);
result = accept (socket,
address != NULL ? (struct sockaddr *) & address -> address : NULL,
address != NULL ? & address -> addressLength : NULL);
if (result == -1)
return ENET_SOCKET_NULL;
return result;
}
@@ -311,59 +454,185 @@ enet_socket_destroy (ENetSocket socket)
int
enet_socket_send (ENetSocket socket,
const ENetAddress * address,
const ENetAddress * peerAddress,
const ENetAddress * localAddress,
const ENetBuffer * buffers,
size_t bufferCount)
{
struct sockaddr_in sin;
DWORD sentLength = 0;
DWORD sentLength;
WSAMSG msg = { 0 };
char controlBufData[1024];
PWSACMSGHDR chdr = NULL;
if (address != NULL)
#ifdef HAS_QWAVE
if (!qosAddedFlow && qosHandle != INVALID_HANDLE_VALUE)
{
memset (& sin, 0, sizeof (struct sockaddr_in));
BOOL isV4MappedV6Addr =
peerAddress->address.ss_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((PSOCKADDR_IN6)&peerAddress->address)->sin6_addr);
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
// qWAVE doesn't properly support IPv4-mapped IPv6 addresses, nor does it
// correctly support IPv4 addresses on a dual-stack socket (despite MSDN's
// claims to the contrary). To get proper QoS tagging when hosting in dual
// stack mode, we will temporarily connect() the socket to allow qWAVE to
// successfully initialize a flow, then disconnect it again so WSASendMsg()
// works later on.
if (isV4MappedV6Addr) {
connect(socket, (PSOCKADDR)&peerAddress->address, peerAddress->addressLength);
}
if (WSASendTo (socket,
(LPWSABUF) buffers,
(DWORD) bufferCount,
& sentLength,
qosFlowId = 0; // Must be initialized to 0
pfnQOSAddSocketToFlow(qosHandle,
socket,
isV4MappedV6Addr ? NULL : (struct sockaddr *)&peerAddress->address,
QOSTrafficTypeControl,
QOS_NON_ADAPTIVE_FLOW,
&qosFlowId);
if (isV4MappedV6Addr) {
SOCKADDR_IN6 empty = { 0 };
empty.sin6_family = AF_INET6;
connect(socket, (PSOCKADDR)&empty, sizeof(empty));
}
// Even if we failed, don't try again
qosAddedFlow = TRUE;
}
#endif
msg.name = (struct sockaddr *) & peerAddress -> address;
msg.namelen = peerAddress -> addressLength;
msg.lpBuffers = (LPWSABUF) buffers;
msg.dwBufferCount = (DWORD) bufferCount;
// We always send traffic from the same local address as we last received
// from this peer to ensure it correctly recognizes our responses as
// coming from the expected host.
if (localAddress != NULL) {
if (localAddress->address.ss_family == AF_INET) {
IN_PKTINFO pktInfo;
pktInfo.ipi_addr = ((PSOCKADDR_IN)&localAddress->address)->sin_addr;
pktInfo.ipi_ifindex = 0; // Unspecified
msg.Control.buf = controlBufData;
msg.Control.len += WSA_CMSG_SPACE(sizeof(pktInfo));
if (chdr == NULL) {
chdr = WSA_CMSG_FIRSTHDR(&msg);
}
else {
chdr = WSA_CMSG_NXTHDR(&msg, chdr);
}
chdr->cmsg_level = IPPROTO_IP;
chdr->cmsg_type = IP_PKTINFO;
chdr->cmsg_len = WSA_CMSG_LEN(sizeof(pktInfo));
memcpy(WSA_CMSG_DATA(chdr), &pktInfo, sizeof(pktInfo));
}
else if (localAddress->address.ss_family == AF_INET6) {
IN6_PKTINFO pktInfo;
pktInfo.ipi6_addr = ((PSOCKADDR_IN6)&localAddress->address)->sin6_addr;
pktInfo.ipi6_ifindex = 0; // Unspecified
msg.Control.buf = controlBufData;
msg.Control.len += WSA_CMSG_SPACE(sizeof(pktInfo));
if (chdr == NULL) {
chdr = WSA_CMSG_FIRSTHDR(&msg);
}
else {
chdr = WSA_CMSG_NXTHDR(&msg, chdr);
}
chdr->cmsg_level = IPPROTO_IPV6;
chdr->cmsg_type = IPV6_PKTINFO;
chdr->cmsg_len = WSA_CMSG_LEN(sizeof(pktInfo));
memcpy(WSA_CMSG_DATA(chdr), &pktInfo, sizeof(pktInfo));
}
}
// This is a bit of a hack because it's not really per-socket or
// per-destination, but it is fine for our current usage of ENet
// in Moonlight and Sunshine where only a single socket is used.
if (enableEcn) {
BOOL isV4MappedV6Addr =
peerAddress->address.ss_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((PSOCKADDR_IN6)&peerAddress->address)->sin6_addr);
msg.Control.buf = controlBufData;
msg.Control.len += WSA_CMSG_SPACE(sizeof(INT));
if (chdr == NULL) {
chdr = WSA_CMSG_FIRSTHDR(&msg);
}
else {
chdr = WSA_CMSG_NXTHDR(&msg, chdr);
}
if (peerAddress->address.ss_family == AF_INET || isV4MappedV6Addr) {
chdr->cmsg_level = IPPROTO_IP;
chdr->cmsg_type = IP_ECN;
}
else {
chdr->cmsg_level = IPPROTO_IPV6;
chdr->cmsg_type = IPV6_ECN;
}
chdr->cmsg_len = WSA_CMSG_LEN(sizeof(INT));
*(PINT)WSA_CMSG_DATA(chdr) = 0x01; // ECT(1) (L4S)
}
if (WSASendMsg (socket,
& msg,
0,
address != NULL ? (struct sockaddr *) & sin : NULL,
address != NULL ? sizeof (struct sockaddr_in) : 0,
& sentLength,
NULL,
NULL) == SOCKET_ERROR)
{
if (WSAGetLastError () == WSAEWOULDBLOCK)
switch (WSAGetLastError ())
{
case WSAEWOULDBLOCK:
return 0;
// These errors are treated as possible transient
// conditions that could be caused by a network
// interruption. We'll ignore them and allow the
// socket timeout to kill us if the connection
// is permanently interrupted.
case WSAEADDRNOTAVAIL:
case WSAENETDOWN:
case WSAENETUNREACH:
case WSAEHOSTDOWN:
case WSAEHOSTUNREACH:
return 0;
default:
return -1;
}
}
return (int) sentLength;
}
int
enet_socket_receive (ENetSocket socket,
ENetAddress * address,
ENetAddress * peerAddress,
ENetAddress * localAddress,
ENetBuffer * buffers,
size_t bufferCount)
{
INT sinLength = sizeof (struct sockaddr_in);
DWORD flags = 0,
recvLength = 0;
struct sockaddr_in sin;
DWORD recvLength;
WSAMSG msg = { 0 };
char controlBufData[1024];
if (WSARecvFrom (socket,
(LPWSABUF) buffers,
(DWORD) bufferCount,
msg.name = peerAddress != NULL ? (struct sockaddr *) & peerAddress -> address : NULL;
msg.namelen = peerAddress != NULL ? sizeof (peerAddress -> address) : 0;
msg.lpBuffers = (LPWSABUF) buffers;
msg.dwBufferCount = (DWORD) bufferCount;
msg.Control.buf = controlBufData;
msg.Control.len = sizeof(controlBufData);
if (pfnWSARecvMsg (socket,
& msg,
& recvLength,
& flags,
address != NULL ? (struct sockaddr *) & sin : NULL,
address != NULL ? & sinLength : NULL,
NULL,
NULL) == SOCKET_ERROR)
{
@@ -372,20 +641,42 @@ enet_socket_receive (ENetSocket socket,
case WSAEWOULDBLOCK:
case WSAECONNRESET:
return 0;
case WSAEMSGSIZE:
return -2;
}
return -1;
}
if (flags & MSG_PARTIAL)
return -1;
if (msg.dwFlags & MSG_PARTIAL)
return -2;
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
// Retrieve the local address that this traffic was received on
// to ensure we respond from the correct address/interface.
if (localAddress != NULL) {
for (PWSACMSGHDR chdr = WSA_CMSG_FIRSTHDR(&msg); chdr != NULL; chdr = WSA_CMSG_NXTHDR(&msg, chdr)) {
if (chdr->cmsg_level == IPPROTO_IP && chdr->cmsg_type == IP_PKTINFO) {
PSOCKADDR_IN localAddr = (PSOCKADDR_IN)&localAddress->address;
localAddr->sin_family = AF_INET;
localAddr->sin_addr = ((IN_PKTINFO*)WSA_CMSG_DATA(chdr))->ipi_addr;
localAddress->addressLength = sizeof(*localAddr);
break;
}
else if (chdr->cmsg_level == IPPROTO_IPV6 && chdr->cmsg_type == IPV6_PKTINFO) {
PSOCKADDR_IN6 localAddr = (PSOCKADDR_IN6)&localAddress->address;
localAddr->sin6_family = AF_INET6;
localAddr->sin6_addr = ((IN6_PKTINFO*)WSA_CMSG_DATA(chdr))->ipi6_addr;
localAddress->addressLength = sizeof(*localAddr);
break;
}
}
}
peerAddress->addressLength = msg.namelen;
return (int) recvLength;
}