├── .github
└── workflows
│ └── cmake.yml
├── .gitignore
├── CMakeLists.txt
├── ChangeLog
├── Doxyfile
├── DoxygenLayout.xml
├── LICENSE
├── Makefile.am
├── README
├── callbacks.c
├── compress.c
├── configure.ac
├── docs
├── FAQ.dox
├── design.dox
├── install.dox
├── license.dox
├── mainpage.dox
└── tutorial.dox
├── enet.dsp
├── enet_dll.cbp
├── host.c
├── include
└── enet
│ ├── callbacks.h
│ ├── enet.h
│ ├── list.h
│ ├── protocol.h
│ ├── time.h
│ ├── types.h
│ ├── unix.h
│ ├── utility.h
│ └── win32.h
├── libenet.pc.in
├── list.c
├── m4
└── .keep
├── packet.c
├── peer.c
├── premake4.lua
├── protocol.c
├── unix.c
└── win32.c
/.github/workflows/cmake.yml:
--------------------------------------------------------------------------------
1 | on: [push, pull_request]
2 |
3 | name: CMake
4 |
5 | jobs:
6 | cmake-build:
7 | name: CMake ${{ matrix.os }} ${{ matrix.build_type }}
8 | runs-on: ${{ matrix.os }}
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | os: ["ubuntu-latest", "windows-latest", "macos-latest"]
13 | build_type: ["Debug", "Release"]
14 | steps:
15 | - uses: actions/checkout@v3
16 |
17 | - name: Configure CMake
18 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
19 |
20 | - name: Build
21 | run: cmake --build ${{github.workspace}}/build --config ${{ matrix.build_type }}
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Potential build directories
2 | [Aa][Rr][Mm]/
3 | [Aa][Rr][Mm]64/
4 | [Bb]in/
5 | [Dd]ebug/
6 | [Dd]ebugPublic/
7 | [Ll]og/
8 | [Ll]ogs/
9 | [Oo]bj/
10 | [Rr]elease/
11 | [Rr]eleases/
12 | [Ww][Ii][Nn]32/
13 | bld/
14 | build/
15 | builds/
16 | out/
17 | x64/
18 | x86/
19 |
20 | # VS
21 | .vs/
22 | .vscode/
23 | !.vscode/extensions.json
24 | !.vscode/launch.json
25 | !.vscode/settings.json
26 | !.vscode/tasks.json
27 |
28 | # CMake
29 | _deps
30 | CMakeCache.txt
31 | CMakeFiles
32 | CMakeLists.txt.user
33 | CMakeScripts
34 | CMakeUserPresets.json
35 | CTestTestfile.cmake
36 | cmake_install.cmake
37 | compile_commands.json
38 | install_manifest.txt
39 |
40 | # Prerequisites
41 | *.d
42 |
43 | # Object files
44 | *.o
45 | *.ko
46 | *.obj
47 | *.elf
48 |
49 | # Linker output
50 | *.ilk
51 | *.map
52 | *.exp
53 |
54 | # Libraries
55 | *.lib
56 | *.a
57 | *.la
58 | *.lo
59 |
60 | # Shared objects
61 | *.dll
62 | *.so
63 | *.so.*
64 | *.dylib
65 |
66 | # Debug files
67 | *.dSYM/
68 | *.su
69 | *.idb
70 | *.pdb
71 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.12...3.20)
2 |
3 | project(enet)
4 |
5 | # The "configure" step.
6 | include(CheckFunctionExists)
7 | include(CheckStructHasMember)
8 | include(CheckTypeSize)
9 | check_function_exists("fcntl" HAS_FCNTL)
10 | check_function_exists("poll" HAS_POLL)
11 | check_function_exists("getaddrinfo" HAS_GETADDRINFO)
12 | check_function_exists("getnameinfo" HAS_GETNAMEINFO)
13 | check_function_exists("gethostbyname_r" HAS_GETHOSTBYNAME_R)
14 | check_function_exists("gethostbyaddr_r" HAS_GETHOSTBYADDR_R)
15 | check_function_exists("inet_pton" HAS_INET_PTON)
16 | check_function_exists("inet_ntop" HAS_INET_NTOP)
17 | check_struct_has_member("struct msghdr" "msg_flags" "sys/types.h;sys/socket.h" HAS_MSGHDR_FLAGS)
18 | set(CMAKE_EXTRA_INCLUDE_FILES "sys/types.h" "sys/socket.h")
19 | check_type_size("socklen_t" HAS_SOCKLEN_T BUILTIN_TYPES_ONLY)
20 | unset(CMAKE_EXTRA_INCLUDE_FILES)
21 | if(MSVC)
22 | add_definitions(-W3)
23 | else()
24 | add_definitions(-Wno-error)
25 | endif()
26 |
27 | if(HAS_FCNTL)
28 | add_definitions(-DHAS_FCNTL=1)
29 | endif()
30 | if(HAS_POLL)
31 | add_definitions(-DHAS_POLL=1)
32 | endif()
33 | if(HAS_GETNAMEINFO)
34 | add_definitions(-DHAS_GETNAMEINFO=1)
35 | endif()
36 | if(HAS_GETADDRINFO)
37 | add_definitions(-DHAS_GETADDRINFO=1)
38 | endif()
39 | if(HAS_GETHOSTBYNAME_R)
40 | add_definitions(-DHAS_GETHOSTBYNAME_R=1)
41 | endif()
42 | if(HAS_GETHOSTBYADDR_R)
43 | add_definitions(-DHAS_GETHOSTBYADDR_R=1)
44 | endif()
45 | if(HAS_INET_PTON)
46 | add_definitions(-DHAS_INET_PTON=1)
47 | endif()
48 | if(HAS_INET_NTOP)
49 | add_definitions(-DHAS_INET_NTOP=1)
50 | endif()
51 | if(HAS_MSGHDR_FLAGS)
52 | add_definitions(-DHAS_MSGHDR_FLAGS=1)
53 | endif()
54 | if(HAS_SOCKLEN_T)
55 | add_definitions(-DHAS_SOCKLEN_T=1)
56 | endif()
57 |
58 | include_directories(${PROJECT_SOURCE_DIR}/include)
59 |
60 | set(INCLUDE_FILES_PREFIX include/enet)
61 | set(INCLUDE_FILES
62 | ${INCLUDE_FILES_PREFIX}/callbacks.h
63 | ${INCLUDE_FILES_PREFIX}/enet.h
64 | ${INCLUDE_FILES_PREFIX}/list.h
65 | ${INCLUDE_FILES_PREFIX}/protocol.h
66 | ${INCLUDE_FILES_PREFIX}/time.h
67 | ${INCLUDE_FILES_PREFIX}/types.h
68 | ${INCLUDE_FILES_PREFIX}/unix.h
69 | ${INCLUDE_FILES_PREFIX}/utility.h
70 | ${INCLUDE_FILES_PREFIX}/win32.h
71 | )
72 |
73 | set(SOURCE_FILES
74 | callbacks.c
75 | compress.c
76 | host.c
77 | list.c
78 | packet.c
79 | peer.c
80 | protocol.c
81 | unix.c
82 | win32.c)
83 |
84 | source_group(include FILES ${INCLUDE_FILES})
85 | source_group(source FILES ${SOURCE_FILES})
86 |
87 | if(WIN32 AND BUILD_SHARED_LIBS AND (MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
88 | add_definitions(-DENET_DLL=1)
89 | add_definitions(-DENET_BUILDING_LIB)
90 | endif()
91 |
92 | add_library(enet
93 | ${INCLUDE_FILES}
94 | ${SOURCE_FILES}
95 | )
96 |
97 | if (WIN32)
98 | target_link_libraries(enet winmm ws2_32)
99 | endif()
100 |
101 | include(GNUInstallDirs)
102 | install(TARGETS enet
103 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
104 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
105 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
106 | )
107 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/enet
108 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
109 | )
110 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
1 | ENet 1.3.18 (April 14, 2024):
2 |
3 | * Packet sending performance improvements
4 | * MTU negotiation fixes
5 | * Checksum alignment fix
6 | * No more dynamic initialization of checksum table
7 | * ENET_SOCKOPT_TTL
8 | * Other miscellaneous small improvements
9 |
10 | ENet 1.3.17 (November 15, 2020):
11 |
12 | * fixes for sender getting too far ahead of receiver that can cause instability with reliable packets
13 |
14 | ENet 1.3.16 (September 8, 2020):
15 |
16 | * fix bug in unreliable fragment queuing
17 | * use single output queue for reliable and unreliable packets for saner ordering
18 | * revert experimental throttle changes that were less stable than prior algorithm
19 |
20 | ENet 1.3.15 (April 20, 2020):
21 |
22 | * quicker RTT initialization
23 | * use fractional precision for RTT calculations
24 | * fixes for packet throttle with low RTT variance
25 | * miscellaneous socket bug fixes
26 |
27 | ENet 1.3.14 (January 27, 2019):
28 |
29 | * bug fix for enet_peer_disconnect_later()
30 | * use getaddrinfo and getnameinfo where available
31 | * miscellaneous cleanups
32 |
33 | ENet 1.3.13 (April 30, 2015):
34 |
35 | * miscellaneous bug fixes
36 | * added premake and cmake support
37 | * miscellaneous documentation cleanups
38 |
39 | ENet 1.3.12 (April 24, 2014):
40 |
41 | * added maximumPacketSize and maximumWaitingData fields to ENetHost to limit the amount of
42 | data waiting to be delivered on a peer (beware that the default maximumPacketSize is
43 | 32MB and should be set higher if desired as should maximumWaitingData)
44 |
45 | ENet 1.3.11 (December 26, 2013):
46 |
47 | * allow an ENetHost to connect to itself
48 | * fixed possible bug with disconnect notifications during connect attempts
49 | * fixed some preprocessor definition bugs
50 |
51 | ENet 1.3.10 (October 23, 2013);
52 |
53 | * doubled maximum reliable window size
54 | * fixed RCVTIMEO/SNDTIMEO socket options and also added NODELAY
55 |
56 | ENet 1.3.9 (August 19, 2013):
57 |
58 | * added duplicatePeers option to ENetHost which can limit the number of peers from duplicate IPs
59 | * added enet_socket_get_option() and ENET_SOCKOPT_ERROR
60 | * added enet_host_random_seed() platform stub
61 |
62 | ENet 1.3.8 (June 2, 2013):
63 |
64 | * added enet_linked_version() for checking the linked version
65 | * added enet_socket_get_address() for querying the local address of a socket
66 | * silenced some debugging prints unless ENET_DEBUG is defined during compilation
67 | * handle EINTR in enet_socket_wait() so that enet_host_service() doesn't propagate errors from signals
68 | * optimized enet_host_bandwidth_throttle() to be less expensive for large numbers of peers
69 |
70 | ENet 1.3.7 (March 6, 2013):
71 |
72 | * added ENET_PACKET_FLAG_SENT to indicate that a packet is being freed because it has been sent
73 | * added userData field to ENetPacket
74 | * changed how random seed is generated on Windows to avoid import warnings
75 | * fixed case where disconnects could be generated with no preceding connect event
76 |
77 | ENet 1.3.6 (December 11, 2012):
78 |
79 | * added support for intercept callback in ENetHost that can be used to process raw packets before ENet
80 | * added enet_socket_shutdown() for issuing shutdown on a socket
81 | * fixed enet_socket_connect() to not error on non-blocking connects
82 | * fixed bug in MTU negotiation during connections
83 |
84 | ENet 1.3.5 (July 31, 2012):
85 |
86 | * fixed bug in unreliable packet fragment queuing
87 |
88 | ENet 1.3.4 (May 29, 2012):
89 |
90 | * added enet_peer_ping_interval() for configuring per-peer ping intervals
91 | * added enet_peer_timeout() for configuring per-peer timeouts
92 | * added protocol packet size limits
93 |
94 | ENet 1.3.3 (June 28, 2011):
95 |
96 | * fixed bug with simultaneous disconnects not dispatching events
97 |
98 | ENet 1.3.2 (May 31, 2011):
99 |
100 | * added support for unreliable packet fragmenting via the packet flag
101 | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
102 | * fixed regression in unreliable packet queuing
103 | * added check against received port to limit some forms of IP-spoofing
104 |
105 | ENet 1.3.1 (February 10, 2011):
106 |
107 | * fixed bug in tracking of reliable data in transit
108 | * reliable data window size now scales with the throttle
109 | * fixed bug in fragment length calculation when checksums are used
110 |
111 | ENet 1.3.0 (June 5, 2010):
112 |
113 | * enet_host_create() now requires the channel limit to be specified as
114 | a parameter
115 | * enet_host_connect() now accepts a data parameter which is supplied
116 | to the receiving receiving host in the event data field for a connect event
117 | * added an adaptive order-2 PPM range coder as a built-in compressor option
118 | which can be set with enet_host_compress_with_range_coder()
119 | * added support for packet compression configurable with a callback
120 | * improved session number handling to not rely on the packet checksum
121 | field, saving 4 bytes per packet unless the checksum option is used
122 | * removed the dependence on the rand callback for session number handling
123 |
124 | Caveats: This version is not protocol compatible with the 1.2 series or
125 | earlier. The enet_host_connect and enet_host_create API functions require
126 | supplying additional parameters.
127 |
128 | ENet 1.2.5 (June 28, 2011):
129 |
130 | * fixed bug with simultaneous disconnects not dispatching events
131 |
132 | ENet 1.2.4 (May 31, 2011):
133 |
134 | * fixed regression in unreliable packet queuing
135 | * added check against received port to limit some forms of IP-spoofing
136 |
137 | ENet 1.2.3 (February 10, 2011):
138 |
139 | * fixed bug in tracking reliable data in transit
140 |
141 | ENet 1.2.2 (June 5, 2010):
142 |
143 | * checksum functionality is now enabled by setting a checksum callback
144 | inside ENetHost instead of being a configure script option
145 | * added totalSentData, totalSentPackets, totalReceivedData, and
146 | totalReceivedPackets counters inside ENetHost for getting usage
147 | statistics
148 | * added enet_host_channel_limit() for limiting the maximum number of
149 | channels allowed by connected peers
150 | * now uses dispatch queues for event dispatch rather than potentially
151 | unscalable array walking
152 | * added no_memory callback that is called when a malloc attempt fails,
153 | such that if no_memory returns rather than aborts (the default behavior),
154 | then the error is propagated to the return value of the API calls
155 | * now uses packed attribute for protocol structures on platforms with
156 | strange alignment rules
157 | * improved autoconf build system contributed by Nathan Brink allowing
158 | for easier building as a shared library
159 |
160 | Caveats: If you were using the compile-time option that enabled checksums,
161 | make sure to set the checksum callback inside ENetHost to enet_crc32 to
162 | regain the old behavior. The ENetCallbacks structure has added new fields,
163 | so make sure to clear the structure to zero before use if
164 | using enet_initialize_with_callbacks().
165 |
166 | ENet 1.2.1 (November 12, 2009):
167 |
168 | * fixed bug that could cause disconnect events to be dropped
169 | * added thin wrapper around select() for portable usage
170 | * added ENET_SOCKOPT_REUSEADDR socket option
171 | * factored enet_socket_bind()/enet_socket_listen() out of enet_socket_create()
172 | * added contributed Code::Blocks build file
173 |
174 | ENet 1.2 (February 12, 2008):
175 |
176 | * fixed bug in VERIFY_CONNECT acknowledgement that could cause connect
177 | attempts to occasionally timeout
178 | * fixed acknowledgements to check both the outgoing and sent queues
179 | when removing acknowledged packets
180 | * fixed accidental bit rot in the MSVC project file
181 | * revised sequence number overflow handling to address some possible
182 | disconnect bugs
183 | * added enet_host_check_events() for getting only local queued events
184 | * factored out socket option setting into enet_socket_set_option() so
185 | that socket options are now set separately from enet_socket_create()
186 |
187 | Caveats: While this release is superficially protocol compatible with 1.1,
188 | differences in the sequence number overflow handling can potentially cause
189 | random disconnects.
190 |
191 | ENet 1.1 (June 6, 2007):
192 |
193 | * optional CRC32 just in case someone needs a stronger checksum than UDP
194 | provides (--enable-crc32 configure option)
195 | * the size of packet headers are half the size they used to be (so less
196 | overhead when sending small packets)
197 | * enet_peer_disconnect_later() that waits till all queued outgoing
198 | packets get sent before issuing an actual disconnect
199 | * freeCallback field in individual packets for notification of when a
200 | packet is about to be freed
201 | * ENET_PACKET_FLAG_NO_ALLOCATE for supplying pre-allocated data to a
202 | packet (can be used in concert with freeCallback to support some custom
203 | allocation schemes that the normal memory allocation callbacks would
204 | normally not allow)
205 | * enet_address_get_host_ip() for printing address numbers
206 | * promoted the enet_socket_*() functions to be part of the API now
207 | * a few stability/crash fixes
208 |
209 |
210 |
--------------------------------------------------------------------------------
/DoxygenLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2002-2024 Lee Salzman
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | pkgconfigdir = $(libdir)/pkgconfig
2 | nodist_pkgconfig_DATA = libenet.pc
3 |
4 | enetincludedir=$(includedir)/enet
5 | enetinclude_HEADERS = \
6 | include/enet/callbacks.h \
7 | include/enet/enet.h \
8 | include/enet/list.h \
9 | include/enet/protocol.h \
10 | include/enet/time.h \
11 | include/enet/types.h \
12 | include/enet/unix.h \
13 | include/enet/utility.h \
14 | include/enet/win32.h
15 |
16 | lib_LTLIBRARIES = libenet.la
17 | libenet_la_SOURCES = callbacks.c compress.c host.c list.c packet.c peer.c protocol.c unix.c win32.c
18 | # see info '(libtool) Updating version info' before making a release
19 | libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 7:6:0
20 | AM_CPPFLAGS = -I$(top_srcdir)/include
21 |
22 | ACLOCAL_AMFLAGS = -Im4
23 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Please visit the ENet homepage at http://sauerbraten.org/enet/ for installation
2 | and usage instructions.
3 |
4 | If you obtained this package from github, the quick description on how to build
5 | is:
6 |
7 | # Generate the build system.
8 |
9 | autoreconf -vfi
10 |
11 | # Compile and install the library.
12 |
13 | ./configure && make && make install
14 |
15 |
16 |
--------------------------------------------------------------------------------
/callbacks.c:
--------------------------------------------------------------------------------
1 | /**
2 | @file callbacks.c
3 | @brief ENet callback functions
4 | */
5 | #define ENET_BUILDING_LIB 1
6 | #include "enet/enet.h"
7 |
8 | static ENetCallbacks callbacks = { malloc, free, abort };
9 |
10 | int
11 | enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits)
12 | {
13 | if (version < ENET_VERSION_CREATE (1, 3, 0))
14 | return -1;
15 |
16 | if (inits -> malloc != NULL || inits -> free != NULL)
17 | {
18 | if (inits -> malloc == NULL || inits -> free == NULL)
19 | return -1;
20 |
21 | callbacks.malloc = inits -> malloc;
22 | callbacks.free = inits -> free;
23 | }
24 |
25 | if (inits -> no_memory != NULL)
26 | callbacks.no_memory = inits -> no_memory;
27 |
28 | return enet_initialize ();
29 | }
30 |
31 | ENetVersion
32 | enet_linked_version (void)
33 | {
34 | return ENET_VERSION;
35 | }
36 |
37 | void *
38 | enet_malloc (size_t size)
39 | {
40 | void * memory = callbacks.malloc (size);
41 |
42 | if (memory == NULL)
43 | callbacks.no_memory ();
44 |
45 | return memory;
46 | }
47 |
48 | void
49 | enet_free (void * memory)
50 | {
51 | callbacks.free (memory);
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/compress.c:
--------------------------------------------------------------------------------
1 | /**
2 | @file compress.c
3 | @brief An adaptive order-2 PPM range coder
4 | */
5 | #define ENET_BUILDING_LIB 1
6 | #include
7 | #include "enet/enet.h"
8 |
9 | typedef struct _ENetSymbol
10 | {
11 | /* binary indexed tree of symbols */
12 | enet_uint8 value;
13 | enet_uint8 count;
14 | enet_uint16 under;
15 | enet_uint16 left, right;
16 |
17 | /* context defined by this symbol */
18 | enet_uint16 symbols;
19 | enet_uint16 escapes;
20 | enet_uint16 total;
21 | enet_uint16 parent;
22 | } ENetSymbol;
23 |
24 | /* adaptation constants tuned aggressively for small packet sizes rather than large file compression */
25 | enum
26 | {
27 | ENET_RANGE_CODER_TOP = 1<<24,
28 | ENET_RANGE_CODER_BOTTOM = 1<<16,
29 |
30 | ENET_CONTEXT_SYMBOL_DELTA = 3,
31 | ENET_CONTEXT_SYMBOL_MINIMUM = 1,
32 | ENET_CONTEXT_ESCAPE_MINIMUM = 1,
33 |
34 | ENET_SUBCONTEXT_ORDER = 2,
35 | ENET_SUBCONTEXT_SYMBOL_DELTA = 2,
36 | ENET_SUBCONTEXT_ESCAPE_DELTA = 5
37 | };
38 |
39 | /* context exclusion roughly halves compression speed, so disable for now */
40 | #undef ENET_CONTEXT_EXCLUSION
41 |
42 | typedef struct _ENetRangeCoder
43 | {
44 | /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */
45 | ENetSymbol symbols[4096];
46 | } ENetRangeCoder;
47 |
48 | void *
49 | enet_range_coder_create (void)
50 | {
51 | ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder));
52 | if (rangeCoder == NULL)
53 | return NULL;
54 |
55 | return rangeCoder;
56 | }
57 |
58 | void
59 | enet_range_coder_destroy (void * context)
60 | {
61 | ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
62 | if (rangeCoder == NULL)
63 | return;
64 |
65 | enet_free (rangeCoder);
66 | }
67 |
68 | #define ENET_SYMBOL_CREATE(symbol, value_, count_) \
69 | { \
70 | symbol = & rangeCoder -> symbols [nextSymbol ++]; \
71 | symbol -> value = value_; \
72 | symbol -> count = count_; \
73 | symbol -> under = count_; \
74 | symbol -> left = 0; \
75 | symbol -> right = 0; \
76 | symbol -> symbols = 0; \
77 | symbol -> escapes = 0; \
78 | symbol -> total = 0; \
79 | symbol -> parent = 0; \
80 | }
81 |
82 | #define ENET_CONTEXT_CREATE(context, escapes_, minimum) \
83 | { \
84 | ENET_SYMBOL_CREATE (context, 0, 0); \
85 | (context) -> escapes = escapes_; \
86 | (context) -> total = escapes_ + 256*minimum; \
87 | (context) -> symbols = 0; \
88 | }
89 |
90 | static enet_uint16
91 | enet_symbol_rescale (ENetSymbol * symbol)
92 | {
93 | enet_uint16 total = 0;
94 | for (;;)
95 | {
96 | symbol -> count -= symbol->count >> 1;
97 | symbol -> under = symbol -> count;
98 | if (symbol -> left)
99 | symbol -> under += enet_symbol_rescale (symbol + symbol -> left);
100 | total += symbol -> under;
101 | if (! symbol -> right) break;
102 | symbol += symbol -> right;
103 | }
104 | return total;
105 | }
106 |
107 | #define ENET_CONTEXT_RESCALE(context, minimum) \
108 | { \
109 | (context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \
110 | (context) -> escapes -= (context) -> escapes >> 1; \
111 | (context) -> total += (context) -> escapes + 256*minimum; \
112 | }
113 |
114 | #define ENET_RANGE_CODER_OUTPUT(value) \
115 | { \
116 | if (outData >= outEnd) \
117 | return 0; \
118 | * outData ++ = value; \
119 | }
120 |
121 | #define ENET_RANGE_CODER_ENCODE(under, count, total) \
122 | { \
123 | encodeRange /= (total); \
124 | encodeLow += (under) * encodeRange; \
125 | encodeRange *= (count); \
126 | for (;;) \
127 | { \
128 | if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \
129 | { \
130 | if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
131 | encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
132 | } \
133 | ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
134 | encodeRange <<= 8; \
135 | encodeLow <<= 8; \
136 | } \
137 | }
138 |
139 | #define ENET_RANGE_CODER_FLUSH \
140 | { \
141 | while (encodeLow) \
142 | { \
143 | ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
144 | encodeLow <<= 8; \
145 | } \
146 | }
147 |
148 | #define ENET_RANGE_CODER_FREE_SYMBOLS \
149 | { \
150 | if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \
151 | { \
152 | nextSymbol = 0; \
153 | ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \
154 | predicted = 0; \
155 | order = 0; \
156 | } \
157 | }
158 |
159 | #define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \
160 | { \
161 | under_ = value*minimum; \
162 | count_ = minimum; \
163 | if (! (context) -> symbols) \
164 | { \
165 | ENET_SYMBOL_CREATE (symbol_, value_, update); \
166 | (context) -> symbols = symbol_ - (context); \
167 | } \
168 | else \
169 | { \
170 | ENetSymbol * node = (context) + (context) -> symbols; \
171 | for (;;) \
172 | { \
173 | if (value_ < node -> value) \
174 | { \
175 | node -> under += update; \
176 | if (node -> left) { node += node -> left; continue; } \
177 | ENET_SYMBOL_CREATE (symbol_, value_, update); \
178 | node -> left = symbol_ - node; \
179 | } \
180 | else \
181 | if (value_ > node -> value) \
182 | { \
183 | under_ += node -> under; \
184 | if (node -> right) { node += node -> right; continue; } \
185 | ENET_SYMBOL_CREATE (symbol_, value_, update); \
186 | node -> right = symbol_ - node; \
187 | } \
188 | else \
189 | { \
190 | count_ += node -> count; \
191 | under_ += node -> under - node -> count; \
192 | node -> under += update; \
193 | node -> count += update; \
194 | symbol_ = node; \
195 | } \
196 | break; \
197 | } \
198 | } \
199 | }
200 |
201 | #ifdef ENET_CONTEXT_EXCLUSION
202 | static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
203 |
204 | #define ENET_CONTEXT_WALK(context, body) \
205 | { \
206 | const ENetSymbol * node = (context) + (context) -> symbols; \
207 | const ENetSymbol * stack [256]; \
208 | size_t stackSize = 0; \
209 | while (node -> left) \
210 | { \
211 | stack [stackSize ++] = node; \
212 | node += node -> left; \
213 | } \
214 | for (;;) \
215 | { \
216 | body; \
217 | if (node -> right) \
218 | { \
219 | node += node -> right; \
220 | while (node -> left) \
221 | { \
222 | stack [stackSize ++] = node; \
223 | node += node -> left; \
224 | } \
225 | } \
226 | else \
227 | if (stackSize <= 0) \
228 | break; \
229 | else \
230 | node = stack [-- stackSize]; \
231 | } \
232 | }
233 |
234 | #define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \
235 | ENET_CONTEXT_WALK(context, { \
236 | if (node -> value != value_) \
237 | { \
238 | enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \
239 | if (node -> value < value_) \
240 | under -= parentCount; \
241 | total -= parentCount; \
242 | } \
243 | })
244 | #endif
245 |
246 | size_t
247 | enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit)
248 | {
249 | ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
250 | enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
251 | const enet_uint8 * inData, * inEnd;
252 | enet_uint32 encodeLow = 0, encodeRange = ~0;
253 | ENetSymbol * root;
254 | enet_uint16 predicted = 0;
255 | size_t order = 0, nextSymbol = 0;
256 |
257 | if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0)
258 | return 0;
259 |
260 | inData = (const enet_uint8 *) inBuffers -> data;
261 | inEnd = & inData [inBuffers -> dataLength];
262 | inBuffers ++;
263 | inBufferCount --;
264 |
265 | ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
266 |
267 | for (;;)
268 | {
269 | ENetSymbol * subcontext, * symbol;
270 | #ifdef ENET_CONTEXT_EXCLUSION
271 | const ENetSymbol * childContext = & emptyContext;
272 | #endif
273 | enet_uint8 value;
274 | enet_uint16 count, under, * parent = & predicted, total;
275 | if (inData >= inEnd)
276 | {
277 | if (inBufferCount <= 0)
278 | break;
279 | inData = (const enet_uint8 *) inBuffers -> data;
280 | inEnd = & inData [inBuffers -> dataLength];
281 | inBuffers ++;
282 | inBufferCount --;
283 | }
284 | value = * inData ++;
285 |
286 | for (subcontext = & rangeCoder -> symbols [predicted];
287 | subcontext != root;
288 | #ifdef ENET_CONTEXT_EXCLUSION
289 | childContext = subcontext,
290 | #endif
291 | subcontext = & rangeCoder -> symbols [subcontext -> parent])
292 | {
293 | ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
294 | * parent = symbol - rangeCoder -> symbols;
295 | parent = & symbol -> parent;
296 | total = subcontext -> total;
297 | #ifdef ENET_CONTEXT_EXCLUSION
298 | if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
299 | ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0);
300 | #endif
301 | if (count > 0)
302 | {
303 | ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total);
304 | }
305 | else
306 | {
307 | if (subcontext -> escapes > 0 && subcontext -> escapes < total)
308 | ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total);
309 | subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
310 | subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
311 | }
312 | subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
313 | if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
314 | ENET_CONTEXT_RESCALE (subcontext, 0);
315 | if (count > 0) goto nextInput;
316 | }
317 |
318 | ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM);
319 | * parent = symbol - rangeCoder -> symbols;
320 | parent = & symbol -> parent;
321 | total = root -> total;
322 | #ifdef ENET_CONTEXT_EXCLUSION
323 | if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
324 | ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM);
325 | #endif
326 | ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total);
327 | root -> total += ENET_CONTEXT_SYMBOL_DELTA;
328 | if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
329 | ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
330 |
331 | nextInput:
332 | if (order >= ENET_SUBCONTEXT_ORDER)
333 | predicted = rangeCoder -> symbols [predicted].parent;
334 | else
335 | order ++;
336 | ENET_RANGE_CODER_FREE_SYMBOLS;
337 | }
338 |
339 | ENET_RANGE_CODER_FLUSH;
340 |
341 | return (size_t) (outData - outStart);
342 | }
343 |
344 | #define ENET_RANGE_CODER_SEED \
345 | { \
346 | if (inData < inEnd) decodeCode |= * inData ++ << 24; \
347 | if (inData < inEnd) decodeCode |= * inData ++ << 16; \
348 | if (inData < inEnd) decodeCode |= * inData ++ << 8; \
349 | if (inData < inEnd) decodeCode |= * inData ++; \
350 | }
351 |
352 | #define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total)))
353 |
354 | #define ENET_RANGE_CODER_DECODE(under, count, total) \
355 | { \
356 | decodeLow += (under) * decodeRange; \
357 | decodeRange *= (count); \
358 | for (;;) \
359 | { \
360 | if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \
361 | { \
362 | if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
363 | decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
364 | } \
365 | decodeCode <<= 8; \
366 | if (inData < inEnd) \
367 | decodeCode |= * inData ++; \
368 | decodeRange <<= 8; \
369 | decodeLow <<= 8; \
370 | } \
371 | }
372 |
373 | #define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \
374 | { \
375 | under_ = 0; \
376 | count_ = minimum; \
377 | if (! (context) -> symbols) \
378 | { \
379 | createRoot; \
380 | } \
381 | else \
382 | { \
383 | ENetSymbol * node = (context) + (context) -> symbols; \
384 | for (;;) \
385 | { \
386 | enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \
387 | visitNode; \
388 | if (code >= after) \
389 | { \
390 | under_ += node -> under; \
391 | if (node -> right) { node += node -> right; continue; } \
392 | createRight; \
393 | } \
394 | else \
395 | if (code < after - before) \
396 | { \
397 | node -> under += update; \
398 | if (node -> left) { node += node -> left; continue; } \
399 | createLeft; \
400 | } \
401 | else \
402 | { \
403 | value_ = node -> value; \
404 | count_ += node -> count; \
405 | under_ = after - before; \
406 | node -> under += update; \
407 | node -> count += update; \
408 | symbol_ = node; \
409 | } \
410 | break; \
411 | } \
412 | } \
413 | }
414 |
415 | #define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
416 | ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0)
417 |
418 | #define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
419 | ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \
420 | { \
421 | value_ = code / minimum; \
422 | under_ = code - code%minimum; \
423 | ENET_SYMBOL_CREATE (symbol_, value_, update); \
424 | (context) -> symbols = symbol_ - (context); \
425 | }, \
426 | exclude (node -> value, after, before), \
427 | { \
428 | value_ = node->value + 1 + (code - after)/minimum; \
429 | under_ = code - (code - after)%minimum; \
430 | ENET_SYMBOL_CREATE (symbol_, value_, update); \
431 | node -> right = symbol_ - node; \
432 | }, \
433 | { \
434 | value_ = node->value - 1 - (after - before - code - 1)/minimum; \
435 | under_ = code - (after - before - code - 1)%minimum; \
436 | ENET_SYMBOL_CREATE (symbol_, value_, update); \
437 | node -> left = symbol_ - node; \
438 | }) \
439 |
440 | #ifdef ENET_CONTEXT_EXCLUSION
441 | typedef struct _ENetExclude
442 | {
443 | enet_uint8 value;
444 | enet_uint16 under;
445 | } ENetExclude;
446 |
447 | #define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \
448 | { \
449 | enet_uint16 under = 0; \
450 | nextExclude = excludes; \
451 | ENET_CONTEXT_WALK (context, { \
452 | under += rangeCoder -> symbols [node -> parent].count + minimum; \
453 | nextExclude -> value = node -> value; \
454 | nextExclude -> under = under; \
455 | nextExclude ++; \
456 | }); \
457 | total -= under; \
458 | }
459 |
460 | #define ENET_CONTEXT_EXCLUDED(value_, after, before) \
461 | { \
462 | size_t low = 0, high = nextExclude - excludes; \
463 | for(;;) \
464 | { \
465 | size_t mid = (low + high) >> 1; \
466 | const ENetExclude * exclude = & excludes [mid]; \
467 | if (value_ < exclude -> value) \
468 | { \
469 | if (low + 1 < high) \
470 | { \
471 | high = mid; \
472 | continue; \
473 | } \
474 | if (exclude > excludes) \
475 | after -= exclude [-1].under; \
476 | } \
477 | else \
478 | { \
479 | if (value_ > exclude -> value) \
480 | { \
481 | if (low + 1 < high) \
482 | { \
483 | low = mid; \
484 | continue; \
485 | } \
486 | } \
487 | else \
488 | before = 0; \
489 | after -= exclude -> under; \
490 | } \
491 | break; \
492 | } \
493 | }
494 | #endif
495 |
496 | #define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before)
497 |
498 | size_t
499 | enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit)
500 | {
501 | ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
502 | enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
503 | const enet_uint8 * inEnd = & inData [inLimit];
504 | enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0;
505 | ENetSymbol * root;
506 | enet_uint16 predicted = 0;
507 | size_t order = 0, nextSymbol = 0;
508 | #ifdef ENET_CONTEXT_EXCLUSION
509 | ENetExclude excludes [256];
510 | ENetExclude * nextExclude = excludes;
511 | #endif
512 |
513 | if (rangeCoder == NULL || inLimit <= 0)
514 | return 0;
515 |
516 | ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
517 |
518 | ENET_RANGE_CODER_SEED;
519 |
520 | for (;;)
521 | {
522 | ENetSymbol * subcontext, * symbol, * patch;
523 | #ifdef ENET_CONTEXT_EXCLUSION
524 | const ENetSymbol * childContext = & emptyContext;
525 | #endif
526 | enet_uint8 value = 0;
527 | enet_uint16 code, under, count, bottom, * parent = & predicted, total;
528 |
529 | for (subcontext = & rangeCoder -> symbols [predicted];
530 | subcontext != root;
531 | #ifdef ENET_CONTEXT_EXCLUSION
532 | childContext = subcontext,
533 | #endif
534 | subcontext = & rangeCoder -> symbols [subcontext -> parent])
535 | {
536 | if (subcontext -> escapes <= 0)
537 | continue;
538 | total = subcontext -> total;
539 | #ifdef ENET_CONTEXT_EXCLUSION
540 | if (childContext -> total > 0)
541 | ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0);
542 | #endif
543 | if (subcontext -> escapes >= total)
544 | continue;
545 | code = ENET_RANGE_CODER_READ (total);
546 | if (code < subcontext -> escapes)
547 | {
548 | ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total);
549 | continue;
550 | }
551 | code -= subcontext -> escapes;
552 | #ifdef ENET_CONTEXT_EXCLUSION
553 | if (childContext -> total > 0)
554 | {
555 | ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED);
556 | }
557 | else
558 | #endif
559 | {
560 | ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED);
561 | }
562 | bottom = symbol - rangeCoder -> symbols;
563 | ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total);
564 | subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
565 | if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
566 | ENET_CONTEXT_RESCALE (subcontext, 0);
567 | goto patchContexts;
568 | }
569 |
570 | total = root -> total;
571 | #ifdef ENET_CONTEXT_EXCLUSION
572 | if (childContext -> total > 0)
573 | ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM);
574 | #endif
575 | code = ENET_RANGE_CODER_READ (total);
576 | if (code < root -> escapes)
577 | {
578 | ENET_RANGE_CODER_DECODE (0, root -> escapes, total);
579 | break;
580 | }
581 | code -= root -> escapes;
582 | #ifdef ENET_CONTEXT_EXCLUSION
583 | if (childContext -> total > 0)
584 | {
585 | ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED);
586 | }
587 | else
588 | #endif
589 | {
590 | ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED);
591 | }
592 | bottom = symbol - rangeCoder -> symbols;
593 | ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total);
594 | root -> total += ENET_CONTEXT_SYMBOL_DELTA;
595 | if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
596 | ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
597 |
598 | patchContexts:
599 | for (patch = & rangeCoder -> symbols [predicted];
600 | patch != subcontext;
601 | patch = & rangeCoder -> symbols [patch -> parent])
602 | {
603 | ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
604 | * parent = symbol - rangeCoder -> symbols;
605 | parent = & symbol -> parent;
606 | if (count <= 0)
607 | {
608 | patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
609 | patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
610 | }
611 | patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
612 | if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
613 | ENET_CONTEXT_RESCALE (patch, 0);
614 | }
615 | * parent = bottom;
616 |
617 | ENET_RANGE_CODER_OUTPUT (value);
618 |
619 | if (order >= ENET_SUBCONTEXT_ORDER)
620 | predicted = rangeCoder -> symbols [predicted].parent;
621 | else
622 | order ++;
623 | ENET_RANGE_CODER_FREE_SYMBOLS;
624 | }
625 |
626 | return (size_t) (outData - outStart);
627 | }
628 |
629 | /** @defgroup host ENet host functions
630 | @{
631 | */
632 |
633 | /** Sets the packet compressor the host should use to the default range coder.
634 | @param host host to enable the range coder for
635 | @returns 0 on success, < 0 on failure
636 | */
637 | int
638 | enet_host_compress_with_range_coder (ENetHost * host)
639 | {
640 | ENetCompressor compressor;
641 | memset (& compressor, 0, sizeof (compressor));
642 | compressor.context = enet_range_coder_create();
643 | if (compressor.context == NULL)
644 | return -1;
645 | compressor.compress = enet_range_coder_compress;
646 | compressor.decompress = enet_range_coder_decompress;
647 | compressor.destroy = enet_range_coder_destroy;
648 | enet_host_compress (host, & compressor);
649 | return 0;
650 | }
651 |
652 | /** @} */
653 |
654 |
655 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT([libenet], [1.3.18])
2 | AC_CONFIG_SRCDIR([include/enet/enet.h])
3 | AM_INIT_AUTOMAKE([foreign])
4 |
5 | AC_CONFIG_MACRO_DIR([m4])
6 |
7 | AC_PROG_CC
8 | AC_PROG_LIBTOOL
9 |
10 | AC_CHECK_FUNC(getaddrinfo, [AC_DEFINE(HAS_GETADDRINFO)])
11 | AC_CHECK_FUNC(getnameinfo, [AC_DEFINE(HAS_GETNAMEINFO)])
12 | AC_CHECK_FUNC(gethostbyaddr_r, [AC_DEFINE(HAS_GETHOSTBYADDR_R)])
13 | AC_CHECK_FUNC(gethostbyname_r, [AC_DEFINE(HAS_GETHOSTBYNAME_R)])
14 | AC_CHECK_FUNC(poll, [AC_DEFINE(HAS_POLL)])
15 | AC_CHECK_FUNC(fcntl, [AC_DEFINE(HAS_FCNTL)])
16 | AC_CHECK_FUNC(inet_pton, [AC_DEFINE(HAS_INET_PTON)])
17 | AC_CHECK_FUNC(inet_ntop, [AC_DEFINE(HAS_INET_NTOP)])
18 |
19 | AC_CHECK_MEMBER(struct msghdr.msg_flags, [AC_DEFINE(HAS_MSGHDR_FLAGS)], , [#include ])
20 |
21 | AC_CHECK_TYPE(socklen_t, [AC_DEFINE(HAS_SOCKLEN_T)], ,
22 | #include
23 | #include
24 | )
25 |
26 | AC_CONFIG_FILES([Makefile
27 | libenet.pc])
28 | AC_OUTPUT
29 |
--------------------------------------------------------------------------------
/docs/FAQ.dox:
--------------------------------------------------------------------------------
1 | /**
2 | @page FAQ Frequently Answered Questions
3 |
4 | @section Q1 Is ENet thread-safe?
5 |
6 | ENet does not use any significant global variables, the vast majority
7 | of state is encapsulated in the ENetHost structure. As such, as long
8 | as the application guards access to this structure, then ENet should
9 | operate fine in a multi-threaded environment.
10 |
11 | @section Q2 Isn't ENet just re-inventing TCP?! What's the point?
12 |
13 | In a perfect world, that would be true. But as many have found, using
14 | TCP either in lieu of or in conjunction with UDP can lead to all kinds
15 | of nightmares. TCP is a good, solid protocol, however it simply isn't
16 | up to the task of real-time games. Too much of TCP's implementation
17 | dictates a policy that isn't practical for games. If you want to use
18 | TCP, then do so -- this library is for people that either don't want
19 | to use TCP or have tried and ended up being discouraged with the
20 | performance.
21 |
22 | */
23 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/design.dox:
--------------------------------------------------------------------------------
1 | /**
2 | @page Features Features and Architecture
3 |
4 | ENet evolved specifically as a UDP networking layer for the
5 | multiplayer first person shooter Cube. Cube necessitated low latency
6 | communication with data sent out very frequently, so TCP was an
7 | unsuitable choice due to its high latency and stream orientation. UDP,
8 | however, lacks many sometimes necessary features from TCP such as
9 | reliability, sequencing, unrestricted packet sizes, and connection
10 | management. So UDP by itself was not suitable as a network protocol
11 | either. No suitable freely available networking libraries existed at
12 | the time of ENet's creation to fill this niche.
13 |
14 | UDP and TCP could have been used together in Cube to benefit somewhat
15 | from both of their features, however, the resulting combinations of
16 | protocols still leaves much to be desired. TCP lacks multiple streams
17 | of communication without resorting to opening many sockets and
18 | complicates delineation of packets due to its buffering behavior. UDP
19 | lacks sequencing, connection management, management of bandwidth
20 | resources, and imposes limitations on the size of packets. A
21 | significant investment is required to integrate these two protocols,
22 | and the end result is worse off in features and performance than the
23 | uniform protocol presented by ENet.
24 |
25 | ENet thus attempts to address these issues and provide a single,
26 | uniform protocol layered over UDP to the developer with the best
27 | features of UDP and TCP as well as some useful features neither
28 | provide, with a much cleaner integration than any resulting from a
29 | mixture of UDP and TCP.
30 |
31 | @section CM Connection Management
32 |
33 | ENet provides a simple connection interface over which to communicate
34 | with a foreign host. The liveness of the connection is actively
35 | monitored by pinging the foreign host at frequent intervals, and also
36 | monitors the network conditions from the local host to the foreign
37 | host such as the mean round trip time and packet loss in this fashion.
38 |
39 | @section Sequencing Sequencing
40 |
41 | Rather than a single byte stream that complicates the delineation of
42 | packets, ENet presents connections as multiple, properly sequenced
43 | packet streams that simplify the transfer of various types of data.
44 |
45 | ENet provides sequencing for all packets by assigning to each sent
46 | packet a sequence number that is incremented as packets are sent. ENet
47 | guarantees that no packet with a higher sequence number will be
48 | delivered before a packet with a lower sequence number, thus ensuring
49 | packets are delivered exactly in the order they are sent.
50 |
51 | For unreliable packets, ENet will simply discard the lower sequence
52 | number packet if a packet with a higher sequence number has already
53 | been delivered. This allows the packets to be dispatched immediately
54 | as they arrive, and reduce latency of unreliable packets to an
55 | absolute minimum. For reliable packets, if a higher sequence number
56 | packet arrives, but the preceding packets in the sequence have not yet
57 | arrived, ENet will stall delivery of the higher sequence number
58 | packets until its predecessors have arrived.
59 |
60 | @section Channels Channels
61 |
62 | Since ENet will stall delivery of reliable packets to ensure proper
63 | sequencing, and consequently any packets of higher sequence number
64 | whether reliable or unreliable, in the event the reliable packet's
65 | predecessors have not yet arrived, this can introduce latency into the
66 | delivery of other packets which may not need to be as strictly ordered
67 | with respect to the packet that stalled their delivery.
68 |
69 | To combat this latency and reduce the ordering restrictions on
70 | packets, ENet provides multiple channels of communication over a given
71 | connection. Each channel is independently sequenced, and so the
72 | delivery status of a packet in one channel will not stall the delivery
73 | of other packets in another channel.
74 |
75 | @section Reliability Reliability
76 |
77 | ENet provides optional reliability of packet delivery by ensuring the
78 | foreign host acknowledges receipt of all reliable packets. ENet will
79 | attempt to resend the packet up to a reasonable amount of times, if no
80 | acknowledgement of the packet's receipt happens within a specified
81 | timeout. Retry timeouts are progressive and become more lenient with
82 | every failed attempt to allow for temporary turbulence in network
83 | conditions.
84 |
85 | @section FaR Fragmentation and Reassembly
86 |
87 | ENet will send and deliver packets regardless of size. Large packets
88 | are fragmented into many smaller packets of suitable size, and
89 | reassembled on the foreign host to recover the original packet for
90 | delivery. The process is entirely transparent to the developer.
91 |
92 | @section Aggregation Aggregation
93 |
94 | ENet aggregates all protocol commands, including acknowledgements and
95 | packet transfer, into larger protocol packets to ensure the proper
96 | utilization of the connection and to limit the opportunities for
97 | packet loss that might otherwise result in further delivery latency.
98 |
99 | @section Adaptability Adaptability
100 |
101 | ENet provides an in-flight data window for reliable packets to ensure
102 | connections are not overwhelmed by volumes of packets. It also
103 | provides a static bandwidth allocation mechanism to ensure the total
104 | volume of packets sent and received to a host don't exceed the host's
105 | capabilities. Further, ENet also provides a dynamic throttle that
106 | responds to deviations from normal network connections to rectify
107 | various types of network congestion by further limiting the volume of
108 | packets sent.
109 |
110 | @section Portability Portability
111 |
112 | ENet works on Windows and any other Unix or Unix-like platform
113 | providing a BSD sockets interface. The library has a small and stable
114 | code base that can easily be extended to support other platforms and
115 | integrates easily. ENet makes no assumptions about the underlying
116 | platform's endianess or word size.
117 |
118 | @section Freedom Freedom
119 |
120 | ENet demands no royalties and doesn't carry a viral license that would
121 | restrict you in how you might use it in your programs. ENet is
122 | licensed under a short-and-sweet MIT-style license, which gives you
123 | the freedom to do anything you want with it (well, almost anything).
124 |
125 | */
126 |
127 |
--------------------------------------------------------------------------------
/docs/install.dox:
--------------------------------------------------------------------------------
1 | /**
2 | @page Installation Installation
3 |
4 | ENet should be trivially simple to integrate with most applications.
5 | First, make sure you download the latest source distribution at @ref Downloads.
6 |
7 | @section Unix Unix-like Operating Systems
8 |
9 | If you are using an ENet release, then you should simply be able to build it
10 | by doing the following:
11 |
12 | ./configure && make && make install
13 |
14 | If you obtained the package from github, you must have automake and autoconf
15 | available to generate the build system first by doing the following command
16 | before using the above mentioned build procedure:
17 |
18 | autoreconf -vfi
19 |
20 |
21 | @subsection SolarisBSD Solaris and BSD
22 |
23 | When building ENet under Solaris, you must specify the -lsocket and
24 | -lnsl parameters to your compiler to ensure that the sockets library
25 | is linked in.
26 |
27 | @section Windows Microsoft Windows
28 |
29 | You may simply use the included "enet.lib" or "enet64.lib" static libraries.
30 | However, if you wish to build the library yourself, then the following
31 | instructions apply:
32 |
33 | There is an included MSVC 6 project (enet.dsp) which you may use to
34 | build a suitable library file. Alternatively, you may simply drag all
35 | the ENet source files into your main project.
36 |
37 | You will have to link to the Winsock2 libraries, so make sure to add
38 | ws2_32.lib and winmm.lib to your library list (Project Settings | Link |
39 | Object/library modules).
40 |
41 | @subsection enet.dsp Building with the included enet.dsp
42 |
43 | Load the included enet.dsp. MSVC may ask you to convert it if you
44 | are on a newer version of MSVC - just allow the conversion and save
45 | the resulting project as "enet" or similar. After you build this
46 | project, it will output an "enet.lib" file to either the "Debug/"
47 | or "Release/" directory, depending on which configuration you have
48 | selected to build. By default, it should produce "Debug/enet.lib".
49 |
50 | You may then copy the resulting "enet.lib" file and the header files
51 | found in the "include/" directory to your other projects and add it to
52 | their library lists. Make sure to also link against "ws2_32.lib" and
53 | "winmm.lib" as described above.
54 |
55 | @subsection DLL DLL
56 |
57 | If you wish to build ENet as a DLL you must first define ENET_DLL
58 | within the project (Project Settings | C/C++ | Preprocessor |
59 | Preprocessor definitions) or, more invasively, simply define ENET_DLL
60 | at the top of enet.h.
61 |
62 | */
63 |
64 |
--------------------------------------------------------------------------------
/docs/license.dox:
--------------------------------------------------------------------------------
1 | /**
2 | @page License License
3 |
4 | Copyright (c) 2002-2024 Lee Salzman
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining
7 | a copy of this software and associated documentation files (the
8 | "Software"), to deal in the Software without restriction, including
9 | without limitation the rights to use, copy, modify, merge, publish,
10 | distribute, sublicense, and/or sell copies of the Software, and to
11 | permit persons to whom the Software is furnished to do so, subject to
12 | the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | */
26 |
27 |
--------------------------------------------------------------------------------
/docs/mainpage.dox:
--------------------------------------------------------------------------------
1 | /** @mainpage ENet
2 |
3 | ENet's purpose is to provide a relatively thin, simple and robust
4 | network communication layer on top of UDP (User Datagram Protocol).
5 | The primary feature it provides is optional reliable, in-order
6 | delivery of packets.
7 |
8 | ENet omits certain higher level networking features such as authentication,
9 | lobbying, server discovery, encryption, or other similar tasks that are
10 | particularly application specific so that the library remains flexible,
11 | portable, and easily embeddable.
12 |
13 | @ref Features
14 |
15 | @ref Downloads
16 |
17 | @ref Installation
18 |
19 | @ref Tutorial
20 |
21 | @ref MailingList
22 |
23 | @ref IRCChannel
24 |
25 | @ref FAQ
26 |
27 | @ref License
28 |
29 | Documentation
30 |
31 | */
32 |
33 | /**
34 | @page Downloads Downloads
35 |
36 | You can retrieve the source to ENet by downloading it in either .tar.gz form
37 | or accessing the github distribution directly.
38 |
39 | The most recent stable release (1.3.18) can be downloaded here.
40 | The last release that is protocol compatible with the 1.2 series or earlier (1.2.5) can be downloaded here.
41 |
42 | You can find the most recent ENet source at the github repository.
43 |
44 | */
45 |
46 | /**
47 | @page MailingList Mailing List
48 |
49 | The enet-discuss list is for discussion of ENet, including bug reports or feature requests.
50 |
51 | */
52 |
53 | /**
54 | @page IRCChannel IRC Channel
55 |
56 | Join the \#enet channel on the Libera Chat IRC network (irc.libera.chat) for real-time discussion about the ENet library.
57 |
58 | */
59 |
60 |
--------------------------------------------------------------------------------
/docs/tutorial.dox:
--------------------------------------------------------------------------------
1 | /**
2 | @page Tutorial Tutorial
3 |
4 | @ref Initialization
5 |
6 | @ref CreateServer
7 |
8 | @ref CreateClient
9 |
10 | @ref ManageHost
11 |
12 | @ref SendingPacket
13 |
14 | @ref Disconnecting
15 |
16 | @ref Connecting
17 |
18 | @section Initialization Initialization
19 |
20 | You should include the file when using ENet. Do not
21 | include without the directory prefix, as this may cause
22 | file name conflicts on some systems.
23 |
24 | Before using ENet, you must call enet_initialize() to initialize the
25 | library. Upon program exit, you should call enet_deinitialize() so
26 | that the library may clean up any used resources.
27 |
28 | @code
29 | #include
30 |
31 | int
32 | main (int argc, char ** argv)
33 | {
34 | if (enet_initialize () != 0)
35 | {
36 | fprintf (stderr, "An error occurred while initializing ENet.\n");
37 | return EXIT_FAILURE;
38 | }
39 | atexit (enet_deinitialize);
40 | ...
41 | ...
42 | ...
43 | }
44 | @endcode
45 |
46 | @section CreateServer Creating an ENet server
47 |
48 | Servers in ENet are constructed with enet_host_create(). You must
49 | specify an address on which to receive data and new connections, as
50 | well as the maximum allowable numbers of connected peers. You may
51 | optionally specify the incoming and outgoing bandwidth of the server
52 | in bytes per second so that ENet may try to statically manage
53 | bandwidth resources among connected peers in addition to its dynamic
54 | throttling algorithm; specifying 0 for these two options will cause
55 | ENet to rely entirely upon its dynamic throttling algorithm to manage
56 | bandwidth.
57 |
58 | When done with a host, the host may be destroyed with
59 | enet_host_destroy(). All connected peers to the host will be reset,
60 | and the resources used by the host will be freed.
61 |
62 | @code
63 | ENetAddress address;
64 | ENetHost * server;
65 |
66 | /* Bind the server to the default localhost. */
67 | /* A specific host address can be specified by */
68 | /* enet_address_set_host (& address, "x.x.x.x"); */
69 |
70 | address.host = ENET_HOST_ANY;
71 | /* Bind the server to port 1234. */
72 | address.port = 1234;
73 |
74 | server = enet_host_create (& address /* the address to bind the server host to */,
75 | 32 /* allow up to 32 clients and/or outgoing connections */,
76 | 2 /* allow up to 2 channels to be used, 0 and 1 */,
77 | 0 /* assume any amount of incoming bandwidth */,
78 | 0 /* assume any amount of outgoing bandwidth */);
79 | if (server == NULL)
80 | {
81 | fprintf (stderr,
82 | "An error occurred while trying to create an ENet server host.\n");
83 | exit (EXIT_FAILURE);
84 | }
85 | ...
86 | ...
87 | ...
88 | enet_host_destroy(server);
89 | @endcode
90 |
91 | @section CreateClient Creating an ENet client
92 |
93 | Clients in ENet are similarly constructed with enet_host_create() when
94 | no address is specified to bind the host to. Bandwidth may be
95 | specified for the client host as in the above example. The peer count
96 | controls the maximum number of connections to other server hosts that
97 | may be simultaneously open.
98 |
99 | @code
100 | ENetHost * client;
101 |
102 | client = enet_host_create (NULL /* create a client host */,
103 | 1 /* only allow 1 outgoing connection */,
104 | 2 /* allow up 2 channels to be used, 0 and 1 */,
105 | 0 /* assume any amount of incoming bandwidth */,
106 | 0 /* assume any amount of outgoing bandwidth */);
107 |
108 | if (client == NULL)
109 | {
110 | fprintf (stderr,
111 | "An error occurred while trying to create an ENet client host.\n");
112 | exit (EXIT_FAILURE);
113 | }
114 | ...
115 | ...
116 | ...
117 | enet_host_destroy(client);
118 | @endcode
119 |
120 | @section ManageHost Managing an ENet host
121 |
122 | ENet uses a polled event model to notify the programmer of significant
123 | events. ENet hosts are polled for events with enet_host_service(),
124 | where an optional timeout value in milliseconds may be specified to
125 | control how long ENet will poll; if a timeout of 0 is specified,
126 | enet_host_service() will return immediately if there are no events to
127 | dispatch. enet_host_service() will return 1 if an event was dispatched
128 | within the specified timeout.
129 |
130 | Beware that most processing of the network with the ENet stack is done
131 | inside enet_host_service(). Both hosts that make up the sides of a connection
132 | must regularly call this function to ensure packets are actually sent and
133 | received. A common symptom of not actively calling enet_host_service()
134 | on both ends is that one side receives events while the other does not.
135 | The best way to schedule this activity to ensure adequate service is, for
136 | example, to call enet_host_service() with a 0 timeout (meaning non-blocking)
137 | at the beginning of every frame in a game loop.
138 |
139 | Currently there are only four types of significant events in ENet:
140 |
141 | An event of type ENET_EVENT_TYPE_NONE is returned if no event occurred
142 | within the specified time limit. enet_host_service() will return 0
143 | with this event.
144 |
145 | An event of type ENET_EVENT_TYPE_CONNECT is returned when either a new client
146 | host has connected to the server host or when an attempt to establish a
147 | connection with a foreign host has succeeded. Only the "peer" field of the
148 | event structure is valid for this event and contains the newly connected peer.
149 |
150 | An event of type ENET_EVENT_TYPE_RECEIVE is returned when a packet is received
151 | from a connected peer. The "peer" field contains the peer the packet was
152 | received from, "channelID" is the channel on which the packet was sent, and
153 | "packet" is the packet that was sent. The packet contained in the "packet"
154 | field must be destroyed with enet_packet_destroy() when you are done
155 | inspecting its contents.
156 |
157 | An event of type ENET_EVENT_TYPE_DISCONNECT is returned when a connected peer
158 | has either explicitly disconnected or timed out. Only the "peer" field of the
159 | event structure is valid for this event and contains the peer that
160 | disconnected. Only the "data" field of the peer is still valid on a
161 | disconnect event and must be explicitly reset.
162 |
163 | @code
164 | ENetEvent event;
165 |
166 | /* Wait up to 1000 milliseconds for an event. */
167 | while (enet_host_service (client, & event, 1000) > 0)
168 | {
169 | switch (event.type)
170 | {
171 | case ENET_EVENT_TYPE_CONNECT:
172 | printf ("A new client connected from %x:%u.\n",
173 | event.peer -> address.host,
174 | event.peer -> address.port);
175 |
176 | /* Store any relevant client information here. */
177 | event.peer -> data = "Client information";
178 |
179 | break;
180 |
181 | case ENET_EVENT_TYPE_RECEIVE:
182 | printf ("A packet of length %u containing %s was received from %s on channel %u.\n",
183 | event.packet -> dataLength,
184 | event.packet -> data,
185 | event.peer -> data,
186 | event.channelID);
187 |
188 | /* Clean up the packet now that we're done using it. */
189 | enet_packet_destroy (event.packet);
190 |
191 | break;
192 |
193 | case ENET_EVENT_TYPE_DISCONNECT:
194 | printf ("%s disconnected.\n", event.peer -> data);
195 |
196 | /* Reset the peer's client information. */
197 |
198 | event.peer -> data = NULL;
199 | }
200 | }
201 | ...
202 | ...
203 | ...
204 | @endcode
205 |
206 | @section SendingPacket Sending a packet to an ENet peer
207 |
208 | Packets in ENet are created with enet_packet_create(), where the size
209 | of the packet must be specified. Optionally, initial data may be
210 | specified to copy into the packet.
211 |
212 | Certain flags may also be supplied to enet_packet_create() to control
213 | various packet features:
214 |
215 | ENET_PACKET_FLAG_RELIABLE specifies that the packet must use reliable
216 | delivery. A reliable packet is guaranteed to be delivered, and a
217 | number of retry attempts will be made until an acknowledgement is
218 | received from the foreign host the packet is sent to. If a certain
219 | number of retry attempts is reached without any acknowledgement, ENet
220 | will assume the peer has disconnected and forcefully reset the
221 | connection. If this flag is not specified, the packet is assumed an
222 | unreliable packet, and no retry attempts will be made nor
223 | acknowledgements generated.
224 |
225 | A packet may be resized (extended or truncated) with
226 | enet_packet_resize().
227 |
228 | A packet is sent to a foreign host with
229 | enet_peer_send(). enet_peer_send() accepts a channel id over which to
230 | send the packet to a given peer. Once the packet is handed over to
231 | ENet with enet_peer_send(), ENet will handle its deallocation and
232 | enet_packet_destroy() should not be used upon it.
233 |
234 | One may also use enet_host_broadcast() to send a packet to all
235 | connected peers on a given host over a specified channel id, as with
236 | enet_peer_send().
237 |
238 | Queued packets will be sent on a call to enet_host_service().
239 | Alternatively, enet_host_flush() will send out queued packets without
240 | dispatching any events.
241 |
242 | @code
243 | /* Create a reliable packet of size 7 containing "packet\0" */
244 | ENetPacket * packet = enet_packet_create ("packet",
245 | strlen ("packet") + 1,
246 | ENET_PACKET_FLAG_RELIABLE);
247 |
248 | /* Extend the packet so and append the string "foo", so it now */
249 | /* contains "packetfoo\0" */
250 | enet_packet_resize (packet, strlen ("packetfoo") + 1);
251 | strcpy (& packet -> data [strlen ("packet")], "foo");
252 |
253 | /* Send the packet to the peer over channel id 0. */
254 | /* One could also broadcast the packet by */
255 | /* enet_host_broadcast (host, 0, packet); */
256 | enet_peer_send (peer, 0, packet);
257 | ...
258 | ...
259 | ...
260 | /* One could just use enet_host_service() instead. */
261 | enet_host_flush (host);
262 | @endcode
263 |
264 | @section Disconnecting Disconnecting an ENet peer
265 |
266 | Peers may be gently disconnected with enet_peer_disconnect(). A
267 | disconnect request will be sent to the foreign host, and ENet will
268 | wait for an acknowledgement from the foreign host before finally
269 | disconnecting. An event of type ENET_EVENT_TYPE_DISCONNECT will be
270 | generated once the disconnection succeeds. Normally timeouts apply to
271 | the disconnect acknowledgement, and so if no acknowledgement is
272 | received after a length of time the peer will be forcefully
273 | disconnected.
274 |
275 | enet_peer_reset() will forcefully disconnect a peer. The foreign host
276 | will get no notification of a disconnect and will time out on the
277 | foreign host. No event is generated.
278 |
279 | @code
280 | ENetEvent event;
281 |
282 | enet_peer_disconnect (peer, 0);
283 |
284 | /* Allow up to 3 seconds for the disconnect to succeed
285 | * and drop any packets received packets.
286 | */
287 | while (enet_host_service (client, & event, 3000) > 0)
288 | {
289 | switch (event.type)
290 | {
291 | case ENET_EVENT_TYPE_RECEIVE:
292 | enet_packet_destroy (event.packet);
293 | break;
294 |
295 | case ENET_EVENT_TYPE_DISCONNECT:
296 | puts ("Disconnection succeeded.");
297 | return;
298 | ...
299 | ...
300 | ...
301 | }
302 | }
303 |
304 | /* We've arrived here, so the disconnect attempt didn't */
305 | /* succeed yet. Force the connection down. */
306 | enet_peer_reset (peer);
307 | ...
308 | ...
309 | ...
310 | @endcode
311 |
312 | @section Connecting Connecting to an ENet host
313 |
314 | A connection to a foreign host is initiated with enet_host_connect().
315 | It accepts the address of a foreign host to connect to, and the number
316 | of channels that should be allocated for communication. If N channels
317 | are allocated for use, their channel ids will be numbered 0 through
318 | N-1. A peer representing the connection attempt is returned, or NULL
319 | if there were no available peers over which to initiate the
320 | connection. When the connection attempt succeeds, an event of type
321 | ENET_EVENT_TYPE_CONNECT will be generated. If the connection attempt
322 | times out or otherwise fails, an event of type
323 | ENET_EVENT_TYPE_DISCONNECT will be generated.
324 |
325 | @code
326 | ENetAddress address;
327 | ENetEvent event;
328 | ENetPeer *peer;
329 |
330 | /* Connect to some.server.net:1234. */
331 | enet_address_set_host (& address, "some.server.net");
332 | address.port = 1234;
333 |
334 | /* Initiate the connection, allocating the two channels 0 and 1. */
335 | peer = enet_host_connect (client, & address, 2, 0);
336 |
337 | if (peer == NULL)
338 | {
339 | fprintf (stderr,
340 | "No available peers for initiating an ENet connection.\n");
341 | exit (EXIT_FAILURE);
342 | }
343 |
344 | /* Wait up to 5 seconds for the connection attempt to succeed. */
345 | if (enet_host_service (client, & event, 5000) > 0 &&
346 | event.type == ENET_EVENT_TYPE_CONNECT)
347 | {
348 | puts ("Connection to some.server.net:1234 succeeded.");
349 | ...
350 | ...
351 | ...
352 | }
353 | else
354 | {
355 | /* Either the 5 seconds are up or a disconnect event was */
356 | /* received. Reset the peer in the event the 5 seconds */
357 | /* had run out without any significant event. */
358 | enet_peer_reset (peer);
359 |
360 | puts ("Connection to some.server.net:1234 failed.");
361 | }
362 | ...
363 | ...
364 | ...
365 | @endcode
366 | */
367 |
--------------------------------------------------------------------------------
/enet.dsp:
--------------------------------------------------------------------------------
1 | # Microsoft Developer Studio Project File - Name="enet" - Package Owner=<4>
2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00
3 | # ** DO NOT EDIT **
4 |
5 | # TARGTYPE "Win32 (x86) Static Library" 0x0104
6 |
7 | CFG=enet - Win32 Debug
8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE,
9 | !MESSAGE use the Export Makefile command and run
10 | !MESSAGE
11 | !MESSAGE NMAKE /f "enet.mak".
12 | !MESSAGE
13 | !MESSAGE You can specify a configuration when running NMAKE
14 | !MESSAGE by defining the macro CFG on the command line. For example:
15 | !MESSAGE
16 | !MESSAGE NMAKE /f "enet.mak" CFG="enet - Win32 Debug"
17 | !MESSAGE
18 | !MESSAGE Possible choices for configuration are:
19 | !MESSAGE
20 | !MESSAGE "enet - Win32 Release" (based on "Win32 (x86) Static Library")
21 | !MESSAGE "enet - Win32 Debug" (based on "Win32 (x86) Static Library")
22 | !MESSAGE
23 |
24 | # Begin Project
25 | # PROP AllowPerConfigDependencies 0
26 | # PROP Scc_ProjName ""
27 | # PROP Scc_LocalPath ""
28 | CPP=cl.exe
29 | RSC=rc.exe
30 |
31 | !IF "$(CFG)" == "enet - Win32 Release"
32 |
33 | # PROP BASE Use_MFC 0
34 | # PROP BASE Use_Debug_Libraries 0
35 | # PROP BASE Output_Dir "Release"
36 | # PROP BASE Intermediate_Dir "Release"
37 | # PROP BASE Target_Dir ""
38 | # PROP Use_MFC 0
39 | # PROP Use_Debug_Libraries 0
40 | # PROP Output_Dir "Release"
41 | # PROP Intermediate_Dir "Release"
42 | # PROP Target_Dir ""
43 | MTL=midl.exe
44 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
45 | # ADD CPP /nologo /W3 /O2 /I "include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
46 | # SUBTRACT CPP /YX
47 | # ADD BASE RSC /l 0x409 /d "NDEBUG"
48 | # ADD RSC /l 0x409 /d "NDEBUG"
49 | BSC32=bscmake.exe
50 | # ADD BASE BSC32 /nologo
51 | # ADD BSC32 /nologo
52 | LIB32=link.exe -lib
53 | # ADD BASE LIB32 /nologo
54 | # ADD LIB32 /nologo
55 |
56 | !ELSEIF "$(CFG)" == "enet - Win32 Debug"
57 |
58 | # PROP BASE Use_MFC 0
59 | # PROP BASE Use_Debug_Libraries 1
60 | # PROP BASE Output_Dir "Debug"
61 | # PROP BASE Intermediate_Dir "Debug"
62 | # PROP BASE Target_Dir ""
63 | # PROP Use_MFC 0
64 | # PROP Use_Debug_Libraries 1
65 | # PROP Output_Dir "Debug"
66 | # PROP Intermediate_Dir "Debug"
67 | # PROP Target_Dir ""
68 | MTL=midl.exe
69 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
70 | # ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c
71 | # SUBTRACT CPP /YX
72 | # ADD BASE RSC /l 0x409 /d "_DEBUG"
73 | # ADD RSC /l 0x409 /d "_DEBUG"
74 | BSC32=bscmake.exe
75 | # ADD BASE BSC32 /nologo
76 | # ADD BSC32 /nologo
77 | LIB32=link.exe -lib
78 | # ADD BASE LIB32 /nologo
79 | # ADD LIB32 /nologo
80 |
81 | !ENDIF
82 |
83 | # Begin Target
84 |
85 | # Name "enet - Win32 Release"
86 | # Name "enet - Win32 Debug"
87 | # Begin Group "Source Files"
88 |
89 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
90 | # Begin Source File
91 |
92 | SOURCE=.\host.c
93 | # End Source File
94 | # Begin Source File
95 |
96 | SOURCE=.\list.c
97 | # End Source File
98 | # Begin Source File
99 |
100 | SOURCE=.\callbacks.c
101 | # End Source File
102 | # Begin Source File
103 |
104 | SOURCE=.\compress.c
105 | # End Source File
106 | # Begin Source File
107 |
108 | SOURCE=.\packet.c
109 | # End Source File
110 | # Begin Source File
111 |
112 | SOURCE=.\peer.c
113 | # End Source File
114 | # Begin Source File
115 |
116 | SOURCE=.\protocol.c
117 | # End Source File
118 | # Begin Source File
119 |
120 | SOURCE=.\unix.c
121 | # End Source File
122 | # Begin Source File
123 |
124 | SOURCE=.\win32.c
125 | # End Source File
126 | # End Group
127 | # Begin Group "Header Files"
128 |
129 | # PROP Default_Filter "h;hpp;hxx;hm;inl"
130 | # Begin Source File
131 |
132 | SOURCE=.\include\enet\enet.h
133 | # End Source File
134 | # Begin Source File
135 |
136 | SOURCE=.\include\enet\list.h
137 | # End Source File
138 | # Begin Source File
139 |
140 | SOURCE=.\include\enet\callbacks.h
141 | # End Source File
142 | # Begin Source File
143 |
144 | SOURCE=.\include\enet\protocol.h
145 | # End Source File
146 | # Begin Source File
147 |
148 | SOURCE=.\include\enet\time.h
149 | # End Source File
150 | # Begin Source File
151 |
152 | SOURCE=.\include\enet\types.h
153 | # End Source File
154 | # Begin Source File
155 |
156 | SOURCE=.\include\enet\unix.h
157 | # End Source File
158 | # Begin Source File
159 |
160 | SOURCE=.\include\enet\utility.h
161 | # End Source File
162 | # Begin Source File
163 |
164 | SOURCE=.\include\enet\win32.h
165 | # End Source File
166 | # End Group
167 | # End Target
168 | # End Project
169 |
--------------------------------------------------------------------------------
/enet_dll.cbp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/host.c:
--------------------------------------------------------------------------------
1 | /**
2 | @file host.c
3 | @brief ENet host management functions
4 | */
5 | #define ENET_BUILDING_LIB 1
6 | #include
7 | #include "enet/enet.h"
8 |
9 | /** @defgroup host ENet host functions
10 | @{
11 | */
12 |
13 | /** Creates a host for communicating to peers.
14 |
15 | @param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host.
16 | @param peerCount the maximum number of peers that should be allocated for the host.
17 | @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
18 | @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
19 | @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
20 |
21 | @returns the host on success and NULL on failure
22 |
23 | @remarks ENet will strategically drop packets on specific sides of a connection between hosts
24 | to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine
25 | the window size of a connection which limits the amount of reliable packets that may be in transit
26 | at any given time.
27 | */
28 | ENetHost *
29 | enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
30 | {
31 | ENetHost * host;
32 | ENetPeer * currentPeer;
33 |
34 | if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
35 | return NULL;
36 |
37 | host = (ENetHost *) enet_malloc (sizeof (ENetHost));
38 | if (host == NULL)
39 | return NULL;
40 | memset (host, 0, sizeof (ENetHost));
41 |
42 | host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer));
43 | if (host -> peers == NULL)
44 | {
45 | enet_free (host);
46 |
47 | return NULL;
48 | }
49 | memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
50 |
51 | host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
52 | if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0))
53 | {
54 | if (host -> socket != ENET_SOCKET_NULL)
55 | enet_socket_destroy (host -> socket);
56 |
57 | enet_free (host -> peers);
58 | enet_free (host);
59 |
60 | return NULL;
61 | }
62 |
63 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1);
64 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1);
65 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
66 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
67 |
68 | if (address != NULL && enet_socket_get_address (host -> socket, & host -> address) < 0)
69 | host -> address = * address;
70 |
71 | if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
72 | channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
73 | else
74 | if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
75 | channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
76 |
77 | host -> randomSeed = (enet_uint32) (size_t) host;
78 | host -> randomSeed += enet_host_random_seed ();
79 | host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16);
80 | host -> channelLimit = channelLimit;
81 | host -> incomingBandwidth = incomingBandwidth;
82 | host -> outgoingBandwidth = outgoingBandwidth;
83 | host -> bandwidthThrottleEpoch = 0;
84 | host -> recalculateBandwidthLimits = 0;
85 | host -> mtu = ENET_HOST_DEFAULT_MTU;
86 | host -> peerCount = peerCount;
87 | host -> commandCount = 0;
88 | host -> bufferCount = 0;
89 | host -> checksum = NULL;
90 | host -> receivedAddress.host = ENET_HOST_ANY;
91 | host -> receivedAddress.port = 0;
92 | host -> receivedData = NULL;
93 | host -> receivedDataLength = 0;
94 |
95 | host -> totalSentData = 0;
96 | host -> totalSentPackets = 0;
97 | host -> totalReceivedData = 0;
98 | host -> totalReceivedPackets = 0;
99 | host -> totalQueued = 0;
100 |
101 | host -> connectedPeers = 0;
102 | host -> bandwidthLimitedPeers = 0;
103 | host -> duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID;
104 | host -> maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE;
105 | host -> maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA;
106 |
107 | host -> compressor.context = NULL;
108 | host -> compressor.compress = NULL;
109 | host -> compressor.decompress = NULL;
110 | host -> compressor.destroy = NULL;
111 |
112 | host -> intercept = NULL;
113 |
114 | enet_list_clear (& host -> dispatchQueue);
115 |
116 | for (currentPeer = host -> peers;
117 | currentPeer < & host -> peers [host -> peerCount];
118 | ++ currentPeer)
119 | {
120 | currentPeer -> host = host;
121 | currentPeer -> incomingPeerID = currentPeer - host -> peers;
122 | currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF;
123 | currentPeer -> data = NULL;
124 |
125 | enet_list_clear (& currentPeer -> acknowledgements);
126 | enet_list_clear (& currentPeer -> sentReliableCommands);
127 | enet_list_clear (& currentPeer -> outgoingCommands);
128 | enet_list_clear (& currentPeer -> outgoingSendReliableCommands);
129 | enet_list_clear (& currentPeer -> dispatchedCommands);
130 |
131 | enet_peer_reset (currentPeer);
132 | }
133 |
134 | return host;
135 | }
136 |
137 | /** Destroys the host and all resources associated with it.
138 | @param host pointer to the host to destroy
139 | */
140 | void
141 | enet_host_destroy (ENetHost * host)
142 | {
143 | ENetPeer * currentPeer;
144 |
145 | if (host == NULL)
146 | return;
147 |
148 | enet_socket_destroy (host -> socket);
149 |
150 | for (currentPeer = host -> peers;
151 | currentPeer < & host -> peers [host -> peerCount];
152 | ++ currentPeer)
153 | {
154 | enet_peer_reset (currentPeer);
155 | }
156 |
157 | if (host -> compressor.context != NULL && host -> compressor.destroy)
158 | (* host -> compressor.destroy) (host -> compressor.context);
159 |
160 | enet_free (host -> peers);
161 | enet_free (host);
162 | }
163 |
164 | enet_uint32
165 | enet_host_random (ENetHost * host)
166 | {
167 | /* Mulberry32 by Tommy Ettinger */
168 | enet_uint32 n = (host -> randomSeed += 0x6D2B79F5U);
169 | n = (n ^ (n >> 15)) * (n | 1U);
170 | n ^= n + (n ^ (n >> 7)) * (n | 61U);
171 | return n ^ (n >> 14);
172 | }
173 |
174 | /** Initiates a connection to a foreign host.
175 | @param host host seeking the connection
176 | @param address destination for the connection
177 | @param channelCount number of channels to allocate
178 | @param data user data supplied to the receiving host
179 | @returns a peer representing the foreign host on success, NULL on failure
180 | @remarks The peer returned will have not completed the connection until enet_host_service()
181 | notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
182 | */
183 | ENetPeer *
184 | enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data)
185 | {
186 | ENetPeer * currentPeer;
187 | ENetChannel * channel;
188 | ENetProtocol command;
189 |
190 | if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
191 | channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
192 | else
193 | if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
194 | channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
195 |
196 | for (currentPeer = host -> peers;
197 | currentPeer < & host -> peers [host -> peerCount];
198 | ++ currentPeer)
199 | {
200 | if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
201 | break;
202 | }
203 |
204 | if (currentPeer >= & host -> peers [host -> peerCount])
205 | return NULL;
206 |
207 | currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
208 | if (currentPeer -> channels == NULL)
209 | return NULL;
210 | currentPeer -> channelCount = channelCount;
211 | currentPeer -> state = ENET_PEER_STATE_CONNECTING;
212 | currentPeer -> address = * address;
213 | currentPeer -> connectID = enet_host_random (host);
214 | currentPeer -> mtu = host -> mtu;
215 |
216 | if (host -> outgoingBandwidth == 0)
217 | currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
218 | else
219 | currentPeer -> windowSize = (host -> outgoingBandwidth /
220 | ENET_PEER_WINDOW_SIZE_SCALE) *
221 | ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
222 |
223 | if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
224 | currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
225 | else
226 | if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
227 | currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
228 |
229 | for (channel = currentPeer -> channels;
230 | channel < & currentPeer -> channels [channelCount];
231 | ++ channel)
232 | {
233 | channel -> outgoingReliableSequenceNumber = 0;
234 | channel -> outgoingUnreliableSequenceNumber = 0;
235 | channel -> incomingReliableSequenceNumber = 0;
236 | channel -> incomingUnreliableSequenceNumber = 0;
237 |
238 | enet_list_clear (& channel -> incomingReliableCommands);
239 | enet_list_clear (& channel -> incomingUnreliableCommands);
240 |
241 | channel -> usedReliableWindows = 0;
242 | memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows));
243 | }
244 |
245 | command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
246 | command.header.channelID = 0xFF;
247 | command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
248 | command.connect.incomingSessionID = currentPeer -> incomingSessionID;
249 | command.connect.outgoingSessionID = currentPeer -> outgoingSessionID;
250 | command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu);
251 | command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize);
252 | command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount);
253 | command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth);
254 | command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
255 | command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval);
256 | command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration);
257 | command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration);
258 | command.connect.connectID = currentPeer -> connectID;
259 | command.connect.data = ENET_HOST_TO_NET_32 (data);
260 |
261 | enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0);
262 |
263 | return currentPeer;
264 | }
265 |
266 | /** Queues a packet to be sent to all peers associated with the host.
267 | @param host host on which to broadcast the packet
268 | @param channelID channel on which to broadcast
269 | @param packet packet to broadcast
270 | */
271 | void
272 | enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet)
273 | {
274 | ENetPeer * currentPeer;
275 |
276 | for (currentPeer = host -> peers;
277 | currentPeer < & host -> peers [host -> peerCount];
278 | ++ currentPeer)
279 | {
280 | if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
281 | continue;
282 |
283 | enet_peer_send (currentPeer, channelID, packet);
284 | }
285 |
286 | if (packet -> referenceCount == 0)
287 | enet_packet_destroy (packet);
288 | }
289 |
290 | /** Sets the packet compressor the host should use to compress and decompress packets.
291 | @param host host to enable or disable compression for
292 | @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled
293 | */
294 | void
295 | enet_host_compress (ENetHost * host, const ENetCompressor * compressor)
296 | {
297 | if (host -> compressor.context != NULL && host -> compressor.destroy)
298 | (* host -> compressor.destroy) (host -> compressor.context);
299 |
300 | if (compressor)
301 | host -> compressor = * compressor;
302 | else
303 | host -> compressor.context = NULL;
304 | }
305 |
306 | /** Limits the maximum allowed channels of future incoming connections.
307 | @param host host to limit
308 | @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
309 | */
310 | void
311 | enet_host_channel_limit (ENetHost * host, size_t channelLimit)
312 | {
313 | if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
314 | channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
315 | else
316 | if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
317 | channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
318 |
319 | host -> channelLimit = channelLimit;
320 | }
321 |
322 |
323 | /** Adjusts the bandwidth limits of a host.
324 | @param host host to adjust
325 | @param incomingBandwidth new incoming bandwidth
326 | @param outgoingBandwidth new outgoing bandwidth
327 | @remarks the incoming and outgoing bandwidth parameters are identical in function to those
328 | specified in enet_host_create().
329 | */
330 | void
331 | enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
332 | {
333 | host -> incomingBandwidth = incomingBandwidth;
334 | host -> outgoingBandwidth = outgoingBandwidth;
335 | host -> recalculateBandwidthLimits = 1;
336 | }
337 |
338 | void
339 | enet_host_bandwidth_throttle (ENetHost * host)
340 | {
341 | enet_uint32 timeCurrent = enet_time_get (),
342 | elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch,
343 | peersRemaining = (enet_uint32) host -> connectedPeers,
344 | dataTotal = ~0,
345 | bandwidth = ~0,
346 | throttle = 0,
347 | bandwidthLimit = 0;
348 | int needsAdjustment = host -> bandwidthLimitedPeers > 0 ? 1 : 0;
349 | ENetPeer * peer;
350 | ENetProtocol command;
351 |
352 | if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
353 | return;
354 |
355 | host -> bandwidthThrottleEpoch = timeCurrent;
356 |
357 | if (peersRemaining == 0)
358 | return;
359 |
360 | if (host -> outgoingBandwidth != 0)
361 | {
362 | dataTotal = 0;
363 | bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000;
364 |
365 | for (peer = host -> peers;
366 | peer < & host -> peers [host -> peerCount];
367 | ++ peer)
368 | {
369 | if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
370 | continue;
371 |
372 | dataTotal += peer -> outgoingDataTotal;
373 | }
374 | }
375 |
376 | while (peersRemaining > 0 && needsAdjustment != 0)
377 | {
378 | needsAdjustment = 0;
379 |
380 | if (dataTotal <= bandwidth)
381 | throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
382 | else
383 | throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
384 |
385 | for (peer = host -> peers;
386 | peer < & host -> peers [host -> peerCount];
387 | ++ peer)
388 | {
389 | enet_uint32 peerBandwidth;
390 |
391 | if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
392 | peer -> incomingBandwidth == 0 ||
393 | peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
394 | continue;
395 |
396 | peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000;
397 | if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth)
398 | continue;
399 |
400 | peer -> packetThrottleLimit = (peerBandwidth *
401 | ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal;
402 |
403 | if (peer -> packetThrottleLimit == 0)
404 | peer -> packetThrottleLimit = 1;
405 |
406 | if (peer -> packetThrottle > peer -> packetThrottleLimit)
407 | peer -> packetThrottle = peer -> packetThrottleLimit;
408 |
409 | peer -> outgoingBandwidthThrottleEpoch = timeCurrent;
410 |
411 | peer -> incomingDataTotal = 0;
412 | peer -> outgoingDataTotal = 0;
413 |
414 | needsAdjustment = 1;
415 | -- peersRemaining;
416 | bandwidth -= peerBandwidth;
417 | dataTotal -= peerBandwidth;
418 | }
419 | }
420 |
421 | if (peersRemaining > 0)
422 | {
423 | if (dataTotal <= bandwidth)
424 | throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
425 | else
426 | throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
427 |
428 | for (peer = host -> peers;
429 | peer < & host -> peers [host -> peerCount];
430 | ++ peer)
431 | {
432 | if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
433 | peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
434 | continue;
435 |
436 | peer -> packetThrottleLimit = throttle;
437 |
438 | if (peer -> packetThrottle > peer -> packetThrottleLimit)
439 | peer -> packetThrottle = peer -> packetThrottleLimit;
440 |
441 | peer -> incomingDataTotal = 0;
442 | peer -> outgoingDataTotal = 0;
443 | }
444 | }
445 |
446 | if (host -> recalculateBandwidthLimits)
447 | {
448 | host -> recalculateBandwidthLimits = 0;
449 |
450 | peersRemaining = (enet_uint32) host -> connectedPeers;
451 | bandwidth = host -> incomingBandwidth;
452 | needsAdjustment = 1;
453 |
454 | if (bandwidth == 0)
455 | bandwidthLimit = 0;
456 | else
457 | while (peersRemaining > 0 && needsAdjustment != 0)
458 | {
459 | needsAdjustment = 0;
460 | bandwidthLimit = bandwidth / peersRemaining;
461 |
462 | for (peer = host -> peers;
463 | peer < & host -> peers [host -> peerCount];
464 | ++ peer)
465 | {
466 | if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
467 | peer -> incomingBandwidthThrottleEpoch == timeCurrent)
468 | continue;
469 |
470 | if (peer -> outgoingBandwidth > 0 &&
471 | peer -> outgoingBandwidth >= bandwidthLimit)
472 | continue;
473 |
474 | peer -> incomingBandwidthThrottleEpoch = timeCurrent;
475 |
476 | needsAdjustment = 1;
477 | -- peersRemaining;
478 | bandwidth -= peer -> outgoingBandwidth;
479 | }
480 | }
481 |
482 | for (peer = host -> peers;
483 | peer < & host -> peers [host -> peerCount];
484 | ++ peer)
485 | {
486 | if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
487 | continue;
488 |
489 | command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
490 | command.header.channelID = 0xFF;
491 | command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
492 |
493 | if (peer -> incomingBandwidthThrottleEpoch == timeCurrent)
494 | command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth);
495 | else
496 | command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit);
497 |
498 | enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
499 | }
500 | }
501 | }
502 |
503 | /** @} */
504 |
--------------------------------------------------------------------------------
/include/enet/callbacks.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file callbacks.h
3 | @brief ENet callbacks
4 | */
5 | #ifndef __ENET_CALLBACKS_H__
6 | #define __ENET_CALLBACKS_H__
7 |
8 | #include
9 |
10 | typedef struct _ENetCallbacks
11 | {
12 | void * (ENET_CALLBACK * malloc) (size_t size);
13 | void (ENET_CALLBACK * free) (void * memory);
14 | void (ENET_CALLBACK * no_memory) (void);
15 | } ENetCallbacks;
16 |
17 | #ifdef __cplusplus
18 | extern "C"
19 | {
20 | #endif
21 |
22 | /** @defgroup callbacks ENet internal callbacks
23 | @{
24 | @ingroup private
25 | */
26 |
27 | extern void * enet_malloc (size_t);
28 | extern void enet_free (void *);
29 |
30 | /** @} */
31 |
32 | #ifdef __cplusplus
33 | }
34 | #endif
35 |
36 | #endif /* __ENET_CALLBACKS_H__ */
37 |
38 |
--------------------------------------------------------------------------------
/include/enet/enet.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file enet.h
3 | @brief ENet public header file
4 | */
5 | #ifndef __ENET_ENET_H__
6 | #define __ENET_ENET_H__
7 |
8 | #include
9 |
10 | #ifdef _WIN32
11 | #include "enet/win32.h"
12 | #else
13 | #include "enet/unix.h"
14 | #endif
15 |
16 | #include "enet/types.h"
17 | #include "enet/protocol.h"
18 | #include "enet/list.h"
19 | #include "enet/callbacks.h"
20 |
21 | #define ENET_VERSION_MAJOR 1
22 | #define ENET_VERSION_MINOR 3
23 | #define ENET_VERSION_PATCH 18
24 | #define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch))
25 | #define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF)
26 | #define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF)
27 | #define ENET_VERSION_GET_PATCH(version) ((version)&0xFF)
28 | #define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH)
29 |
30 | typedef enet_uint32 ENetVersion;
31 |
32 | struct _ENetHost;
33 | struct _ENetEvent;
34 | struct _ENetPacket;
35 |
36 | typedef enum _ENetSocketType
37 | {
38 | ENET_SOCKET_TYPE_STREAM = 1,
39 | ENET_SOCKET_TYPE_DATAGRAM = 2
40 | } ENetSocketType;
41 |
42 | typedef enum _ENetSocketWait
43 | {
44 | ENET_SOCKET_WAIT_NONE = 0,
45 | ENET_SOCKET_WAIT_SEND = (1 << 0),
46 | ENET_SOCKET_WAIT_RECEIVE = (1 << 1),
47 | ENET_SOCKET_WAIT_INTERRUPT = (1 << 2)
48 | } ENetSocketWait;
49 |
50 | typedef enum _ENetSocketOption
51 | {
52 | ENET_SOCKOPT_NONBLOCK = 1,
53 | ENET_SOCKOPT_BROADCAST = 2,
54 | ENET_SOCKOPT_RCVBUF = 3,
55 | ENET_SOCKOPT_SNDBUF = 4,
56 | ENET_SOCKOPT_REUSEADDR = 5,
57 | ENET_SOCKOPT_RCVTIMEO = 6,
58 | ENET_SOCKOPT_SNDTIMEO = 7,
59 | ENET_SOCKOPT_ERROR = 8,
60 | ENET_SOCKOPT_NODELAY = 9,
61 | ENET_SOCKOPT_TTL = 10
62 | } ENetSocketOption;
63 |
64 | typedef enum _ENetSocketShutdown
65 | {
66 | ENET_SOCKET_SHUTDOWN_READ = 0,
67 | ENET_SOCKET_SHUTDOWN_WRITE = 1,
68 | ENET_SOCKET_SHUTDOWN_READ_WRITE = 2
69 | } ENetSocketShutdown;
70 |
71 | #define ENET_HOST_ANY 0
72 | #define ENET_HOST_BROADCAST 0xFFFFFFFFU
73 | #define ENET_PORT_ANY 0
74 |
75 | /**
76 | * Portable internet address structure.
77 | *
78 | * The host must be specified in network byte-order, and the port must be in host
79 | * byte-order. The constant ENET_HOST_ANY may be used to specify the default
80 | * server host. The constant ENET_HOST_BROADCAST may be used to specify the
81 | * broadcast address (255.255.255.255). This makes sense for enet_host_connect,
82 | * but not for enet_host_create. Once a server responds to a broadcast, the
83 | * address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
84 | */
85 | typedef struct _ENetAddress
86 | {
87 | enet_uint32 host;
88 | enet_uint16 port;
89 | } ENetAddress;
90 |
91 | /**
92 | * Packet flag bit constants.
93 | *
94 | * The host must be specified in network byte-order, and the port must be in
95 | * host byte-order. The constant ENET_HOST_ANY may be used to specify the
96 | * default server host.
97 |
98 | @sa ENetPacket
99 | */
100 | typedef enum _ENetPacketFlag
101 | {
102 | /** packet must be received by the target peer and resend attempts should be
103 | * made until the packet is delivered */
104 | ENET_PACKET_FLAG_RELIABLE = (1 << 0),
105 | /** packet will not be sequenced with other packets
106 | */
107 | ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1),
108 | /** packet will not allocate data, and user must supply it instead */
109 | ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2),
110 | /** packet will be fragmented using unreliable (instead of reliable) sends
111 | * if it exceeds the MTU */
112 | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3),
113 |
114 | /** whether the packet has been sent from all queues it has been entered into */
115 | ENET_PACKET_FLAG_SENT = (1<<8)
116 | } ENetPacketFlag;
117 |
118 | typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *);
119 |
120 | /**
121 | * ENet packet structure.
122 | *
123 | * An ENet data packet that may be sent to or received from a peer. The shown
124 | * fields should only be read and never modified. The data field contains the
125 | * allocated data for the packet. The dataLength fields specifies the length
126 | * of the allocated data. The flags field is either 0 (specifying no flags),
127 | * or a bitwise-or of any combination of the following flags:
128 | *
129 | * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer
130 | * and resend attempts should be made until the packet is delivered
131 | *
132 | * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets
133 | * (not supported for reliable packets)
134 | *
135 | * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead
136 | *
137 | * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable
138 | * (instead of reliable) sends if it exceeds the MTU
139 | *
140 | * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into
141 | @sa ENetPacketFlag
142 | */
143 | typedef struct _ENetPacket
144 | {
145 | size_t referenceCount; /**< internal use only */
146 | enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */
147 | enet_uint8 * data; /**< allocated data for packet */
148 | size_t dataLength; /**< length of data */
149 | ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */
150 | void * userData; /**< application private data, may be freely modified */
151 | } ENetPacket;
152 |
153 | typedef struct _ENetAcknowledgement
154 | {
155 | ENetListNode acknowledgementList;
156 | enet_uint32 sentTime;
157 | ENetProtocol command;
158 | } ENetAcknowledgement;
159 |
160 | typedef struct _ENetOutgoingCommand
161 | {
162 | ENetListNode outgoingCommandList;
163 | enet_uint16 reliableSequenceNumber;
164 | enet_uint16 unreliableSequenceNumber;
165 | enet_uint32 sentTime;
166 | enet_uint32 roundTripTimeout;
167 | enet_uint32 queueTime;
168 | enet_uint32 fragmentOffset;
169 | enet_uint16 fragmentLength;
170 | enet_uint16 sendAttempts;
171 | ENetProtocol command;
172 | ENetPacket * packet;
173 | } ENetOutgoingCommand;
174 |
175 | typedef struct _ENetIncomingCommand
176 | {
177 | ENetListNode incomingCommandList;
178 | enet_uint16 reliableSequenceNumber;
179 | enet_uint16 unreliableSequenceNumber;
180 | ENetProtocol command;
181 | enet_uint32 fragmentCount;
182 | enet_uint32 fragmentsRemaining;
183 | enet_uint32 * fragments;
184 | ENetPacket * packet;
185 | } ENetIncomingCommand;
186 |
187 | typedef enum _ENetPeerState
188 | {
189 | ENET_PEER_STATE_DISCONNECTED = 0,
190 | ENET_PEER_STATE_CONNECTING = 1,
191 | ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2,
192 | ENET_PEER_STATE_CONNECTION_PENDING = 3,
193 | ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4,
194 | ENET_PEER_STATE_CONNECTED = 5,
195 | ENET_PEER_STATE_DISCONNECT_LATER = 6,
196 | ENET_PEER_STATE_DISCONNECTING = 7,
197 | ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8,
198 | ENET_PEER_STATE_ZOMBIE = 9
199 | } ENetPeerState;
200 |
201 | #ifndef ENET_BUFFER_MAXIMUM
202 | #define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS)
203 | #endif
204 |
205 | enum
206 | {
207 | ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024,
208 | ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024,
209 | ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000,
210 | ENET_HOST_DEFAULT_MTU = 1392,
211 | ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024,
212 | ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024,
213 |
214 | ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500,
215 | ENET_PEER_DEFAULT_PACKET_THROTTLE = 32,
216 | ENET_PEER_PACKET_THROTTLE_SCALE = 32,
217 | ENET_PEER_PACKET_THROTTLE_COUNTER = 7,
218 | ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2,
219 | ENET_PEER_PACKET_THROTTLE_DECELERATION = 2,
220 | ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000,
221 | ENET_PEER_PACKET_LOSS_SCALE = (1 << 16),
222 | ENET_PEER_PACKET_LOSS_INTERVAL = 10000,
223 | ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024,
224 | ENET_PEER_TIMEOUT_LIMIT = 32,
225 | ENET_PEER_TIMEOUT_MINIMUM = 5000,
226 | ENET_PEER_TIMEOUT_MAXIMUM = 30000,
227 | ENET_PEER_PING_INTERVAL = 500,
228 | ENET_PEER_UNSEQUENCED_WINDOWS = 64,
229 | ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024,
230 | ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32,
231 | ENET_PEER_RELIABLE_WINDOWS = 16,
232 | ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000,
233 | ENET_PEER_FREE_RELIABLE_WINDOWS = 8
234 | };
235 |
236 | typedef struct _ENetChannel
237 | {
238 | enet_uint16 outgoingReliableSequenceNumber;
239 | enet_uint16 outgoingUnreliableSequenceNumber;
240 | enet_uint16 usedReliableWindows;
241 | enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS];
242 | enet_uint16 incomingReliableSequenceNumber;
243 | enet_uint16 incomingUnreliableSequenceNumber;
244 | ENetList incomingReliableCommands;
245 | ENetList incomingUnreliableCommands;
246 | } ENetChannel;
247 |
248 | typedef enum _ENetPeerFlag
249 | {
250 | ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0),
251 | ENET_PEER_FLAG_CONTINUE_SENDING = (1 << 1)
252 | } ENetPeerFlag;
253 |
254 | /**
255 | * An ENet peer which data packets may be sent or received from.
256 | *
257 | * No fields should be modified unless otherwise specified.
258 | */
259 | typedef struct _ENetPeer
260 | {
261 | ENetListNode dispatchList;
262 | struct _ENetHost * host;
263 | enet_uint16 outgoingPeerID;
264 | enet_uint16 incomingPeerID;
265 | enet_uint32 connectID;
266 | enet_uint8 outgoingSessionID;
267 | enet_uint8 incomingSessionID;
268 | ENetAddress address; /**< Internet address of the peer */
269 | void * data; /**< Application private data, may be freely modified */
270 | ENetPeerState state;
271 | ENetChannel * channels;
272 | size_t channelCount; /**< Number of channels allocated for communication with peer */
273 | enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */
274 | enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */
275 | enet_uint32 incomingBandwidthThrottleEpoch;
276 | enet_uint32 outgoingBandwidthThrottleEpoch;
277 | enet_uint32 incomingDataTotal;
278 | enet_uint32 outgoingDataTotal;
279 | enet_uint32 lastSendTime;
280 | enet_uint32 lastReceiveTime;
281 | enet_uint32 nextTimeout;
282 | enet_uint32 earliestTimeout;
283 | enet_uint32 packetLossEpoch;
284 | enet_uint32 packetsSent;
285 | enet_uint32 packetsLost;
286 | enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */
287 | enet_uint32 packetLossVariance;
288 | enet_uint32 packetThrottle;
289 | enet_uint32 packetThrottleLimit;
290 | enet_uint32 packetThrottleCounter;
291 | enet_uint32 packetThrottleEpoch;
292 | enet_uint32 packetThrottleAcceleration;
293 | enet_uint32 packetThrottleDeceleration;
294 | enet_uint32 packetThrottleInterval;
295 | enet_uint32 pingInterval;
296 | enet_uint32 timeoutLimit;
297 | enet_uint32 timeoutMinimum;
298 | enet_uint32 timeoutMaximum;
299 | enet_uint32 lastRoundTripTime;
300 | enet_uint32 lowestRoundTripTime;
301 | enet_uint32 lastRoundTripTimeVariance;
302 | enet_uint32 highestRoundTripTimeVariance;
303 | enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */
304 | enet_uint32 roundTripTimeVariance;
305 | enet_uint32 mtu;
306 | enet_uint32 windowSize;
307 | enet_uint32 reliableDataInTransit;
308 | enet_uint16 outgoingReliableSequenceNumber;
309 | ENetList acknowledgements;
310 | ENetList sentReliableCommands;
311 | ENetList outgoingSendReliableCommands;
312 | ENetList outgoingCommands;
313 | ENetList dispatchedCommands;
314 | enet_uint16 flags;
315 | enet_uint16 reserved;
316 | enet_uint16 incomingUnsequencedGroup;
317 | enet_uint16 outgoingUnsequencedGroup;
318 | enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32];
319 | enet_uint32 eventData;
320 | size_t totalWaitingData;
321 | } ENetPeer;
322 |
323 | /** An ENet packet compressor for compressing UDP packets before socket sends or receives.
324 | */
325 | typedef struct _ENetCompressor
326 | {
327 | /** Context data for the compressor. Must be non-NULL. */
328 | void * context;
329 | /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
330 | size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit);
331 | /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
332 | size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit);
333 | /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */
334 | void (ENET_CALLBACK * destroy) (void * context);
335 | } ENetCompressor;
336 |
337 | /** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */
338 | typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount);
339 |
340 | /** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */
341 | typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event);
342 |
343 | /** An ENet host for communicating with peers.
344 | *
345 | * No fields should be modified unless otherwise stated.
346 |
347 | @sa enet_host_create()
348 | @sa enet_host_destroy()
349 | @sa enet_host_connect()
350 | @sa enet_host_service()
351 | @sa enet_host_flush()
352 | @sa enet_host_broadcast()
353 | @sa enet_host_compress()
354 | @sa enet_host_compress_with_range_coder()
355 | @sa enet_host_channel_limit()
356 | @sa enet_host_bandwidth_limit()
357 | @sa enet_host_bandwidth_throttle()
358 | */
359 | typedef struct _ENetHost
360 | {
361 | ENetSocket socket;
362 | ENetAddress address; /**< Internet address of the host */
363 | enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */
364 | enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */
365 | enet_uint32 bandwidthThrottleEpoch;
366 | enet_uint32 mtu;
367 | enet_uint32 randomSeed;
368 | int recalculateBandwidthLimits;
369 | ENetPeer * peers; /**< array of peers allocated for this host */
370 | size_t peerCount; /**< number of peers allocated for this host */
371 | size_t channelLimit; /**< maximum number of channels allowed for connected peers */
372 | enet_uint32 serviceTime;
373 | ENetList dispatchQueue;
374 | enet_uint32 totalQueued;
375 | size_t packetSize;
376 | enet_uint16 headerFlags;
377 | ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS];
378 | size_t commandCount;
379 | ENetBuffer buffers [ENET_BUFFER_MAXIMUM];
380 | size_t bufferCount;
381 | ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */
382 | ENetCompressor compressor;
383 | enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU];
384 | ENetAddress receivedAddress;
385 | enet_uint8 * receivedData;
386 | size_t receivedDataLength;
387 | enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */
388 | enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */
389 | enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */
390 | enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */
391 | ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */
392 | size_t connectedPeers;
393 | size_t bandwidthLimitedPeers;
394 | size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */
395 | size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */
396 | size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */
397 | } ENetHost;
398 |
399 | /**
400 | * An ENet event type, as specified in @ref ENetEvent.
401 | */
402 | typedef enum _ENetEventType
403 | {
404 | /** no event occurred within the specified time limit */
405 | ENET_EVENT_TYPE_NONE = 0,
406 |
407 | /** a connection request initiated by enet_host_connect has completed.
408 | * The peer field contains the peer which successfully connected.
409 | */
410 | ENET_EVENT_TYPE_CONNECT = 1,
411 |
412 | /** a peer has disconnected. This event is generated on a successful
413 | * completion of a disconnect initiated by enet_peer_disconnect, if
414 | * a peer has timed out, or if a connection request intialized by
415 | * enet_host_connect has timed out. The peer field contains the peer
416 | * which disconnected. The data field contains user supplied data
417 | * describing the disconnection, or 0, if none is available.
418 | */
419 | ENET_EVENT_TYPE_DISCONNECT = 2,
420 |
421 | /** a packet has been received from a peer. The peer field specifies the
422 | * peer which sent the packet. The channelID field specifies the channel
423 | * number upon which the packet was received. The packet field contains
424 | * the packet that was received; this packet must be destroyed with
425 | * enet_packet_destroy after use.
426 | */
427 | ENET_EVENT_TYPE_RECEIVE = 3
428 | } ENetEventType;
429 |
430 | /**
431 | * An ENet event as returned by enet_host_service().
432 |
433 | @sa enet_host_service
434 | */
435 | typedef struct _ENetEvent
436 | {
437 | ENetEventType type; /**< type of the event */
438 | ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */
439 | enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */
440 | enet_uint32 data; /**< data associated with the event, if appropriate */
441 | ENetPacket * packet; /**< packet associated with the event, if appropriate */
442 | } ENetEvent;
443 |
444 | #ifdef __cplusplus
445 | extern "C"
446 | {
447 | #endif
448 |
449 | /** @defgroup global ENet global functions
450 | @{
451 | */
452 |
453 | /**
454 | Initializes ENet globally. Must be called prior to using any functions in
455 | ENet.
456 | @returns 0 on success, < 0 on failure
457 | */
458 | ENET_API int enet_initialize (void);
459 |
460 | /**
461 | Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored.
462 |
463 | @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use
464 | @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults
465 | @returns 0 on success, < 0 on failure
466 | */
467 | ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits);
468 |
469 | /**
470 | Shuts down ENet globally. Should be called when a program that has
471 | initialized ENet exits.
472 | */
473 | ENET_API void enet_deinitialize (void);
474 |
475 | /**
476 | Gives the linked version of the ENet library.
477 | @returns the version number
478 | */
479 | ENET_API ENetVersion enet_linked_version (void);
480 |
481 | /** @} */
482 |
483 | /** @defgroup private ENet private implementation functions */
484 |
485 | /**
486 | Returns the wall-time in milliseconds. Its initial value is unspecified
487 | unless otherwise set.
488 | */
489 | ENET_API enet_uint32 enet_time_get (void);
490 | /**
491 | Sets the current wall-time in milliseconds.
492 | */
493 | ENET_API void enet_time_set (enet_uint32);
494 |
495 | /** @defgroup socket ENet socket functions
496 | @{
497 | */
498 | ENET_API ENetSocket enet_socket_create (ENetSocketType);
499 | ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *);
500 | ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *);
501 | ENET_API int enet_socket_listen (ENetSocket, int);
502 | ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *);
503 | ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *);
504 | ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t);
505 | ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t);
506 | ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32);
507 | ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int);
508 | ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *);
509 | ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown);
510 | ENET_API void enet_socket_destroy (ENetSocket);
511 | ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32);
512 |
513 | /** @} */
514 |
515 | /** @defgroup Address ENet address functions
516 | @{
517 | */
518 |
519 | /** Attempts to parse the printable form of the IP address in the parameter hostName
520 | and sets the host field in the address parameter if successful.
521 | @param address destination to store the parsed IP address
522 | @param hostName IP address to parse
523 | @retval 0 on success
524 | @retval < 0 on failure
525 | @returns the address of the given hostName in address on success
526 | */
527 | ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostName);
528 |
529 | /** Attempts to resolve the host named by the parameter hostName and sets
530 | the host field in the address parameter if successful.
531 | @param address destination to store resolved address
532 | @param hostName host name to lookup
533 | @retval 0 on success
534 | @retval < 0 on failure
535 | @returns the address of the given hostName in address on success
536 | */
537 | ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName);
538 |
539 | /** Gives the printable form of the IP address specified in the address parameter.
540 | @param address address printed
541 | @param hostName destination for name, must not be NULL
542 | @param nameLength maximum length of hostName.
543 | @returns the null-terminated name of the host in hostName on success
544 | @retval 0 on success
545 | @retval < 0 on failure
546 | */
547 | ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength);
548 |
549 | /** Attempts to do a reverse lookup of the host field in the address parameter.
550 | @param address address used for reverse lookup
551 | @param hostName destination for name, must not be NULL
552 | @param nameLength maximum length of hostName.
553 | @returns the null-terminated name of the host in hostName on success
554 | @retval 0 on success
555 | @retval < 0 on failure
556 | */
557 | ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength);
558 |
559 | /** @} */
560 |
561 | ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32);
562 | ENET_API void enet_packet_destroy (ENetPacket *);
563 | ENET_API int enet_packet_resize (ENetPacket *, size_t);
564 | ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t);
565 |
566 | ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32);
567 | ENET_API void enet_host_destroy (ENetHost *);
568 | ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32);
569 | ENET_API int enet_host_check_events (ENetHost *, ENetEvent *);
570 | ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32);
571 | ENET_API void enet_host_flush (ENetHost *);
572 | ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *);
573 | ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *);
574 | ENET_API int enet_host_compress_with_range_coder (ENetHost * host);
575 | ENET_API void enet_host_channel_limit (ENetHost *, size_t);
576 | ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32);
577 | extern void enet_host_bandwidth_throttle (ENetHost *);
578 | extern enet_uint32 enet_host_random_seed (void);
579 | extern enet_uint32 enet_host_random (ENetHost *);
580 |
581 | ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *);
582 | ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID);
583 | ENET_API void enet_peer_ping (ENetPeer *);
584 | ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32);
585 | ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
586 | ENET_API void enet_peer_reset (ENetPeer *);
587 | ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32);
588 | ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32);
589 | ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32);
590 | ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
591 | extern int enet_peer_throttle (ENetPeer *, enet_uint32);
592 | extern void enet_peer_reset_queues (ENetPeer *);
593 | extern int enet_peer_has_outgoing_commands (ENetPeer *);
594 | extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *);
595 | extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16);
596 | extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32);
597 | extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16);
598 | extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *);
599 | extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *);
600 | extern void enet_peer_on_connect (ENetPeer *);
601 | extern void enet_peer_on_disconnect (ENetPeer *);
602 |
603 | ENET_API void * enet_range_coder_create (void);
604 | ENET_API void enet_range_coder_destroy (void *);
605 | ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t);
606 | ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t);
607 |
608 | extern size_t enet_protocol_command_size (enet_uint8);
609 |
610 | #ifdef __cplusplus
611 | }
612 | #endif
613 |
614 | #endif /* __ENET_ENET_H__ */
615 |
616 |
--------------------------------------------------------------------------------
/include/enet/list.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file list.h
3 | @brief ENet list management
4 | */
5 | #ifndef __ENET_LIST_H__
6 | #define __ENET_LIST_H__
7 |
8 | #include
9 |
10 | typedef struct _ENetListNode
11 | {
12 | struct _ENetListNode * next;
13 | struct _ENetListNode * previous;
14 | } ENetListNode;
15 |
16 | typedef ENetListNode * ENetListIterator;
17 |
18 | typedef struct _ENetList
19 | {
20 | ENetListNode sentinel;
21 | } ENetList;
22 |
23 | #ifdef __cplusplus
24 | extern "C"
25 | {
26 | #endif
27 |
28 | extern void enet_list_clear (ENetList *);
29 |
30 | extern ENetListIterator enet_list_insert (ENetListIterator, void *);
31 | extern void * enet_list_remove (ENetListIterator);
32 | extern ENetListIterator enet_list_move (ENetListIterator, void *, void *);
33 |
34 | extern size_t enet_list_size (ENetList *);
35 |
36 | #ifdef __cplusplus
37 | }
38 | #endif
39 |
40 | #define enet_list_begin(list) ((list) -> sentinel.next)
41 | #define enet_list_end(list) (& (list) -> sentinel)
42 |
43 | #define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list))
44 |
45 | #define enet_list_next(iterator) ((iterator) -> next)
46 | #define enet_list_previous(iterator) ((iterator) -> previous)
47 |
48 | #define enet_list_front(list) ((void *) (list) -> sentinel.next)
49 | #define enet_list_back(list) ((void *) (list) -> sentinel.previous)
50 |
51 | #endif /* __ENET_LIST_H__ */
52 |
53 |
--------------------------------------------------------------------------------
/include/enet/protocol.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file protocol.h
3 | @brief ENet protocol
4 | */
5 | #ifndef __ENET_PROTOCOL_H__
6 | #define __ENET_PROTOCOL_H__
7 |
8 | #include "enet/types.h"
9 |
10 | enum
11 | {
12 | ENET_PROTOCOL_MINIMUM_MTU = 576,
13 | ENET_PROTOCOL_MAXIMUM_MTU = 4096,
14 | ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32,
15 | ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096,
16 | ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536,
17 | ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1,
18 | ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255,
19 | ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF,
20 | ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024
21 | };
22 |
23 | typedef enum _ENetProtocolCommand
24 | {
25 | ENET_PROTOCOL_COMMAND_NONE = 0,
26 | ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1,
27 | ENET_PROTOCOL_COMMAND_CONNECT = 2,
28 | ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3,
29 | ENET_PROTOCOL_COMMAND_DISCONNECT = 4,
30 | ENET_PROTOCOL_COMMAND_PING = 5,
31 | ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6,
32 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7,
33 | ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8,
34 | ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9,
35 | ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10,
36 | ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11,
37 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12,
38 | ENET_PROTOCOL_COMMAND_COUNT = 13,
39 |
40 | ENET_PROTOCOL_COMMAND_MASK = 0x0F
41 | } ENetProtocolCommand;
42 |
43 | typedef enum _ENetProtocolFlag
44 | {
45 | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7),
46 | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6),
47 |
48 | ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14),
49 | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15),
50 | ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME,
51 |
52 | ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12),
53 | ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12
54 | } ENetProtocolFlag;
55 |
56 | #ifdef _MSC_VER
57 | #pragma pack(push, 1)
58 | #define ENET_PACKED
59 | #elif defined(__GNUC__) || defined(__clang__)
60 | #define ENET_PACKED __attribute__ ((packed))
61 | #else
62 | #define ENET_PACKED
63 | #endif
64 |
65 | typedef struct _ENetProtocolHeader
66 | {
67 | enet_uint16 peerID;
68 | enet_uint16 sentTime;
69 | } ENET_PACKED ENetProtocolHeader;
70 |
71 | typedef struct _ENetProtocolCommandHeader
72 | {
73 | enet_uint8 command;
74 | enet_uint8 channelID;
75 | enet_uint16 reliableSequenceNumber;
76 | } ENET_PACKED ENetProtocolCommandHeader;
77 |
78 | typedef struct _ENetProtocolAcknowledge
79 | {
80 | ENetProtocolCommandHeader header;
81 | enet_uint16 receivedReliableSequenceNumber;
82 | enet_uint16 receivedSentTime;
83 | } ENET_PACKED ENetProtocolAcknowledge;
84 |
85 | typedef struct _ENetProtocolConnect
86 | {
87 | ENetProtocolCommandHeader header;
88 | enet_uint16 outgoingPeerID;
89 | enet_uint8 incomingSessionID;
90 | enet_uint8 outgoingSessionID;
91 | enet_uint32 mtu;
92 | enet_uint32 windowSize;
93 | enet_uint32 channelCount;
94 | enet_uint32 incomingBandwidth;
95 | enet_uint32 outgoingBandwidth;
96 | enet_uint32 packetThrottleInterval;
97 | enet_uint32 packetThrottleAcceleration;
98 | enet_uint32 packetThrottleDeceleration;
99 | enet_uint32 connectID;
100 | enet_uint32 data;
101 | } ENET_PACKED ENetProtocolConnect;
102 |
103 | typedef struct _ENetProtocolVerifyConnect
104 | {
105 | ENetProtocolCommandHeader header;
106 | enet_uint16 outgoingPeerID;
107 | enet_uint8 incomingSessionID;
108 | enet_uint8 outgoingSessionID;
109 | enet_uint32 mtu;
110 | enet_uint32 windowSize;
111 | enet_uint32 channelCount;
112 | enet_uint32 incomingBandwidth;
113 | enet_uint32 outgoingBandwidth;
114 | enet_uint32 packetThrottleInterval;
115 | enet_uint32 packetThrottleAcceleration;
116 | enet_uint32 packetThrottleDeceleration;
117 | enet_uint32 connectID;
118 | } ENET_PACKED ENetProtocolVerifyConnect;
119 |
120 | typedef struct _ENetProtocolBandwidthLimit
121 | {
122 | ENetProtocolCommandHeader header;
123 | enet_uint32 incomingBandwidth;
124 | enet_uint32 outgoingBandwidth;
125 | } ENET_PACKED ENetProtocolBandwidthLimit;
126 |
127 | typedef struct _ENetProtocolThrottleConfigure
128 | {
129 | ENetProtocolCommandHeader header;
130 | enet_uint32 packetThrottleInterval;
131 | enet_uint32 packetThrottleAcceleration;
132 | enet_uint32 packetThrottleDeceleration;
133 | } ENET_PACKED ENetProtocolThrottleConfigure;
134 |
135 | typedef struct _ENetProtocolDisconnect
136 | {
137 | ENetProtocolCommandHeader header;
138 | enet_uint32 data;
139 | } ENET_PACKED ENetProtocolDisconnect;
140 |
141 | typedef struct _ENetProtocolPing
142 | {
143 | ENetProtocolCommandHeader header;
144 | } ENET_PACKED ENetProtocolPing;
145 |
146 | typedef struct _ENetProtocolSendReliable
147 | {
148 | ENetProtocolCommandHeader header;
149 | enet_uint16 dataLength;
150 | } ENET_PACKED ENetProtocolSendReliable;
151 |
152 | typedef struct _ENetProtocolSendUnreliable
153 | {
154 | ENetProtocolCommandHeader header;
155 | enet_uint16 unreliableSequenceNumber;
156 | enet_uint16 dataLength;
157 | } ENET_PACKED ENetProtocolSendUnreliable;
158 |
159 | typedef struct _ENetProtocolSendUnsequenced
160 | {
161 | ENetProtocolCommandHeader header;
162 | enet_uint16 unsequencedGroup;
163 | enet_uint16 dataLength;
164 | } ENET_PACKED ENetProtocolSendUnsequenced;
165 |
166 | typedef struct _ENetProtocolSendFragment
167 | {
168 | ENetProtocolCommandHeader header;
169 | enet_uint16 startSequenceNumber;
170 | enet_uint16 dataLength;
171 | enet_uint32 fragmentCount;
172 | enet_uint32 fragmentNumber;
173 | enet_uint32 totalLength;
174 | enet_uint32 fragmentOffset;
175 | } ENET_PACKED ENetProtocolSendFragment;
176 |
177 | typedef union _ENetProtocol
178 | {
179 | ENetProtocolCommandHeader header;
180 | ENetProtocolAcknowledge acknowledge;
181 | ENetProtocolConnect connect;
182 | ENetProtocolVerifyConnect verifyConnect;
183 | ENetProtocolDisconnect disconnect;
184 | ENetProtocolPing ping;
185 | ENetProtocolSendReliable sendReliable;
186 | ENetProtocolSendUnreliable sendUnreliable;
187 | ENetProtocolSendUnsequenced sendUnsequenced;
188 | ENetProtocolSendFragment sendFragment;
189 | ENetProtocolBandwidthLimit bandwidthLimit;
190 | ENetProtocolThrottleConfigure throttleConfigure;
191 | } ENET_PACKED ENetProtocol;
192 |
193 | #ifdef _MSC_VER
194 | #pragma pack(pop)
195 | #endif
196 |
197 | #endif /* __ENET_PROTOCOL_H__ */
198 |
199 |
--------------------------------------------------------------------------------
/include/enet/time.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file time.h
3 | @brief ENet time constants and macros
4 | */
5 | #ifndef __ENET_TIME_H__
6 | #define __ENET_TIME_H__
7 |
8 | #define ENET_TIME_OVERFLOW 86400000
9 |
10 | #define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW)
11 | #define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW)
12 | #define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b))
13 | #define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b))
14 |
15 | #define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b))
16 |
17 | #endif /* __ENET_TIME_H__ */
18 |
19 |
--------------------------------------------------------------------------------
/include/enet/types.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file types.h
3 | @brief type definitions for ENet
4 | */
5 | #ifndef __ENET_TYPES_H__
6 | #define __ENET_TYPES_H__
7 |
8 | typedef unsigned char enet_uint8; /**< unsigned 8-bit type */
9 | typedef unsigned short enet_uint16; /**< unsigned 16-bit type */
10 | typedef unsigned int enet_uint32; /**< unsigned 32-bit type */
11 |
12 | #endif /* __ENET_TYPES_H__ */
13 |
14 |
--------------------------------------------------------------------------------
/include/enet/unix.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file unix.h
3 | @brief ENet Unix header
4 | */
5 | #ifndef __ENET_UNIX_H__
6 | #define __ENET_UNIX_H__
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #ifdef MSG_MAXIOVLEN
17 | #define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN
18 | #endif
19 |
20 | typedef int ENetSocket;
21 |
22 | #define ENET_SOCKET_NULL -1
23 |
24 | #define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */
25 | #define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */
26 |
27 | #define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */
28 | #define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */
29 |
30 | typedef struct
31 | {
32 | void * data;
33 | size_t dataLength;
34 | } ENetBuffer;
35 |
36 | #define ENET_CALLBACK
37 |
38 | #define ENET_API extern
39 |
40 | typedef fd_set ENetSocketSet;
41 |
42 | #define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset))
43 | #define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset))
44 | #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
45 | #define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset))
46 |
47 | #endif /* __ENET_UNIX_H__ */
48 |
49 |
--------------------------------------------------------------------------------
/include/enet/utility.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file utility.h
3 | @brief ENet utility header
4 | */
5 | #ifndef __ENET_UTILITY_H__
6 | #define __ENET_UTILITY_H__
7 |
8 | #define ENET_MAX(x, y) ((x) > (y) ? (x) : (y))
9 | #define ENET_MIN(x, y) ((x) < (y) ? (x) : (y))
10 | #define ENET_DIFFERENCE(x, y) ((x) < (y) ? (y) - (x) : (x) - (y))
11 |
12 | #endif /* __ENET_UTILITY_H__ */
13 |
14 |
--------------------------------------------------------------------------------
/include/enet/win32.h:
--------------------------------------------------------------------------------
1 | /**
2 | @file win32.h
3 | @brief ENet Win32 header
4 | */
5 | #ifndef __ENET_WIN32_H__
6 | #define __ENET_WIN32_H__
7 |
8 | #ifdef _MSC_VER
9 | #ifdef ENET_BUILDING_LIB
10 | #pragma warning (disable: 4267) // size_t to int conversion
11 | #pragma warning (disable: 4244) // 64bit to 32bit int
12 | #pragma warning (disable: 4018) // signed/unsigned mismatch
13 | #pragma warning (disable: 4146) // unary minus operator applied to unsigned type
14 | #ifndef _CRT_SECURE_NO_DEPRECATE
15 | #define _CRT_SECURE_NO_DEPRECATE
16 | #endif
17 | #ifndef _CRT_SECURE_NO_WARNINGS
18 | #define _CRT_SECURE_NO_WARNINGS
19 | #endif
20 | #endif
21 | #endif
22 |
23 | #include
24 | #include
25 |
26 | typedef SOCKET ENetSocket;
27 |
28 | #define ENET_SOCKET_NULL INVALID_SOCKET
29 |
30 | #define ENET_HOST_TO_NET_16(value) (htons (value))
31 | #define ENET_HOST_TO_NET_32(value) (htonl (value))
32 |
33 | #define ENET_NET_TO_HOST_16(value) (ntohs (value))
34 | #define ENET_NET_TO_HOST_32(value) (ntohl (value))
35 |
36 | typedef struct
37 | {
38 | size_t dataLength;
39 | void * data;
40 | } ENetBuffer;
41 |
42 | #define ENET_CALLBACK __cdecl
43 |
44 | #ifdef ENET_DLL
45 | #ifdef ENET_BUILDING_LIB
46 | #define ENET_API __declspec( dllexport )
47 | #else
48 | #define ENET_API __declspec( dllimport )
49 | #endif /* ENET_BUILDING_LIB */
50 | #else /* !ENET_DLL */
51 | #define ENET_API extern
52 | #endif /* ENET_DLL */
53 |
54 | typedef fd_set ENetSocketSet;
55 |
56 | #define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset))
57 | #define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset))
58 | #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
59 | #define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset))
60 |
61 | #endif /* __ENET_WIN32_H__ */
62 |
63 |
64 |
--------------------------------------------------------------------------------
/libenet.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@prefix@
2 | exec_prefix=@exec_prefix@
3 | libdir=@libdir@
4 | includedir=@includedir@
5 |
6 | Name: @PACKAGE_NAME@
7 | Description: Low-latency UDP networking library supporting optional reliability
8 | Version: @PACKAGE_VERSION@
9 | Cflags: -I${includedir}
10 | Libs: -L${libdir} -lenet
11 |
--------------------------------------------------------------------------------
/list.c:
--------------------------------------------------------------------------------
1 | /**
2 | @file list.c
3 | @brief ENet linked list functions
4 | */
5 | #define ENET_BUILDING_LIB 1
6 | #include "enet/enet.h"
7 |
8 | /**
9 | @defgroup list ENet linked list utility functions
10 | @ingroup private
11 | @{
12 | */
13 | void
14 | enet_list_clear (ENetList * list)
15 | {
16 | list -> sentinel.next = & list -> sentinel;
17 | list -> sentinel.previous = & list -> sentinel;
18 | }
19 |
20 | ENetListIterator
21 | enet_list_insert (ENetListIterator position, void * data)
22 | {
23 | ENetListIterator result = (ENetListIterator) data;
24 |
25 | result -> previous = position -> previous;
26 | result -> next = position;
27 |
28 | result -> previous -> next = result;
29 | position -> previous = result;
30 |
31 | return result;
32 | }
33 |
34 | void *
35 | enet_list_remove (ENetListIterator position)
36 | {
37 | position -> previous -> next = position -> next;
38 | position -> next -> previous = position -> previous;
39 |
40 | return position;
41 | }
42 |
43 | ENetListIterator
44 | enet_list_move (ENetListIterator position, void * dataFirst, void * dataLast)
45 | {
46 | ENetListIterator first = (ENetListIterator) dataFirst,
47 | last = (ENetListIterator) dataLast;
48 |
49 | first -> previous -> next = last -> next;
50 | last -> next -> previous = first -> previous;
51 |
52 | first -> previous = position -> previous;
53 | last -> next = position;
54 |
55 | first -> previous -> next = first;
56 | position -> previous = last;
57 |
58 | return first;
59 | }
60 |
61 | size_t
62 | enet_list_size (ENetList * list)
63 | {
64 | size_t size = 0;
65 | ENetListIterator position;
66 |
67 | for (position = enet_list_begin (list);
68 | position != enet_list_end (list);
69 | position = enet_list_next (position))
70 | ++ size;
71 |
72 | return size;
73 | }
74 |
75 | /** @} */
76 |
--------------------------------------------------------------------------------
/m4/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lsalzman/enet/657eaf97d9d335917c58484a4a4b5e03838ebd8e/m4/.keep
--------------------------------------------------------------------------------
/packet.c:
--------------------------------------------------------------------------------
1 | /**
2 | @file packet.c
3 | @brief ENet packet management functions
4 | */
5 | #include
6 | #define ENET_BUILDING_LIB 1
7 | #include "enet/enet.h"
8 |
9 | /** @defgroup Packet ENet packet functions
10 | @{
11 | */
12 |
13 | /** Creates a packet that may be sent to a peer.
14 | @param data initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL.
15 | @param dataLength size of the data allocated for this packet
16 | @param flags flags for this packet as described for the ENetPacket structure.
17 | @returns the packet on success, NULL on failure
18 | */
19 | ENetPacket *
20 | enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags)
21 | {
22 | ENetPacket * packet = (ENetPacket *) enet_malloc (sizeof (ENetPacket));
23 | if (packet == NULL)
24 | return NULL;
25 |
26 | if (flags & ENET_PACKET_FLAG_NO_ALLOCATE)
27 | packet -> data = (enet_uint8 *) data;
28 | else
29 | if (dataLength <= 0)
30 | packet -> data = NULL;
31 | else
32 | {
33 | packet -> data = (enet_uint8 *) enet_malloc (dataLength);
34 | if (packet -> data == NULL)
35 | {
36 | enet_free (packet);
37 | return NULL;
38 | }
39 |
40 | if (data != NULL)
41 | memcpy (packet -> data, data, dataLength);
42 | }
43 |
44 | packet -> referenceCount = 0;
45 | packet -> flags = flags;
46 | packet -> dataLength = dataLength;
47 | packet -> freeCallback = NULL;
48 | packet -> userData = NULL;
49 |
50 | return packet;
51 | }
52 |
53 | /** Destroys the packet and deallocates its data.
54 | @param packet packet to be destroyed
55 | */
56 | void
57 | enet_packet_destroy (ENetPacket * packet)
58 | {
59 | if (packet == NULL)
60 | return;
61 |
62 | if (packet -> freeCallback != NULL)
63 | (* packet -> freeCallback) (packet);
64 | if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE) &&
65 | packet -> data != NULL)
66 | enet_free (packet -> data);
67 | enet_free (packet);
68 | }
69 |
70 | /** Attempts to resize the data in the packet to length specified in the
71 | dataLength parameter
72 | @param packet packet to resize
73 | @param dataLength new size for the packet data
74 | @returns 0 on success, < 0 on failure
75 | */
76 | int
77 | enet_packet_resize (ENetPacket * packet, size_t dataLength)
78 | {
79 | enet_uint8 * newData;
80 |
81 | if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE))
82 | {
83 | packet -> dataLength = dataLength;
84 |
85 | return 0;
86 | }
87 |
88 | newData = (enet_uint8 *) enet_malloc (dataLength);
89 | if (newData == NULL)
90 | return -1;
91 |
92 | if (packet -> data != NULL)
93 | {
94 | if (packet -> dataLength > 0)
95 | memcpy (newData, packet -> data, packet -> dataLength);
96 |
97 | enet_free (packet -> data);
98 | }
99 |
100 | packet -> data = newData;
101 | packet -> dataLength = dataLength;
102 |
103 | return 0;
104 | }
105 |
106 | static const enet_uint32 crcTable [256] =
107 | {
108 | 0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
109 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
110 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
111 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
112 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
113 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
114 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
115 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
116 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
117 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
118 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
119 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
120 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
121 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
122 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
123 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
124 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
125 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
126 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
127 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
128 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
129 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
130 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
131 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
132 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x5005713,
133 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21,
134 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
135 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
136 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
137 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
138 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
139 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
140 | };
141 |
142 | enet_uint32
143 | enet_crc32 (const ENetBuffer * buffers, size_t bufferCount)
144 | {
145 | enet_uint32 crc = 0xFFFFFFFF;
146 |
147 | while (bufferCount -- > 0)
148 | {
149 | const enet_uint8 * data = (const enet_uint8 *) buffers -> data,
150 | * dataEnd = & data [buffers -> dataLength];
151 |
152 | while (data < dataEnd)
153 | {
154 | crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++];
155 | }
156 |
157 | ++ buffers;
158 | }
159 |
160 | return ENET_HOST_TO_NET_32 (~ crc);
161 | }
162 |
163 | /** @} */
164 |
--------------------------------------------------------------------------------
/premake4.lua:
--------------------------------------------------------------------------------
1 | solution "enet"
2 | configurations { "Debug", "Release" }
3 | platforms { "x32", "x64" }
4 |
5 | project "enet_static"
6 | kind "StaticLib"
7 | language "C"
8 |
9 | files { "*.c" }
10 |
11 | includedirs { "include/" }
12 |
13 | configuration "Debug"
14 | targetsuffix "d"
15 |
16 | defines({ "DEBUG" })
17 |
18 | flags { "Symbols" }
19 |
20 | configuration "Release"
21 | defines({ "NDEBUG" })
22 |
23 | flags { "Optimize" }
24 |
25 | configuration { "Debug", "x64" }
26 | targetsuffix "64d"
27 |
28 | configuration { "Release", "x64" }
29 | targetsuffix "64"
30 |
31 | project "enet"
32 | kind "SharedLib"
33 | language "C"
34 |
35 | files { "*.c" }
36 |
37 | includedirs { "include/" }
38 |
39 | defines({"ENET_DLL=1" })
40 |
41 | configuration "Debug"
42 | targetsuffix "d"
43 |
44 | defines({ "DEBUG" })
45 |
46 | flags { "Symbols" }
47 |
48 | configuration "Release"
49 | defines({ "NDEBUG" })
50 |
51 | flags { "Optimize" }
52 |
53 | configuration { "Debug", "x64" }
54 | targetsuffix "64d"
55 |
56 | configuration { "Release", "x64" }
57 | targetsuffix "64"
58 |
59 |
--------------------------------------------------------------------------------
/unix.c:
--------------------------------------------------------------------------------
1 | /**
2 | @file unix.c
3 | @brief ENet Unix system specific functions
4 | */
5 | #ifndef _WIN32
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #define ENET_BUILDING_LIB 1
19 | #include "enet/enet.h"
20 |
21 | #ifdef __APPLE__
22 | #ifdef HAS_POLL
23 | #undef HAS_POLL
24 | #endif
25 | #ifndef HAS_FCNTL
26 | #define HAS_FCNTL 1
27 | #endif
28 | #ifndef HAS_INET_PTON
29 | #define HAS_INET_PTON 1
30 | #endif
31 | #ifndef HAS_INET_NTOP
32 | #define HAS_INET_NTOP 1
33 | #endif
34 | #ifndef HAS_MSGHDR_FLAGS
35 | #define HAS_MSGHDR_FLAGS 1
36 | #endif
37 | #ifndef HAS_SOCKLEN_T
38 | #define HAS_SOCKLEN_T 1
39 | #endif
40 | #ifndef HAS_GETADDRINFO
41 | #define HAS_GETADDRINFO 1
42 | #endif
43 | #ifndef HAS_GETNAMEINFO
44 | #define HAS_GETNAMEINFO 1
45 | #endif
46 | #endif
47 |
48 | #ifdef HAS_FCNTL
49 | #include
50 | #endif
51 |
52 | #ifdef HAS_POLL
53 | #include
54 | #endif
55 |
56 | #if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
57 | typedef int socklen_t;
58 | #endif
59 |
60 | #ifndef MSG_NOSIGNAL
61 | #define MSG_NOSIGNAL 0
62 | #endif
63 |
64 | static enet_uint32 timeBase = 0;
65 |
66 | int
67 | enet_initialize (void)
68 | {
69 | return 0;
70 | }
71 |
72 | void
73 | enet_deinitialize (void)
74 | {
75 | }
76 |
77 | enet_uint32
78 | enet_host_random_seed (void)
79 | {
80 | return (enet_uint32) time (NULL);
81 | }
82 |
83 | enet_uint32
84 | enet_time_get (void)
85 | {
86 | struct timeval timeVal;
87 |
88 | gettimeofday (& timeVal, NULL);
89 |
90 | return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase;
91 | }
92 |
93 | void
94 | enet_time_set (enet_uint32 newTimeBase)
95 | {
96 | struct timeval timeVal;
97 |
98 | gettimeofday (& timeVal, NULL);
99 |
100 | timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase;
101 | }
102 |
103 | int
104 | enet_address_set_host_ip (ENetAddress * address, const char * name)
105 | {
106 | #ifdef HAS_INET_PTON
107 | if (! inet_pton (AF_INET, name, & address -> host))
108 | #else
109 | if (! inet_aton (name, (struct in_addr *) & address -> host))
110 | #endif
111 | return -1;
112 |
113 | return 0;
114 | }
115 |
116 | int
117 | enet_address_set_host (ENetAddress * address, const char * name)
118 | {
119 | #ifdef HAS_GETADDRINFO
120 | struct addrinfo hints, * resultList = NULL, * result = NULL;
121 |
122 | memset (& hints, 0, sizeof (hints));
123 | hints.ai_family = AF_INET;
124 |
125 | if (getaddrinfo (name, NULL, NULL, & resultList) != 0)
126 | return -1;
127 |
128 | for (result = resultList; result != NULL; result = result -> ai_next)
129 | {
130 | if (result -> ai_family == AF_INET && result -> ai_addr != NULL && result -> ai_addrlen >= sizeof (struct sockaddr_in))
131 | {
132 | struct sockaddr_in * sin = (struct sockaddr_in *) result -> ai_addr;
133 |
134 | address -> host = sin -> sin_addr.s_addr;
135 |
136 | freeaddrinfo (resultList);
137 |
138 | return 0;
139 | }
140 | }
141 |
142 | if (resultList != NULL)
143 | freeaddrinfo (resultList);
144 | #else
145 | struct hostent * hostEntry = NULL;
146 | #ifdef HAS_GETHOSTBYNAME_R
147 | struct hostent hostData;
148 | char buffer [2048];
149 | int errnum;
150 |
151 | #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__GNU__)
152 | gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
153 | #else
154 | hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum);
155 | #endif
156 | #else
157 | hostEntry = gethostbyname (name);
158 | #endif
159 |
160 | if (hostEntry != NULL && hostEntry -> h_addrtype == AF_INET)
161 | {
162 | address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
163 |
164 | return 0;
165 | }
166 | #endif
167 |
168 | return enet_address_set_host_ip (address, name);
169 | }
170 |
171 | int
172 | enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
173 | {
174 | #ifdef HAS_INET_NTOP
175 | if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL)
176 | #else
177 | char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
178 | if (addr != NULL)
179 | {
180 | size_t addrLen = strlen(addr);
181 | if (addrLen >= nameLength)
182 | return -1;
183 | memcpy (name, addr, addrLen + 1);
184 | }
185 | else
186 | #endif
187 | return -1;
188 | return 0;
189 | }
190 |
191 | int
192 | enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
193 | {
194 | #ifdef HAS_GETNAMEINFO
195 | struct sockaddr_in sin;
196 | int err;
197 |
198 | memset (& sin, 0, sizeof (struct sockaddr_in));
199 |
200 | sin.sin_family = AF_INET;
201 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
202 | sin.sin_addr.s_addr = address -> host;
203 |
204 | err = getnameinfo ((struct sockaddr *) & sin, sizeof (sin), name, nameLength, NULL, 0, NI_NAMEREQD);
205 | if (! err)
206 | {
207 | if (name != NULL && nameLength > 0 && ! memchr (name, '\0', nameLength))
208 | return -1;
209 | return 0;
210 | }
211 | if (err != EAI_NONAME)
212 | return -1;
213 | #else
214 | struct in_addr in;
215 | struct hostent * hostEntry = NULL;
216 | #ifdef HAS_GETHOSTBYADDR_R
217 | struct hostent hostData;
218 | char buffer [2048];
219 | int errnum;
220 |
221 | in.s_addr = address -> host;
222 |
223 | #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__GNU__)
224 | gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
225 | #else
226 | hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum);
227 | #endif
228 | #else
229 | in.s_addr = address -> host;
230 |
231 | hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
232 | #endif
233 |
234 | if (hostEntry != NULL)
235 | {
236 | size_t hostLen = strlen (hostEntry -> h_name);
237 | if (hostLen >= nameLength)
238 | return -1;
239 | memcpy (name, hostEntry -> h_name, hostLen + 1);
240 | return 0;
241 | }
242 | #endif
243 |
244 | return enet_address_get_host_ip (address, name, nameLength);
245 | }
246 |
247 | int
248 | enet_socket_bind (ENetSocket socket, const ENetAddress * address)
249 | {
250 | struct sockaddr_in sin;
251 |
252 | memset (& sin, 0, sizeof (struct sockaddr_in));
253 |
254 | sin.sin_family = AF_INET;
255 |
256 | if (address != NULL)
257 | {
258 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
259 | sin.sin_addr.s_addr = address -> host;
260 | }
261 | else
262 | {
263 | sin.sin_port = 0;
264 | sin.sin_addr.s_addr = INADDR_ANY;
265 | }
266 |
267 | return bind (socket,
268 | (struct sockaddr *) & sin,
269 | sizeof (struct sockaddr_in));
270 | }
271 |
272 | int
273 | enet_socket_get_address (ENetSocket socket, ENetAddress * address)
274 | {
275 | struct sockaddr_in sin;
276 | socklen_t sinLength = sizeof (struct sockaddr_in);
277 |
278 | if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
279 | return -1;
280 |
281 | address -> host = (enet_uint32) sin.sin_addr.s_addr;
282 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
283 |
284 | return 0;
285 | }
286 |
287 | int
288 | enet_socket_listen (ENetSocket socket, int backlog)
289 | {
290 | return listen (socket, backlog < 0 ? SOMAXCONN : backlog);
291 | }
292 |
293 | ENetSocket
294 | enet_socket_create (ENetSocketType type)
295 | {
296 | return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
297 | }
298 |
299 | int
300 | enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
301 | {
302 | int result = -1;
303 | switch (option)
304 | {
305 | case ENET_SOCKOPT_NONBLOCK:
306 | #ifdef HAS_FCNTL
307 | result = fcntl (socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl (socket, F_GETFL) & ~O_NONBLOCK));
308 | #else
309 | result = ioctl (socket, FIONBIO, & value);
310 | #endif
311 | break;
312 |
313 | case ENET_SOCKOPT_BROADCAST:
314 | result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int));
315 | break;
316 |
317 | case ENET_SOCKOPT_REUSEADDR:
318 | result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int));
319 | break;
320 |
321 | case ENET_SOCKOPT_RCVBUF:
322 | result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int));
323 | break;
324 |
325 | case ENET_SOCKOPT_SNDBUF:
326 | result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int));
327 | break;
328 |
329 | case ENET_SOCKOPT_RCVTIMEO:
330 | {
331 | struct timeval timeVal;
332 | timeVal.tv_sec = value / 1000;
333 | timeVal.tv_usec = (value % 1000) * 1000;
334 | result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & timeVal, sizeof (struct timeval));
335 | break;
336 | }
337 |
338 | case ENET_SOCKOPT_SNDTIMEO:
339 | {
340 | struct timeval timeVal;
341 | timeVal.tv_sec = value / 1000;
342 | timeVal.tv_usec = (value % 1000) * 1000;
343 | result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & timeVal, sizeof (struct timeval));
344 | break;
345 | }
346 |
347 | case ENET_SOCKOPT_NODELAY:
348 | result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int));
349 | break;
350 |
351 | case ENET_SOCKOPT_TTL:
352 | result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int));
353 | break;
354 |
355 | default:
356 | break;
357 | }
358 | return result == -1 ? -1 : 0;
359 | }
360 |
361 | int
362 | enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
363 | {
364 | int result = -1;
365 | socklen_t len;
366 | switch (option)
367 | {
368 | case ENET_SOCKOPT_ERROR:
369 | len = sizeof (int);
370 | result = getsockopt (socket, SOL_SOCKET, SO_ERROR, value, & len);
371 | break;
372 |
373 | case ENET_SOCKOPT_TTL:
374 | len = sizeof (int);
375 | result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len);
376 | break;
377 |
378 | default:
379 | break;
380 | }
381 | return result == -1 ? -1 : 0;
382 | }
383 |
384 | int
385 | enet_socket_connect (ENetSocket socket, const ENetAddress * address)
386 | {
387 | struct sockaddr_in sin;
388 | int result;
389 |
390 | memset (& sin, 0, sizeof (struct sockaddr_in));
391 |
392 | sin.sin_family = AF_INET;
393 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
394 | sin.sin_addr.s_addr = address -> host;
395 |
396 | result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
397 | if (result == -1 && errno == EINPROGRESS)
398 | return 0;
399 |
400 | return result;
401 | }
402 |
403 | ENetSocket
404 | enet_socket_accept (ENetSocket socket, ENetAddress * address)
405 | {
406 | int result;
407 | struct sockaddr_in sin;
408 | socklen_t sinLength = sizeof (struct sockaddr_in);
409 |
410 | result = accept (socket,
411 | address != NULL ? (struct sockaddr *) & sin : NULL,
412 | address != NULL ? & sinLength : NULL);
413 |
414 | if (result == -1)
415 | return ENET_SOCKET_NULL;
416 |
417 | if (address != NULL)
418 | {
419 | address -> host = (enet_uint32) sin.sin_addr.s_addr;
420 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
421 | }
422 |
423 | return result;
424 | }
425 |
426 | int
427 | enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how)
428 | {
429 | return shutdown (socket, (int) how);
430 | }
431 |
432 | void
433 | enet_socket_destroy (ENetSocket socket)
434 | {
435 | if (socket != -1)
436 | close (socket);
437 | }
438 |
439 | int
440 | enet_socket_send (ENetSocket socket,
441 | const ENetAddress * address,
442 | const ENetBuffer * buffers,
443 | size_t bufferCount)
444 | {
445 | struct msghdr msgHdr;
446 | struct sockaddr_in sin;
447 | int sentLength;
448 |
449 | memset (& msgHdr, 0, sizeof (struct msghdr));
450 |
451 | if (address != NULL)
452 | {
453 | memset (& sin, 0, sizeof (struct sockaddr_in));
454 |
455 | sin.sin_family = AF_INET;
456 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
457 | sin.sin_addr.s_addr = address -> host;
458 |
459 | msgHdr.msg_name = & sin;
460 | msgHdr.msg_namelen = sizeof (struct sockaddr_in);
461 | }
462 |
463 | msgHdr.msg_iov = (struct iovec *) buffers;
464 | msgHdr.msg_iovlen = bufferCount;
465 |
466 | sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL);
467 |
468 | if (sentLength == -1)
469 | {
470 | if (errno == EWOULDBLOCK)
471 | return 0;
472 |
473 | return -1;
474 | }
475 |
476 | return sentLength;
477 | }
478 |
479 | int
480 | enet_socket_receive (ENetSocket socket,
481 | ENetAddress * address,
482 | ENetBuffer * buffers,
483 | size_t bufferCount)
484 | {
485 | struct msghdr msgHdr;
486 | struct sockaddr_in sin;
487 | int recvLength;
488 |
489 | memset (& msgHdr, 0, sizeof (struct msghdr));
490 |
491 | if (address != NULL)
492 | {
493 | msgHdr.msg_name = & sin;
494 | msgHdr.msg_namelen = sizeof (struct sockaddr_in);
495 | }
496 |
497 | msgHdr.msg_iov = (struct iovec *) buffers;
498 | msgHdr.msg_iovlen = bufferCount;
499 |
500 | recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL);
501 |
502 | if (recvLength == -1)
503 | {
504 | switch (errno)
505 | {
506 | case EWOULDBLOCK:
507 | return 0;
508 | case EINTR:
509 | case EMSGSIZE:
510 | return -2;
511 | default:
512 | return -1;
513 | }
514 | }
515 |
516 | #ifdef HAS_MSGHDR_FLAGS
517 | if (msgHdr.msg_flags & MSG_TRUNC)
518 | return -2;
519 | #endif
520 |
521 | if (address != NULL)
522 | {
523 | address -> host = (enet_uint32) sin.sin_addr.s_addr;
524 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
525 | }
526 |
527 | return recvLength;
528 | }
529 |
530 | int
531 | enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout)
532 | {
533 | struct timeval timeVal;
534 |
535 | timeVal.tv_sec = timeout / 1000;
536 | timeVal.tv_usec = (timeout % 1000) * 1000;
537 |
538 | return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal);
539 | }
540 |
541 | int
542 | enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout)
543 | {
544 | #ifdef HAS_POLL
545 | struct pollfd pollSocket;
546 | int pollCount;
547 |
548 | pollSocket.fd = socket;
549 | pollSocket.events = 0;
550 |
551 | if (* condition & ENET_SOCKET_WAIT_SEND)
552 | pollSocket.events |= POLLOUT;
553 |
554 | if (* condition & ENET_SOCKET_WAIT_RECEIVE)
555 | pollSocket.events |= POLLIN;
556 |
557 | pollCount = poll (& pollSocket, 1, timeout);
558 |
559 | if (pollCount < 0)
560 | {
561 | if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT)
562 | {
563 | * condition = ENET_SOCKET_WAIT_INTERRUPT;
564 |
565 | return 0;
566 | }
567 |
568 | return -1;
569 | }
570 |
571 | * condition = ENET_SOCKET_WAIT_NONE;
572 |
573 | if (pollCount == 0)
574 | return 0;
575 |
576 | if (pollSocket.revents & POLLOUT)
577 | * condition |= ENET_SOCKET_WAIT_SEND;
578 |
579 | if (pollSocket.revents & POLLIN)
580 | * condition |= ENET_SOCKET_WAIT_RECEIVE;
581 |
582 | return 0;
583 | #else
584 | fd_set readSet, writeSet;
585 | struct timeval timeVal;
586 | int selectCount;
587 |
588 | timeVal.tv_sec = timeout / 1000;
589 | timeVal.tv_usec = (timeout % 1000) * 1000;
590 |
591 | FD_ZERO (& readSet);
592 | FD_ZERO (& writeSet);
593 |
594 | if (* condition & ENET_SOCKET_WAIT_SEND)
595 | FD_SET (socket, & writeSet);
596 |
597 | if (* condition & ENET_SOCKET_WAIT_RECEIVE)
598 | FD_SET (socket, & readSet);
599 |
600 | selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
601 |
602 | if (selectCount < 0)
603 | {
604 | if (errno == EINTR && * condition & ENET_SOCKET_WAIT_INTERRUPT)
605 | {
606 | * condition = ENET_SOCKET_WAIT_INTERRUPT;
607 |
608 | return 0;
609 | }
610 |
611 | return -1;
612 | }
613 |
614 | * condition = ENET_SOCKET_WAIT_NONE;
615 |
616 | if (selectCount == 0)
617 | return 0;
618 |
619 | if (FD_ISSET (socket, & writeSet))
620 | * condition |= ENET_SOCKET_WAIT_SEND;
621 |
622 | if (FD_ISSET (socket, & readSet))
623 | * condition |= ENET_SOCKET_WAIT_RECEIVE;
624 |
625 | return 0;
626 | #endif
627 | }
628 |
629 | #endif
630 |
631 |
--------------------------------------------------------------------------------
/win32.c:
--------------------------------------------------------------------------------
1 | /**
2 | @file win32.c
3 | @brief ENet Win32 system specific functions
4 | */
5 | #ifdef _WIN32
6 |
7 | #define ENET_BUILDING_LIB 1
8 | #include "enet/enet.h"
9 | #include
10 | #include
11 | #include
12 |
13 | static enet_uint32 timeBase = 0;
14 |
15 | int
16 | enet_initialize (void)
17 | {
18 | WORD versionRequested = MAKEWORD (1, 1);
19 | WSADATA wsaData;
20 |
21 | if (WSAStartup (versionRequested, & wsaData))
22 | return -1;
23 |
24 | if (LOBYTE (wsaData.wVersion) != 1||
25 | HIBYTE (wsaData.wVersion) != 1)
26 | {
27 | WSACleanup ();
28 |
29 | return -1;
30 | }
31 |
32 | timeBeginPeriod (1);
33 |
34 | return 0;
35 | }
36 |
37 | void
38 | enet_deinitialize (void)
39 | {
40 | timeEndPeriod (1);
41 |
42 | WSACleanup ();
43 | }
44 |
45 | enet_uint32
46 | enet_host_random_seed (void)
47 | {
48 | return (enet_uint32) timeGetTime ();
49 | }
50 |
51 | enet_uint32
52 | enet_time_get (void)
53 | {
54 | return (enet_uint32) timeGetTime () - timeBase;
55 | }
56 |
57 | void
58 | enet_time_set (enet_uint32 newTimeBase)
59 | {
60 | timeBase = (enet_uint32) timeGetTime () - newTimeBase;
61 | }
62 |
63 | int
64 | enet_address_set_host_ip (ENetAddress * address, const char * name)
65 | {
66 | enet_uint8 vals [4] = { 0, 0, 0, 0 };
67 | int i;
68 |
69 | for (i = 0; i < 4; ++ i)
70 | {
71 | const char * next = name + 1;
72 | if (* name != '0')
73 | {
74 | long val = strtol (name, (char **) & next, 10);
75 | if (val < 0 || val > 255 || next == name || next - name > 3)
76 | return -1;
77 | vals [i] = (enet_uint8) val;
78 | }
79 |
80 | if (* next != (i < 3 ? '.' : '\0'))
81 | return -1;
82 | name = next + 1;
83 | }
84 |
85 | memcpy (& address -> host, vals, sizeof (enet_uint32));
86 | return 0;
87 | }
88 |
89 | int
90 | enet_address_set_host (ENetAddress * address, const char * name)
91 | {
92 | struct hostent * hostEntry;
93 |
94 | hostEntry = gethostbyname (name);
95 | if (hostEntry == NULL ||
96 | hostEntry -> h_addrtype != AF_INET)
97 | return enet_address_set_host_ip (address, name);
98 |
99 | address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
100 |
101 | return 0;
102 | }
103 |
104 | int
105 | enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
106 | {
107 | char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
108 | if (addr == NULL)
109 | return -1;
110 | else
111 | {
112 | size_t addrLen = strlen(addr);
113 | if (addrLen >= nameLength)
114 | return -1;
115 | memcpy (name, addr, addrLen + 1);
116 | }
117 | return 0;
118 | }
119 |
120 | int
121 | enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
122 | {
123 | struct in_addr in;
124 | struct hostent * hostEntry;
125 |
126 | in.s_addr = address -> host;
127 |
128 | hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
129 | if (hostEntry == NULL)
130 | return enet_address_get_host_ip (address, name, nameLength);
131 | else
132 | {
133 | size_t hostLen = strlen (hostEntry -> h_name);
134 | if (hostLen >= nameLength)
135 | return -1;
136 | memcpy (name, hostEntry -> h_name, hostLen + 1);
137 | }
138 |
139 | return 0;
140 | }
141 |
142 | int
143 | enet_socket_bind (ENetSocket socket, const ENetAddress * address)
144 | {
145 | struct sockaddr_in sin;
146 |
147 | memset (& sin, 0, sizeof (struct sockaddr_in));
148 |
149 | sin.sin_family = AF_INET;
150 |
151 | if (address != NULL)
152 | {
153 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
154 | sin.sin_addr.s_addr = address -> host;
155 | }
156 | else
157 | {
158 | sin.sin_port = 0;
159 | sin.sin_addr.s_addr = INADDR_ANY;
160 | }
161 |
162 | return bind (socket,
163 | (struct sockaddr *) & sin,
164 | sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
165 | }
166 |
167 | int
168 | enet_socket_get_address (ENetSocket socket, ENetAddress * address)
169 | {
170 | struct sockaddr_in sin;
171 | int sinLength = sizeof (struct sockaddr_in);
172 |
173 | if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
174 | return -1;
175 |
176 | address -> host = (enet_uint32) sin.sin_addr.s_addr;
177 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
178 |
179 | return 0;
180 | }
181 |
182 | int
183 | enet_socket_listen (ENetSocket socket, int backlog)
184 | {
185 | return listen (socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0;
186 | }
187 |
188 | ENetSocket
189 | enet_socket_create (ENetSocketType type)
190 | {
191 | return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
192 | }
193 |
194 | int
195 | enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
196 | {
197 | int result = SOCKET_ERROR;
198 | switch (option)
199 | {
200 | case ENET_SOCKOPT_NONBLOCK:
201 | {
202 | u_long nonBlocking = (u_long) value;
203 | result = ioctlsocket (socket, FIONBIO, & nonBlocking);
204 | break;
205 | }
206 |
207 | case ENET_SOCKOPT_BROADCAST:
208 | result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int));
209 | break;
210 |
211 | case ENET_SOCKOPT_REUSEADDR:
212 | result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int));
213 | break;
214 |
215 | case ENET_SOCKOPT_RCVBUF:
216 | result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int));
217 | break;
218 |
219 | case ENET_SOCKOPT_SNDBUF:
220 | result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int));
221 | break;
222 |
223 | case ENET_SOCKOPT_RCVTIMEO:
224 | result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & value, sizeof (int));
225 | break;
226 |
227 | case ENET_SOCKOPT_SNDTIMEO:
228 | result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & value, sizeof (int));
229 | break;
230 |
231 | case ENET_SOCKOPT_NODELAY:
232 | result = setsockopt (socket, IPPROTO_TCP, TCP_NODELAY, (char *) & value, sizeof (int));
233 | break;
234 |
235 | case ENET_SOCKOPT_TTL:
236 | result = setsockopt (socket, IPPROTO_IP, IP_TTL, (char *) & value, sizeof (int));
237 | break;
238 |
239 | default:
240 | break;
241 | }
242 | return result == SOCKET_ERROR ? -1 : 0;
243 | }
244 |
245 | int
246 | enet_socket_get_option (ENetSocket socket, ENetSocketOption option, int * value)
247 | {
248 | int result = SOCKET_ERROR, len;
249 | switch (option)
250 | {
251 | case ENET_SOCKOPT_ERROR:
252 | len = sizeof(int);
253 | result = getsockopt (socket, SOL_SOCKET, SO_ERROR, (char *) value, & len);
254 | break;
255 |
256 | case ENET_SOCKOPT_TTL:
257 | len = sizeof(int);
258 | result = getsockopt (socket, IPPROTO_IP, IP_TTL, (char *) value, & len);
259 | break;
260 |
261 | default:
262 | break;
263 | }
264 | return result == SOCKET_ERROR ? -1 : 0;
265 | }
266 |
267 | int
268 | enet_socket_connect (ENetSocket socket, const ENetAddress * address)
269 | {
270 | struct sockaddr_in sin;
271 | int result;
272 |
273 | memset (& sin, 0, sizeof (struct sockaddr_in));
274 |
275 | sin.sin_family = AF_INET;
276 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
277 | sin.sin_addr.s_addr = address -> host;
278 |
279 | result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
280 | if (result == SOCKET_ERROR && WSAGetLastError () != WSAEWOULDBLOCK)
281 | return -1;
282 |
283 | return 0;
284 | }
285 |
286 | ENetSocket
287 | enet_socket_accept (ENetSocket socket, ENetAddress * address)
288 | {
289 | SOCKET result;
290 | struct sockaddr_in sin;
291 | int sinLength = sizeof (struct sockaddr_in);
292 |
293 | result = accept (socket,
294 | address != NULL ? (struct sockaddr *) & sin : NULL,
295 | address != NULL ? & sinLength : NULL);
296 |
297 | if (result == INVALID_SOCKET)
298 | return ENET_SOCKET_NULL;
299 |
300 | if (address != NULL)
301 | {
302 | address -> host = (enet_uint32) sin.sin_addr.s_addr;
303 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
304 | }
305 |
306 | return result;
307 | }
308 |
309 | int
310 | enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how)
311 | {
312 | return shutdown (socket, (int) how) == SOCKET_ERROR ? -1 : 0;
313 | }
314 |
315 | void
316 | enet_socket_destroy (ENetSocket socket)
317 | {
318 | if (socket != INVALID_SOCKET)
319 | closesocket (socket);
320 | }
321 |
322 | int
323 | enet_socket_send (ENetSocket socket,
324 | const ENetAddress * address,
325 | const ENetBuffer * buffers,
326 | size_t bufferCount)
327 | {
328 | struct sockaddr_in sin;
329 | DWORD sentLength = 0;
330 |
331 | if (address != NULL)
332 | {
333 | memset (& sin, 0, sizeof (struct sockaddr_in));
334 |
335 | sin.sin_family = AF_INET;
336 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
337 | sin.sin_addr.s_addr = address -> host;
338 | }
339 |
340 | if (WSASendTo (socket,
341 | (LPWSABUF) buffers,
342 | (DWORD) bufferCount,
343 | & sentLength,
344 | 0,
345 | address != NULL ? (struct sockaddr *) & sin : NULL,
346 | address != NULL ? sizeof (struct sockaddr_in) : 0,
347 | NULL,
348 | NULL) == SOCKET_ERROR)
349 | {
350 | if (WSAGetLastError () == WSAEWOULDBLOCK)
351 | return 0;
352 |
353 | return -1;
354 | }
355 |
356 | return (int) sentLength;
357 | }
358 |
359 | int
360 | enet_socket_receive (ENetSocket socket,
361 | ENetAddress * address,
362 | ENetBuffer * buffers,
363 | size_t bufferCount)
364 | {
365 | INT sinLength = sizeof (struct sockaddr_in);
366 | DWORD flags = 0,
367 | recvLength = 0;
368 | struct sockaddr_in sin;
369 |
370 | if (WSARecvFrom (socket,
371 | (LPWSABUF) buffers,
372 | (DWORD) bufferCount,
373 | & recvLength,
374 | & flags,
375 | address != NULL ? (struct sockaddr *) & sin : NULL,
376 | address != NULL ? & sinLength : NULL,
377 | NULL,
378 | NULL) == SOCKET_ERROR)
379 | {
380 | switch (WSAGetLastError ())
381 | {
382 | case WSAEWOULDBLOCK:
383 | case WSAECONNRESET:
384 | return 0;
385 | case WSAEINTR:
386 | case WSAEMSGSIZE:
387 | return -2;
388 | default:
389 | return -1;
390 | }
391 | }
392 |
393 | if (flags & MSG_PARTIAL)
394 | return -2;
395 |
396 | if (address != NULL)
397 | {
398 | address -> host = (enet_uint32) sin.sin_addr.s_addr;
399 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
400 | }
401 |
402 | return (int) recvLength;
403 | }
404 |
405 | int
406 | enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout)
407 | {
408 | struct timeval timeVal;
409 |
410 | timeVal.tv_sec = timeout / 1000;
411 | timeVal.tv_usec = (timeout % 1000) * 1000;
412 |
413 | return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal);
414 | }
415 |
416 | int
417 | enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout)
418 | {
419 | fd_set readSet, writeSet;
420 | struct timeval timeVal;
421 | int selectCount;
422 |
423 | timeVal.tv_sec = timeout / 1000;
424 | timeVal.tv_usec = (timeout % 1000) * 1000;
425 |
426 | FD_ZERO (& readSet);
427 | FD_ZERO (& writeSet);
428 |
429 | if (* condition & ENET_SOCKET_WAIT_SEND)
430 | FD_SET (socket, & writeSet);
431 |
432 | if (* condition & ENET_SOCKET_WAIT_RECEIVE)
433 | FD_SET (socket, & readSet);
434 |
435 | selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
436 |
437 | if (selectCount < 0)
438 | return -1;
439 |
440 | * condition = ENET_SOCKET_WAIT_NONE;
441 |
442 | if (selectCount == 0)
443 | return 0;
444 |
445 | if (FD_ISSET (socket, & writeSet))
446 | * condition |= ENET_SOCKET_WAIT_SEND;
447 |
448 | if (FD_ISSET (socket, & readSet))
449 | * condition |= ENET_SOCKET_WAIT_RECEIVE;
450 |
451 | return 0;
452 | }
453 |
454 | #endif
455 |
456 |
--------------------------------------------------------------------------------