├── .editorconfig ├── .gitattributes ├── .github ├── codeql │ └── config.yml └── workflows │ ├── codeql-analysis.yml │ ├── notify-release.yml │ └── tests.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── enet.h ├── misc ├── ChangeLog ├── docs │ ├── FAQ.dox │ ├── design.dox │ ├── install.dox │ ├── license.dox │ ├── mainpage.dox │ └── tutorial.dox └── packager.js ├── package.json └── test ├── build.c ├── cli-server.c ├── library.c └── resize.c /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Set default charset 12 | charset = utf-8 13 | 14 | # 4 space indentation 15 | indent_style = space 16 | indent_size = 4 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=C 2 | code/vendor/* linguist-vendored 3 | -------------------------------------------------------------------------------- /.github/codeql/config.yml: -------------------------------------------------------------------------------- 1 | name: "ENet CodeQL Config" 2 | 3 | queries: 4 | - uses: security-and-quality 5 | - uses: security-extended 6 | 7 | # paths-ignore: 8 | # - code/vendor 9 | 10 | # Documentation for configuring CodeQL is located here: 11 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning 12 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: '20 22 * * 0' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v2 19 | 20 | - name: Initialize CodeQL 21 | uses: github/codeql-action/init@v2 22 | with: 23 | languages: 'cpp' 24 | config-file: ./.github/codeql/config.yml 25 | - run: cmake -B build && cmake --build build 26 | 27 | - name: Perform CodeQL Analysis 28 | uses: github/codeql-action/analyze@v2 29 | -------------------------------------------------------------------------------- /.github/workflows/notify-release.yml: -------------------------------------------------------------------------------- 1 | name: notify-release 2 | on: 3 | release: 4 | types: 5 | - published 6 | workflow_dispatch: 7 | 8 | jobs: 9 | notify: 10 | name: Show a changelog 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: sarisia/actions-status-discord@v1 14 | if: always() 15 | env: 16 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} 17 | with: 18 | description: "**${{ github.repository }}: [${{ github.event.release.name }}](${{ github.event.release.html_url }})**\n\n**Changelog:**\n${{ github.event.release.body }}" 19 | nodetail: true 20 | nofail: true 21 | color: "0x9999ff" 22 | 23 | build-win: 24 | name: Test Windows 25 | runs-on: windows-latest 26 | steps: 27 | - uses: actions/checkout@v1 28 | - name: Run cmake generator 29 | run: cmake -B build -DENET_TEST=1 -DENET_SHARED=1 30 | - name: Run Windows build 31 | run: cmake --build build --config Release 32 | - name: Run unit tests 33 | run: cd build ; .\Release\enet_test.exe 34 | - name: Release 35 | uses: softprops/action-gh-release@v1 36 | if: startsWith(github.ref, 'refs/tags/') 37 | with: 38 | files: build/Release/enet_shared.dll 39 | 40 | build-lin: 41 | name: Test Linux 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@v1 45 | - name: Run cmake generator 46 | run: cmake -B build -DENET_TEST=1 -DENET_SHARED=1 -DCMAKE_BUILD_TYPE=Release 47 | - name: Run build on Linux 48 | run: cmake --build build 49 | - name: Test build on Linux 50 | run: build/enet_test 51 | - name: Release 52 | uses: softprops/action-gh-release@v1 53 | if: startsWith(github.ref, 'refs/tags/') 54 | with: 55 | files: build/libenet_shared.so 56 | 57 | build-mac: 58 | name: Test macOS 59 | runs-on: macOS-latest 60 | steps: 61 | - uses: actions/checkout@v1 62 | - name: Run cmake generator 63 | run: cmake -B build -DENET_TEST=1 -DENET_SHARED=1 -DCMAKE_BUILD_TYPE=Release 64 | - name: Run build on macOS 65 | run: cmake --build build 66 | - name: Test build on macOS 67 | run: build/enet_test 68 | - name: Release 69 | uses: softprops/action-gh-release@v1 70 | if: startsWith(github.ref, 'refs/tags/') 71 | with: 72 | files: build/libenet_shared.dylib 73 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: 3 | push: 4 | tags-ignore: 5 | - 'v[0-9]+.[0-9]+.[0-9]+' 6 | branches: 7 | - master 8 | - review/** 9 | paths: 10 | - 'include/**' 11 | - 'CMakeLists.txt' 12 | pull_request: 13 | branches: 14 | - master 15 | paths: 16 | - 'include/**' 17 | - 'CMakeLists.txt' 18 | 19 | jobs: 20 | prep: 21 | name: Notify about testing 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: inlife/actiord-action@v1 25 | with: 26 | url: ${{ secrets.ACTIORD_URL }} 27 | discord_token: ${{ secrets.DISCORD_TOKEN }} 28 | discord_channel: ${{ secrets.DISCORD_CHANNEL }} 29 | icon: https://avatars1.githubusercontent.com/u/26773913?s=200&v=4 30 | state: started 31 | 32 | build-win: 33 | name: Test Windows 34 | runs-on: windows-latest 35 | needs: [prep] 36 | steps: 37 | - uses: actions/checkout@v1 38 | - name: Run cmake generator 39 | run: cmake -B build -DENET_TEST=1 40 | - name: Run Windows build 41 | run: cmake --build build 42 | - name: Run unit tests 43 | run: cd build ; .\Debug\enet_test.exe 44 | - name: Run unit tests with extra peers 45 | run: cd build ; .\Debug\enet_test_extra_peers.exe 46 | 47 | build-lin: 48 | name: Test Linux 49 | runs-on: ubuntu-latest 50 | needs: [prep] 51 | steps: 52 | - uses: actions/checkout@v1 53 | - name: Run cmake generator 54 | run: cmake -B build -DENET_TEST=1 55 | - name: Run build on Linux 56 | run: cmake --build build 57 | - name: Test build on Linux 58 | run: build/enet_test 59 | - name: Test build on Linux with extra peers 60 | run: build/enet_test_extra_peers 61 | 62 | build-mac: 63 | name: Test macOS 64 | runs-on: macOS-latest 65 | needs: [prep] 66 | steps: 67 | - uses: actions/checkout@v1 68 | - name: Run cmake generator 69 | run: cmake -B build -DENET_TEST=1 70 | - name: Run build on macOS 71 | run: cmake --build build 72 | - name: Test build on macOS 73 | run: build/enet_test 74 | - name: Test build on macOS with extra peers 75 | run: build/enet_test_extra_peers 76 | 77 | done: 78 | name: Notify about status 79 | runs-on: ubuntu-latest 80 | needs: [build-mac, build-lin, build-win] 81 | if: "always()" 82 | steps: 83 | - uses: inlife/actiord-action@v1 84 | if: ${{ contains(needs.build-mac.result, 'success') && contains(needs.build-lin.result, 'success') && contains(needs.build-win.result, 'success') }} 85 | with: 86 | url: ${{ secrets.ACTIORD_URL }} 87 | icon: https://avatars1.githubusercontent.com/u/26773913?s=200&v=4 88 | state: succeeded 89 | 90 | - uses: inlife/actiord-action@v1 91 | if: ${{ !(contains(needs.build-mac.result, 'success') && contains(needs.build-lin.result, 'success') && contains(needs.build-win.result, 'success')) }} 92 | with: 93 | url: ${{ secrets.ACTIORD_URL }} 94 | discord_token: ${{ secrets.DISCORD_TOKEN }} 95 | discord_channel: ${{ secrets.DISCORD_CHANNEL }} 96 | icon: https://avatars1.githubusercontent.com/u/26773913?s=200&v=4 97 | state: failed 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Folders 2 | build/* 3 | misc/deploy/ 4 | node_modules/ 5 | pkg/ 6 | 7 | # vs shit 8 | *.dir/ 9 | x64/ 10 | 11 | # Other 12 | .DS_store 13 | .idea 14 | 15 | # local build scripts 16 | build.sh 17 | build.bat 18 | package-lock.json 19 | 20 | # gtags 21 | GPATH 22 | GRTAGS 23 | GTAGS 24 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(enet C) 3 | 4 | # ----------------------------- 5 | # 1) Build options 6 | # ----------------------------- 7 | option(ENET_STATIC "Build enet as a static library" ON) 8 | option(ENET_SHARED "Build enet as a shared library" OFF) 9 | option(ENET_TEST "Build enet tests" ON) 10 | option(ENET_USE_MORE_PEERS "Build enet with up to 65k peers support" OFF) 11 | 12 | if (ENET_USE_MORE_PEERS) 13 | add_definitions(-DENET_USE_MORE_PEERS) 14 | endif() 15 | 16 | # ----------------------------- 17 | # 2) Static library 18 | # ----------------------------- 19 | if(ENET_STATIC) 20 | add_library(enet_static STATIC test/library.c) 21 | 22 | if(WIN32) 23 | target_link_libraries(enet_static PUBLIC winmm ws2_32) 24 | if(MSVC) 25 | target_compile_options(enet_static PRIVATE /W3) 26 | endif() 27 | else() 28 | target_compile_options(enet_static PRIVATE -Wno-error) 29 | endif() 30 | 31 | target_include_directories(enet_static PUBLIC 32 | $ 33 | $ 34 | ) 35 | 36 | add_library(enet::enet_static ALIAS enet_static) 37 | endif() 38 | 39 | # ----------------------------- 40 | # 3) Shared library 41 | # ----------------------------- 42 | if(ENET_SHARED) 43 | add_library(enet_shared SHARED test/library.c) 44 | target_compile_definitions(enet_shared PUBLIC -DENET_DLL) 45 | 46 | if(WIN32) 47 | target_link_libraries(enet_shared PUBLIC winmm ws2_32) 48 | if(MSVC) 49 | target_compile_options(enet_shared PRIVATE /W3) 50 | endif() 51 | else() 52 | target_compile_options(enet_shared PRIVATE -Wno-error) 53 | endif() 54 | 55 | target_include_directories(enet_shared PUBLIC 56 | $ 57 | $ 58 | ) 59 | 60 | add_library(enet::enet_shared ALIAS enet_shared) 61 | endif() 62 | 63 | # ----------------------------- 64 | # 4) Tests (optional) 65 | # ----------------------------- 66 | if(ENET_TEST) 67 | add_library(enet_test_interface INTERFACE) 68 | 69 | target_include_directories(enet_test_interface INTERFACE 70 | ${CMAKE_CURRENT_SOURCE_DIR}/include 71 | ) 72 | 73 | if(TARGET enet_static) 74 | target_link_libraries(enet_test_interface INTERFACE enet_static) 75 | elseif(TARGET enet_shared) 76 | target_link_libraries(enet_test_interface INTERFACE enet_shared) 77 | endif() 78 | 79 | if(WIN32) 80 | target_link_libraries(enet_test_interface INTERFACE winmm ws2_32) 81 | endif() 82 | 83 | # Default test 84 | add_executable(enet_test test/build.c) 85 | target_link_libraries(enet_test PRIVATE enet_test_interface) 86 | 87 | # Test with more peers 88 | add_executable(enet_test_extra_peers test/build.c) 89 | target_link_libraries(enet_test_extra_peers PRIVATE enet_test_interface) 90 | target_compile_definitions(enet_test_extra_peers PRIVATE ENET_USE_MORE_PEERS) 91 | 92 | endif() 93 | 94 | # ----------------------------- 95 | # 5) Installation 96 | # ----------------------------- 97 | set(_enet_targets_to_install "") 98 | 99 | if(TARGET enet_static) 100 | list(APPEND _enet_targets_to_install enet_static) 101 | set_target_properties(enet_static PROPERTIES OUTPUT_NAME "enet") 102 | endif() 103 | 104 | if(TARGET enet_shared) 105 | list(APPEND _enet_targets_to_install enet_shared) 106 | set_target_properties(enet_shared PROPERTIES OUTPUT_NAME "enet") 107 | endif() 108 | 109 | if(_enet_targets_to_install) 110 | install( 111 | TARGETS ${_enet_targets_to_install} 112 | EXPORT enetTargets 113 | RUNTIME DESTINATION bin 114 | LIBRARY DESTINATION lib 115 | ARCHIVE DESTINATION lib 116 | INCLUDES DESTINATION include 117 | ) 118 | 119 | install( 120 | DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ 121 | DESTINATION include 122 | FILES_MATCHING 123 | PATTERN "*.h" 124 | ) 125 | 126 | install( 127 | EXPORT enetTargets 128 | FILE enetConfig.cmake 129 | NAMESPACE enet:: 130 | DESTINATION lib/cmake/enet 131 | ) 132 | endif() 133 | 134 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2002-2016 Lee Salzman 4 | Copyright (c) 2017-2022 Vladyslav Hrytsenko, Dominik Madarász 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | zpl/enet 3 |
4 | 5 |
6 | 7 |
8 | build status 9 | version 10 | discord 11 | license 12 |
13 | 14 |
15 | 16 |
17 | ENet - Simple, lightweight and reliable UDP networking library written on pure C 18 |
19 | 20 |
21 | 22 | Brought to you by 23 | @lsalzman, 24 | @inlife, 25 | @zpl-zak, 26 | @nxrighthere 27 | and other contributors 28 | 29 |
30 | 31 | ## Disclaimer 32 | 33 | This is a fork of the original library [lsalzman/enet](https://github.com/lsalzman/enet). While original repo offers a stable, time-tested wonderful library, 34 | we are trying to change some things, things, which can't be reflected on the main repo, like: 35 | 36 | * integrated ipv6 support 37 | * added monotonic time 38 | * applied project-wide code style change 39 | * cleaned up project 40 | * single-header style code 41 | * removed some of older/outdated methods 42 | * and many other various changes 43 | 44 | ## Description 45 | 46 | ENet's purpose is to provide a relatively thin, simple and robust network communication 47 | layer on top of UDP (User Datagram Protocol). The primary feature it provides is optional 48 | reliable, in-order delivery of packets, and fragmentation. 49 | 50 | ENet omits certain higher level networking features such as authentication, lobbying, 51 | server discovery, encryption, or other similar tasks that are particularly application 52 | specific so that the library remains flexible, portable, and easily embeddable. 53 | 54 | ## Installation 55 | 56 | Download file [releases/latest/enet.h](https://github.com/zpl-c/enet/releases/latest/download/enet.h) and just add to your project. 57 | 58 | ## Usage (Shared library) 59 | 60 | Build the shared library: 61 | 62 | ```sh 63 | $ cmake -B build -DENET_SHARED=1 -DCMAKE_BUILD_TYPE=Release 64 | $ cmake --build build 65 | ``` 66 | 67 | Use it: 68 | 69 | ```c 70 | #define ENET_DLL 71 | #include 72 | #include 73 | 74 | int main() { 75 | if (enet_initialize () != 0) { 76 | printf("An error occurred while initializing ENet.\n"); 77 | return 1; 78 | } 79 | 80 | enet_deinitialize(); 81 | return 0; 82 | } 83 | ``` 84 | 85 | ## Usage (Static library) 86 | 87 | Build the static library: 88 | 89 | ```sh 90 | $ cmake -B build -DENET_STATIC=1 -DCMAKE_BUILD_TYPE=Release 91 | $ cmake --build build 92 | ``` 93 | 94 | Use it: 95 | 96 | ```c 97 | #include 98 | #include 99 | 100 | int main() { 101 | if (enet_initialize () != 0) { 102 | printf("An error occurred while initializing ENet.\n"); 103 | return 1; 104 | } 105 | 106 | enet_deinitialize(); 107 | return 0; 108 | } 109 | ``` 110 | 111 | ## Usage (Single Header, Preferred) 112 | 113 | In this case, library will be embedded to the project itself. 114 | 115 | Make sure you add a define for `ENET_IMPLEMENTATION` exactly in one source file before including the `enet.h`. 116 | 117 | Here is a simple server and client demo, it will wait 1 second for events, and then exit if none were found: 118 | 119 | Server: 120 | 121 | ```c 122 | #define ENET_IMPLEMENTATION 123 | #include 124 | #include 125 | 126 | int main() { 127 | if (enet_initialize () != 0) { 128 | printf("An error occurred while initializing ENet.\n"); 129 | return 1; 130 | } 131 | 132 | ENetAddress address = {0}; 133 | 134 | address.host = ENET_HOST_ANY; /* Bind the server to the default localhost. */ 135 | address.port = 7777; /* Bind the server to port 7777. */ 136 | 137 | #define MAX_CLIENTS 32 138 | 139 | /* create a server */ 140 | ENetHost * server = enet_host_create(&address, MAX_CLIENTS, 2, 0, 0); 141 | 142 | if (server == NULL) { 143 | printf("An error occurred while trying to create an ENet server host.\n"); 144 | return 1; 145 | } 146 | 147 | printf("Started a server...\n"); 148 | 149 | ENetEvent event; 150 | 151 | /* Wait up to 1000 milliseconds for an event. (WARNING: blocking) */ 152 | while (enet_host_service(server, &event, 1000) > 0) { 153 | switch (event.type) { 154 | case ENET_EVENT_TYPE_CONNECT: 155 | printf("A new client connected from %x:%u.\n", event.peer->address.host, event.peer->address.port); 156 | /* Store any relevant client information here. */ 157 | event.peer->data = "Client information"; 158 | break; 159 | 160 | case ENET_EVENT_TYPE_RECEIVE: 161 | printf("A packet of length %lu containing %s was received from %s on channel %u.\n", 162 | event.packet->dataLength, 163 | event.packet->data, 164 | event.peer->data, 165 | event.channelID); 166 | /* Clean up the packet now that we're done using it. */ 167 | enet_packet_destroy (event.packet); 168 | break; 169 | 170 | case ENET_EVENT_TYPE_DISCONNECT: 171 | printf("%s disconnected.\n", event.peer->data); 172 | /* Reset the peer's client information. */ 173 | event.peer->data = NULL; 174 | break; 175 | 176 | case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: 177 | printf("%s disconnected due to timeout.\n", event.peer->data); 178 | /* Reset the peer's client information. */ 179 | event.peer->data = NULL; 180 | break; 181 | 182 | case ENET_EVENT_TYPE_NONE: 183 | break; 184 | } 185 | } 186 | 187 | enet_host_destroy(server); 188 | enet_deinitialize(); 189 | return 0; 190 | } 191 | 192 | ``` 193 | 194 | Client: 195 | 196 | ```c 197 | #include 198 | #define ENET_IMPLEMENTATION 199 | #include "enet.h" 200 | 201 | int main() { 202 | if (enet_initialize() != 0) { 203 | fprintf(stderr, "An error occurred while initializing ENet.\n"); 204 | return EXIT_FAILURE; 205 | } 206 | 207 | ENetHost* client = { 0 }; 208 | client = enet_host_create(NULL /* create a client host */, 209 | 1 /* only allow 1 outgoing connection */, 210 | 2 /* allow up 2 channels to be used, 0 and 1 */, 211 | 0 /* assume any amount of incoming bandwidth */, 212 | 0 /* assume any amount of outgoing bandwidth */); 213 | if (client == NULL) { 214 | fprintf(stderr, 215 | "An error occurred while trying to create an ENet client host.\n"); 216 | exit(EXIT_FAILURE); 217 | } 218 | 219 | ENetAddress address = { 0 }; 220 | ENetEvent event = { 0 }; 221 | ENetPeer* peer = { 0 }; 222 | /* Connect to some.server.net:1234. */ 223 | enet_address_set_host(&address, "127.0.0.1"); 224 | address.port = 7777; 225 | /* Initiate the connection, allocating the two channels 0 and 1. */ 226 | peer = enet_host_connect(client, &address, 2, 0); 227 | if (peer == NULL) { 228 | fprintf(stderr, 229 | "No available peers for initiating an ENet connection.\n"); 230 | exit(EXIT_FAILURE); 231 | } 232 | /* Wait up to 5 seconds for the connection attempt to succeed. */ 233 | if (enet_host_service(client, &event, 5000) > 0 && 234 | event.type == ENET_EVENT_TYPE_CONNECT) { 235 | puts("Connection to some.server.net:1234 succeeded."); 236 | } else { 237 | /* Either the 5 seconds are up or a disconnect event was */ 238 | /* received. Reset the peer in the event the 5 seconds */ 239 | /* had run out without any significant event. */ 240 | enet_peer_reset(peer); 241 | puts("Connection to some.server.net:1234 failed."); 242 | } 243 | 244 | // Receive some events 245 | enet_host_service(client, &event, 5000); 246 | 247 | // Disconnect 248 | enet_peer_disconnect(peer, 0); 249 | 250 | uint8_t disconnected = false; 251 | /* Allow up to 3 seconds for the disconnect to succeed 252 | * and drop any packets received packets. 253 | */ 254 | while (enet_host_service(client, &event, 3000) > 0) { 255 | switch (event.type) { 256 | case ENET_EVENT_TYPE_RECEIVE: 257 | enet_packet_destroy(event.packet); 258 | break; 259 | case ENET_EVENT_TYPE_DISCONNECT: 260 | puts("Disconnection succeeded."); 261 | disconnected = true; 262 | break; 263 | } 264 | } 265 | 266 | // Drop connection, since disconnection didn't successed 267 | if (!disconnected) { 268 | enet_peer_reset(peer); 269 | } 270 | 271 | enet_host_destroy(client); 272 | enet_deinitialize(); 273 | } 274 | ``` 275 | 276 | ## Tutorials 277 | 278 | More information, examples and tutorials can be found at the official site: http://enet.bespin.org/ 279 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /misc/ChangeLog: -------------------------------------------------------------------------------- 1 | ENet 2.0.0 (April 22, 2018): 2 | * changed library format to single header 3 | * applied project-wide code style change 4 | * integrated ipv6 changes from @proller 5 | * changed packet creation to have one less malloc and free per packet. @boardwalk 6 | * removed enet_packet_resize 7 | * added timeout disconnect notification event @airtame 8 | * added total packets sent and lost to enet_peer @airtame 9 | * force a connect packet not to have extra bytes @pisto 10 | * enforce mtu while receiving packets, and don't give up receiving if one too big comes through @pisto 11 | * add metrics for total data send and received @airtame 12 | * replaced exp backoff time for rel packet timeout with linear @airtame 13 | * added monotonic time @airtame 14 | * removed enet_time_set 15 | * removed a lot of wide platform support code, might bring a lot of issues on older/non-standart platforms 16 | * removed range coder compression code 17 | 18 | ENet 1.3.13 (April 30, 2015): 19 | 20 | * miscellaneous bug fixes 21 | * added premake and cmake support 22 | * miscellaneous documentation cleanups 23 | 24 | ENet 1.3.12 (April 24, 2014): 25 | 26 | * added maximumPacketSize and maximumWaitingData fields to ENetHost to limit the amount of 27 | data waiting to be delivered on a peer (beware that the default maximumPacketSize is 28 | 32MB and should be set higher if desired as should maximumWaitingData) 29 | 30 | ENet 1.3.11 (December 26, 2013): 31 | 32 | * allow an ENetHost to connect to itself 33 | * fixed possible bug with disconnect notifications during connect attempts 34 | * fixed some preprocessor definition bugs 35 | 36 | ENet 1.3.10 (October 23, 2013); 37 | 38 | * doubled maximum reliable window size 39 | * fixed RCVTIMEO/SNDTIMEO socket options and also added NODELAY 40 | 41 | ENet 1.3.9 (August 19, 2013): 42 | 43 | * added duplicatePeers option to ENetHost which can limit the number of peers from duplicate IPs 44 | * added enet_socket_get_option() and ENET_SOCKOPT_ERROR 45 | * added enet_host_random_seed() platform stub 46 | 47 | ENet 1.3.8 (June 2, 2013): 48 | 49 | * added enet_linked_version() for checking the linked version 50 | * added enet_socket_get_address() for querying the local address of a socket 51 | * silenced some debugging prints unless ENET_DEBUG is defined during compilation 52 | * handle EINTR in enet_socket_wait() so that enet_host_service() doesn't propagate errors from signals 53 | * optimized enet_host_bandwidth_throttle() to be less expensive for large numbers of peers 54 | 55 | ENet 1.3.7 (March 6, 2013): 56 | 57 | * added ENET_PACKET_FLAG_SENT to indicate that a packet is being freed because it has been sent 58 | * added userData field to ENetPacket 59 | * changed how random seed is generated on Windows to avoid import warnings 60 | * fixed case where disconnects could be generated with no preceding connect event 61 | 62 | ENet 1.3.6 (December 11, 2012): 63 | 64 | * added support for intercept callback in ENetHost that can be used to process raw packets before ENet 65 | * added enet_socket_shutdown() for issuing shutdown on a socket 66 | * fixed enet_socket_connect() to not error on non-blocking connects 67 | * fixed bug in MTU negotiation during connections 68 | 69 | ENet 1.3.5 (July 31, 2012): 70 | 71 | * fixed bug in unreliable packet fragment queuing 72 | 73 | ENet 1.3.4 (May 29, 2012): 74 | 75 | * added enet_peer_ping_interval() for configuring per-peer ping intervals 76 | * added enet_peer_timeout() for configuring per-peer timeouts 77 | * added protocol packet size limits 78 | 79 | ENet 1.3.3 (June 28, 2011): 80 | 81 | * fixed bug with simultaneous disconnects not dispatching events 82 | 83 | ENet 1.3.2 (May 31, 2011): 84 | 85 | * added support for unreliable packet fragmenting via the packet flag 86 | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT 87 | * fixed regression in unreliable packet queuing 88 | * added check against received port to limit some forms of IP-spoofing 89 | 90 | ENet 1.3.1 (February 10, 2011): 91 | 92 | * fixed bug in tracking of reliable data in transit 93 | * reliable data window size now scales with the throttle 94 | * fixed bug in fragment length calculation when checksums are used 95 | 96 | ENet 1.3.0 (June 5, 2010): 97 | 98 | * enet_host_create() now requires the channel limit to be specified as 99 | a parameter 100 | * enet_host_connect() now accepts a data parameter which is supplied 101 | to the receiving receiving host in the event data field for a connect event 102 | * added an adaptive order-2 PPM range coder as a built-in compressor option 103 | which can be set with enet_host_compress_with_range_coder() 104 | * added support for packet compression configurable with a callback 105 | * improved session number handling to not rely on the packet checksum 106 | field, saving 4 bytes per packet unless the checksum option is used 107 | * removed the dependence on the rand callback for session number handling 108 | 109 | Caveats: This version is not protocol compatible with the 1.2 series or 110 | earlier. The enet_host_connect and enet_host_create API functions require 111 | supplying additional parameters. 112 | 113 | ENet 1.2.5 (June 28, 2011): 114 | 115 | * fixed bug with simultaneous disconnects not dispatching events 116 | 117 | ENet 1.2.4 (May 31, 2011): 118 | 119 | * fixed regression in unreliable packet queuing 120 | * added check against received port to limit some forms of IP-spoofing 121 | 122 | ENet 1.2.3 (February 10, 2011): 123 | 124 | * fixed bug in tracking reliable data in transit 125 | 126 | ENet 1.2.2 (June 5, 2010): 127 | 128 | * checksum functionality is now enabled by setting a checksum callback 129 | inside ENetHost instead of being a configure script option 130 | * added totalSentData, totalSentPackets, totalReceivedData, and 131 | totalReceivedPackets counters inside ENetHost for getting usage 132 | statistics 133 | * added enet_host_channel_limit() for limiting the maximum number of 134 | channels allowed by connected peers 135 | * now uses dispatch queues for event dispatch rather than potentially 136 | unscalable array walking 137 | * added no_memory callback that is called when a malloc attempt fails, 138 | such that if no_memory returns rather than aborts (the default behavior), 139 | then the error is propagated to the return value of the API calls 140 | * now uses packed attribute for protocol structures on platforms with 141 | strange alignment rules 142 | * improved autoconf build system contributed by Nathan Brink allowing 143 | for easier building as a shared library 144 | 145 | Caveats: If you were using the compile-time option that enabled checksums, 146 | make sure to set the checksum callback inside ENetHost to enet_crc32 to 147 | regain the old behavior. The ENetCallbacks structure has added new fields, 148 | so make sure to clear the structure to zero before use if 149 | using enet_initialize_with_callbacks(). 150 | 151 | ENet 1.2.1 (November 12, 2009): 152 | 153 | * fixed bug that could cause disconnect events to be dropped 154 | * added thin wrapper around select() for portable usage 155 | * added ENET_SOCKOPT_REUSEADDR socket option 156 | * factored enet_socket_bind()/enet_socket_listen() out of enet_socket_create() 157 | * added contributed Code::Blocks build file 158 | 159 | ENet 1.2 (February 12, 2008): 160 | 161 | * fixed bug in VERIFY_CONNECT acknowledgement that could cause connect 162 | attempts to occasionally timeout 163 | * fixed acknowledgements to check both the outgoing and sent queues 164 | when removing acknowledged packets 165 | * fixed accidental bit rot in the MSVC project file 166 | * revised sequence number overflow handling to address some possible 167 | disconnect bugs 168 | * added enet_host_check_events() for getting only local queued events 169 | * factored out socket option setting into enet_socket_set_option() so 170 | that socket options are now set separately from enet_socket_create() 171 | 172 | Caveats: While this release is superficially protocol compatible with 1.1, 173 | differences in the sequence number overflow handling can potentially cause 174 | random disconnects. 175 | 176 | ENet 1.1 (June 6, 2007): 177 | 178 | * optional CRC32 just in case someone needs a stronger checksum than UDP 179 | provides (--enable-crc32 configure option) 180 | * the size of packet headers are half the size they used to be (so less 181 | overhead when sending small packets) 182 | * enet_peer_disconnect_later() that waits till all queued outgoing 183 | packets get sent before issuing an actual disconnect 184 | * freeCallback field in individual packets for notification of when a 185 | packet is about to be freed 186 | * ENET_PACKET_FLAG_NO_ALLOCATE for supplying pre-allocated data to a 187 | packet (can be used in concert with freeCallback to support some custom 188 | allocation schemes that the normal memory allocation callbacks would 189 | normally not allow) 190 | * enet_address_get_host_ip() for printing address numbers 191 | * promoted the enet_socket_*() functions to be part of the API now 192 | * a few stability/crash fixes 193 | 194 | 195 | -------------------------------------------------------------------------------- /misc/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 | -------------------------------------------------------------------------------- /misc/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 | -------------------------------------------------------------------------------- /misc/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 | -------------------------------------------------------------------------------- /misc/docs/license.dox: -------------------------------------------------------------------------------- 1 | /** 2 | @page License License 3 | 4 | Copyright (c) 2002-2016 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 | -------------------------------------------------------------------------------- /misc/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.13) 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 freenode IRC network (irc.freenode.net) for real-time discussion about the ENet library. 57 | 58 | */ 59 | 60 | -------------------------------------------------------------------------------- /misc/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 | 57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */, 106 | 14400 / 8 /* 56K modem with 14 Kbps upstream 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 | packet = 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 | -------------------------------------------------------------------------------- /misc/packager.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const {Plugin} = require('release-it') 4 | 5 | const basefile = path.join(__dirname, '..', 'include', 'enet.h') 6 | const workdir = path.join(__dirname, 'deploy') 7 | 8 | const versionGet = () => { 9 | const data = fs.readFileSync(basefile, 'utf8') 10 | 11 | const major = data.match(/ENET_VERSION_MAJOR\s+([0-9]+)\n/)[1] 12 | const minor = data.match(/ENET_VERSION_MINOR\s+([0-9]+)\n/)[1] 13 | const patch = data.match(/ENET_VERSION_PATCH\s+([0-9]+)\n/)[1] 14 | const pre = data.match(/ENET_VERSION_PRE\s+\"([\.a-z0-9]+)\"\n/) 15 | 16 | return `${major}.${minor}.${patch}${pre ? '-' + pre[1] : ''}` 17 | } 18 | 19 | const versionSet = (version) => { 20 | let data = fs.readFileSync(basefile, 'utf8') 21 | 22 | let [base, pre] = version.split('-') 23 | let [major, minor, patch] = base.split('.').map(a => parseInt(a)) 24 | 25 | if (!pre) pre = '' 26 | 27 | data = data.replace(/ENET_VERSION_MAJOR\s+([0-9]+)\n/, `ENET_VERSION_MAJOR ${major}\n`) 28 | data = data.replace(/ENET_VERSION_MINOR\s+([0-9]+)\n/, `ENET_VERSION_MINOR ${minor}\n`) 29 | data = data.replace(/ENET_VERSION_PATCH\s+([0-9]+)\n/, `ENET_VERSION_PATCH ${patch}\n`) 30 | data = data.replace(/ENET_VERSION_PRE\s+\"([\.0-9a-z]+)\"\n/, `ENET_VERSION_PRE "${pre}"\n`) 31 | 32 | fs.writeFileSync(basefile, data) 33 | } 34 | 35 | const embedIncludes = (print) => { 36 | if (!fs.existsSync(workdir)) fs.mkdirSync(workdir) 37 | 38 | let data = fs.readFileSync(basefile, 'utf8') 39 | let lines = data.split('\n') 40 | 41 | // const hedley = lines.find(a => a.indexOf('enet_hedley.h') !== -1) 42 | // const hedleyIndex = lines.indexOf(hedley) 43 | 44 | // lines = lines.map((line, i) => { 45 | // if (i < hedleyIndex) return line 46 | // if (line.indexOf('#include') === -1) return line 47 | // if (line.indexOf('<') !== -1) return line 48 | 49 | // const parts = line.split('#include') 50 | // const spaces = parts[0] 51 | // const filename = parts[1].trim().replace(/"/g, '') 52 | 53 | // const content = fs 54 | // .readFileSync(path.join(__dirname, '..', 'code', filename), 'utf8') 55 | // .split('\n') 56 | // .map(l => spaces + l) 57 | // .map(l => l === spaces ? '' : l) 58 | // .join('\n') 59 | // .replace(/\s+$/g, '') 60 | 61 | // return content 62 | // }) 63 | 64 | const code = lines.join('\n') 65 | if (print) console.log(code) 66 | else fs.writeFileSync(path.join(workdir, 'enet.h'), code) 67 | } 68 | 69 | class Bumper extends Plugin { 70 | getLatestVersion() { 71 | return versionGet() 72 | } 73 | 74 | bump(version) { 75 | this.version = version; 76 | versionSet(version) 77 | } 78 | 79 | async beforeRelease() { 80 | embedIncludes() 81 | console.log('done') 82 | } 83 | 84 | afterRelease() { 85 | if (fs.existsSync(path.join(workdir, 'enet.h'))) { 86 | fs.unlinkSync(path.join(workdir, 'enet.h')) 87 | } 88 | } 89 | } 90 | 91 | module.exports = Bumper 92 | module.exports.embedIncludes = embedIncludes 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enet.c", 3 | "version": "2.6.4", 4 | "description": "ENet - Simple, lightweight and reliable UDP networking library written on pure C.", 5 | "main": "include/enet.h", 6 | "directories": { 7 | "doc": "misc/docs" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/zpl-c/enet-c.git" 12 | }, 13 | "keywords": [ 14 | "udp", 15 | "networking", 16 | "c", 17 | "cpp", 18 | "c++" 19 | ], 20 | "author": "Lee Salzman", 21 | "contributors": [ 22 | "Vladyslav Hrytsenko", 23 | "Dominik Madarász" 24 | ], 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/zpl-c/enet-c/issues" 28 | }, 29 | "homepage": "https://github.com/zpl-c/enet-c#readme", 30 | "scripts": { 31 | "embed": "node -e 'require(\"./misc/packager\").embedIncludes()'", 32 | "release": "release-it", 33 | "release-patch": "release-it patch --ci", 34 | "release-minor": "release-it minor --ci", 35 | "release-major": "release-it major --ci", 36 | "release-patch-pre": "release-it patch --preRelease=pre --ci", 37 | "release-minor-pre": "release-it minor --preRelease=pre --ci", 38 | "release-major-pre": "release-it major --preRelease=pre --ci" 39 | }, 40 | "devDependencies": { 41 | "release-it": "^13.6.1" 42 | }, 43 | "release-it": { 44 | "npm": { 45 | "publish": false 46 | }, 47 | "github": { 48 | "release": true, 49 | "assets": [ 50 | "misc/deploy/enet.h" 51 | ] 52 | }, 53 | "plugins": { 54 | "./misc/packager.js": {} 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/build.c: -------------------------------------------------------------------------------- 1 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 2 | 3 | #define ENET_IMPLEMENTATION 4 | #include "enet.h" 5 | #include 6 | 7 | typedef struct { 8 | ENetHost *host; 9 | ENetPeer *peer; 10 | } Client; 11 | 12 | #ifdef ENET_USE_MORE_PEERS 13 | #define MAX_CLIENTS 5000 14 | #else 15 | #define MAX_CLIENTS 32 16 | #endif 17 | 18 | unsigned long long g_counter = 0; 19 | unsigned long long g_disconnected = 0; 20 | 21 | void host_server(ENetHost *server) { 22 | ENetEvent event; 23 | while (enet_host_service(server, &event, 2) > 0) { 24 | switch (event.type) { 25 | case ENET_EVENT_TYPE_CONNECT: 26 | printf("A new peer with ID %u connected from ::1:%u.\n", event.peer->incomingPeerID , event.peer->address.port); 27 | /* Store any relevant client information here. */ 28 | event.peer->data = (void*)(g_counter++); 29 | break; 30 | case ENET_EVENT_TYPE_RECEIVE: 31 | printf("A packet of length %zu containing %s was received from %s on channel %u.\n", 32 | event.packet->dataLength, 33 | event.packet->data, 34 | (char *)event.peer->data, 35 | event.channelID); 36 | 37 | /* Clean up the packet now that we're done using it. */ 38 | enet_packet_destroy (event.packet); 39 | break; 40 | 41 | case ENET_EVENT_TYPE_DISCONNECT: 42 | printf ("Peer with ID %u disconnected.\n", event.peer->incomingPeerID); 43 | g_disconnected++; 44 | /* Reset the peer's client information. */ 45 | event.peer->data = NULL; 46 | break; 47 | 48 | case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: 49 | printf ("Client %u timeout.\n", event.peer->incomingPeerID); 50 | g_disconnected++; 51 | /* Reset the peer's client information. */ 52 | event.peer->data = NULL; 53 | break; 54 | 55 | case ENET_EVENT_TYPE_NONE: break; 56 | } 57 | } 58 | } 59 | 60 | int main() { 61 | if (enet_initialize() != 0) { 62 | printf("An error occurred while initializing ENet.\n"); 63 | return 1; 64 | } 65 | 66 | int i = 0; 67 | ENetHost *server; 68 | Client clients[MAX_CLIENTS]; 69 | ENetAddress address = {0}; 70 | 71 | address.host = ENET_HOST_ANY; /* Bind the server to the default localhost. */ 72 | address.port = 7777; /* Bind the server to port 7777. */ 73 | 74 | 75 | /* create a server */ 76 | printf("starting server...\n"); 77 | server = enet_host_create(&address, MAX_CLIENTS, 2, 0, 0); 78 | if (server == NULL) { 79 | printf("An error occurred while trying to create an ENet server host.\n"); 80 | return 1; 81 | } 82 | 83 | printf("starting clients...\n"); 84 | for (i = 0; i < MAX_CLIENTS; ++i) { 85 | enet_address_set_host(&address, "127.0.0.1"); 86 | clients[i].host = enet_host_create(NULL, 1, 2, 0, 0); 87 | clients[i].peer = enet_host_connect(clients[i].host, &address, 2, 0); 88 | if (clients[i].peer == NULL) { 89 | printf("coundlnt connect\n"); 90 | return 1; 91 | } 92 | } 93 | 94 | printf("running server...\n"); 95 | 96 | // program will make N iterations, and then exit 97 | static int counter = 1000; 98 | 99 | do { 100 | host_server(server); 101 | 102 | ENetEvent event; 103 | for (i = 0; i < MAX_CLIENTS; ++i) { 104 | enet_host_service(clients[i].host, &event, 0); 105 | } 106 | 107 | counter--; 108 | } while (counter > 0); 109 | 110 | printf("stopping clients...\n"); 111 | 112 | for (i = 0; i < MAX_CLIENTS; ++i) { 113 | enet_peer_disconnect_now(clients[i].peer, 0); 114 | enet_host_destroy(clients[i].host); 115 | } 116 | 117 | counter = 1000; 118 | 119 | do { 120 | host_server(server); 121 | #ifdef _WIN32 122 | Sleep(1); 123 | #else 124 | usleep(1000); 125 | #endif 126 | counter--; 127 | } while (g_disconnected < g_counter); 128 | 129 | enet_host_destroy(server); 130 | enet_deinitialize(); 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /test/cli-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define ENET_IMPLEMENTATION 3 | #include "enet.h" 4 | // #define WIN32_LEAN_AND_MEAN 5 | // #include 6 | 7 | void run_server(); 8 | void run_client(); 9 | 10 | int main(int argc, char** argv) { 11 | if (enet_initialize() < 0) { 12 | printf("failed to initialize enet\n"); 13 | }; 14 | 15 | bool server; 16 | if (argc == 2 && !strcmp(argv[1], "-server")) { 17 | server = true; 18 | } else { 19 | server = false; 20 | } 21 | 22 | if (server) { 23 | printf("launching server\n"); 24 | run_server(); 25 | } else { 26 | printf("launching client\n"); 27 | run_client(); 28 | } 29 | 30 | printf("done\n"); 31 | enet_deinitialize(); 32 | 33 | return 0; 34 | } 35 | 36 | void run_server() { 37 | ENetAddress address = {}; 38 | address.host = ENET_HOST_ANY; 39 | address.port = 1234; 40 | 41 | ENetHost* host = enet_host_create(&address, 4, 1, 0, 0); 42 | 43 | if (!host) { 44 | printf("Failed to create server\n"); 45 | } 46 | 47 | printf("Server started...\n"); 48 | 49 | while (true) { 50 | ENetEvent event; 51 | while (enet_host_service(host, &event, 2) > 0) { 52 | switch (event.type) { 53 | case ENET_EVENT_TYPE_CONNECT: { 54 | printf("A client has connected!\n"); 55 | } break; 56 | case ENET_EVENT_TYPE_RECEIVE: { 57 | printf("Message recieved! %s\n", event.packet->data); 58 | enet_packet_destroy(event.packet); 59 | } break; 60 | case ENET_EVENT_TYPE_DISCONNECT: 61 | case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: 62 | printf("A client has disconnected\n"); 63 | break; 64 | case ENET_EVENT_TYPE_NONE: 65 | break; 66 | } 67 | } 68 | 69 | ENetPeer* currentPeer; 70 | // for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { 71 | // if (currentPeer->state != ENET_PEER_STATE_CONNECTED) { 72 | // continue; 73 | // } 74 | 75 | // ENetPacket * packet = enet_packet_create("HELLO WORLD", strlen("HELLO WORLD"), ENET_PACKET_FLAG_RELIABLE); 76 | // enet_peer_send(currentPeer, 0, packet); 77 | // } 78 | 79 | for (int i = 0; i < 4; i++) { 80 | ENetPeer* peer = &host->peers[i]; 81 | if (peer->state == ENET_PEER_STATE_CONNECTED) { 82 | ENetPacket * packet = 83 | enet_packet_create("HELLO WORLD", strlen("HELLO WORLD"), 84 | ENET_PACKET_FLAG_RELIABLE); 85 | enet_peer_send(peer, 0, packet); 86 | } 87 | } 88 | 89 | usleep(16000); 90 | } 91 | 92 | enet_host_destroy(host); 93 | } 94 | 95 | void run_client() { 96 | ENetAddress address = {}; 97 | address.host = ENET_HOST_ANY; 98 | address.port = 1234; 99 | 100 | ENetHost* host = enet_host_create(NULL, 1, 1, 0, 0); 101 | 102 | enet_address_set_host(&address, "127.0.0.1"); 103 | address.port = 1234; 104 | printf("Connecting to server\n"); 105 | ENetPeer * peer = enet_host_connect(host, &address, 1, 0); 106 | 107 | if (!host) { 108 | printf("Failed to create client\n"); 109 | } 110 | 111 | bool connected = false; 112 | 113 | while (true) { 114 | ENetEvent event; 115 | while (enet_host_service(host, &event, 0) > 0) { 116 | switch (event.type) { 117 | case ENET_EVENT_TYPE_CONNECT: { 118 | printf("Connected to server\n"); 119 | connected = true; 120 | } break; 121 | case ENET_EVENT_TYPE_RECEIVE: { 122 | printf("Message recieved! %s\n", event.packet->data); 123 | enet_packet_destroy(event.packet); 124 | } break; 125 | case ENET_EVENT_TYPE_DISCONNECT: 126 | case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: 127 | printf("A client has disconnected\n"); 128 | break; 129 | } 130 | } 131 | 132 | if (connected) { 133 | if (peer->state == ENET_PEER_STATE_CONNECTED) { 134 | ENetPacket *packet = 135 | enet_packet_create("HELLO WORLD", strlen("HELLO WORLD"), 136 | ENET_PACKET_FLAG_RELIABLE); 137 | enet_peer_send(peer, 0, packet); 138 | } 139 | } 140 | 141 | usleep(16000); 142 | } 143 | 144 | enet_host_destroy(host); 145 | } 146 | -------------------------------------------------------------------------------- /test/library.c: -------------------------------------------------------------------------------- 1 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 2 | #define ENET_IMPLEMENTATION 3 | #include "enet.h" 4 | -------------------------------------------------------------------------------- /test/resize.c: -------------------------------------------------------------------------------- 1 | #define ENET_IMPLEMENTATION 2 | #include "enet.h" 3 | int main() { 4 | ENetPacket *packet = enet_packet_create("packet", 5 | strlen("packet"), 6 | ENET_PACKET_FLAG_RELIABLE); 7 | printf("length: %d, data: %.*s\n", packet->dataLength, packet->dataLength, (char*)packet->data); 8 | packet = enet_packet_resize(packet, strlen("packetfoo")); 9 | strcpy (& packet -> data [strlen ("packet")], "foo"); 10 | printf("length: %d, data: %.*s\n", packet->dataLength, packet->dataLength, (char*)packet->data); 11 | packet = enet_packet_resize(packet, strlen("packet")); 12 | printf("length: %d, data: %.*s\n", packet->dataLength, packet->dataLength, (char*)packet->data); 13 | packet = enet_packet_resize(packet, strlen("packetfoobar")); 14 | strcpy (& packet -> data [strlen ("packet")], "foobar"); 15 | printf("length: %d, data: %.*s\n", packet->dataLength, packet->dataLength, (char*)packet->data); 16 | } 17 | --------------------------------------------------------------------------------