├── Makefile ├── README.md ├── Tutorial.md ├── build └── enet.js ├── examples ├── chrome │ ├── README │ ├── app │ │ ├── background.js │ │ ├── bundle.zip │ │ ├── client.js │ │ ├── echo-server.js │ │ ├── index.html │ │ └── manifest.json │ └── build.sh ├── client.js ├── custom-socket.js ├── get-file.js ├── serve-file.js └── server.js ├── find-emcc.py ├── index.js ├── lib ├── Address.js ├── Event.js ├── Host.js ├── PACKET_FLAG.js ├── PEER_STATE.js ├── Packet.js └── Peer.js ├── package.json └── src ├── enet ├── callbacks.c ├── compress.c ├── host.c ├── include │ └── enet │ │ ├── enet.h │ │ ├── list.h │ │ ├── protocol.h │ │ ├── time.h │ │ ├── types.h │ │ ├── unix.h │ │ └── utility.h ├── list.c ├── packet.c ├── peer.c ├── protocol.c └── unix.c ├── enet_pre.js ├── jsapi.c ├── library_inet.js ├── library_node_sockets.js ├── wrap_footer.js └── wrap_header.js /Makefile: -------------------------------------------------------------------------------- 1 | EMCC=`./find-emcc.py`/emcc 2 | #todo - refactor src/library_inet.js and src/library_node_sockets.js to handle closure compiler before enabling it 3 | OPTIMISE= -O2 --closure 0 -s ASM_JS=1 --llvm-opts 1 --memory-init-file 0 4 | ENET_SOURCE=./src/enet 5 | 6 | EXPORTED_FUNCTIONS= -s EXPORTED_FUNCTIONS="[ \ 7 | '_jsapi_init', \ 8 | '_enet_host_service', \ 9 | '_enet_host_destroy', \ 10 | '_enet_host_flush', \ 11 | '_enet_host_bandwidth_throttle', \ 12 | '_enet_host_broadcast', \ 13 | '_enet_host_compress_with_range_coder', \ 14 | '_enet_host_compress', \ 15 | '_jsapi_host_get_receivedAddress', \ 16 | '_jsapi_host_get_socket', \ 17 | '_jsapi_enet_host_create_server', \ 18 | '_jsapi_enet_host_create_client', \ 19 | '_jsapi_enet_host_from_socket', \ 20 | '_jsapi_enet_host_bind', \ 21 | '_jsapi_enet_host_connect', \ 22 | '_enet_packet_create', \ 23 | '_enet_packet_destroy', \ 24 | '_jsapi_packet_set_free_callback', \ 25 | '_jsapi_packet_get_data', \ 26 | '_jsapi_packet_get_dataLength', \ 27 | '_jsapi_packet_flags', \ 28 | '_jsapi_event_new', \ 29 | '_jsapi_event_free', \ 30 | '_jsapi_event_get_type', \ 31 | '_jsapi_event_get_peer', \ 32 | '_jsapi_event_get_packet', \ 33 | '_jsapi_event_get_data', \ 34 | '_jsapi_event_get_channelID', \ 35 | '_jsapi_address_get_host', \ 36 | '_jsapi_address_get_port', \ 37 | '_enet_peer_send', \ 38 | '_enet_peer_reset', \ 39 | '_enet_peer_ping', \ 40 | '_enet_peer_disconnect', \ 41 | '_enet_peer_disconnect_now', \ 42 | '_enet_peer_disconnect_later', \ 43 | '_jsapi_peer_get_address', \ 44 | '_jsapi_peer_get_state', \ 45 | '_jsapi_peer_get_incomingDataTotal', \ 46 | '_jsapi_peer_get_outgoingDataTotal', \ 47 | '_jsapi_peer_get_reliableDataInTransit' ]" 48 | 49 | module: 50 | $(EMCC) src/jsapi.c $(ENET_SOURCE)/*.c -I$(ENET_SOURCE)/include \ 51 | --pre-js src/enet_pre.js -o build/enet_.js $(OPTIMISE) \ 52 | --js-library src/library_node_sockets.js --js-library src/library_inet.js \ 53 | -s LINKABLE=1 $(EXPORTED_FUNCTIONS) -s RESERVED_FUNCTION_POINTERS=128 -s CHROME_SOCKETS=1 \ 54 | -s ALLOW_MEMORY_GROWTH=1 55 | cat src/wrap_header.js build/enet_.js src/wrap_footer.js > build/enet.js 56 | rm build/enet_.js 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### enet 2 | emscripten compiled [enet networking library](http://enet.bespin.org/) 3 | 4 | ENet's purpose is to provide a relatively thin, simple and robust network communication 5 | layer on top of UDP (User Datagram Protocol). The primary feature it provides is optional 6 | reliable, in-order delivery of packets. 7 | 8 | #### npm package 9 | 10 | enet is published in the [npm registry](https://npmjs.org/package/enet), to install it into your project: 11 | 12 | npm install enet 13 | 14 | #### Documentation 15 | 16 | [Quick Tutorial](https://github.com/mnaamani/enet-npm/blob/master/Tutorial.md) 17 | 18 | #### License 19 | 20 | enet npm module is written by Mokhtar Naamani 21 | and is licensed under the [MIT 22 | license](http://opensource.org/licenses/MIT): 23 | 24 | > Copyright © 2013-2015 Mokhtar Naamani. 25 | > 26 | > Permission is hereby granted, free of charge, to any person 27 | > obtaining a copy of this software and associated documentation files 28 | > (the "Software"), to deal in the Software without restriction, 29 | > including without limitation the rights to use, copy, modify, merge, 30 | > publish, distribute, sublicense, and/or sell copies of the Software, 31 | > and to permit persons to whom the Software is furnished to do so, 32 | > subject to the following conditions: 33 | > 34 | > The above copyright notice and this permission notice shall be 35 | > included in all copies or substantial portions of the Software. 36 | > 37 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 38 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 39 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 40 | > NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 41 | > BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 42 | > ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 43 | > CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 44 | > SOFTWARE. 45 | 46 | enet is Copyright (c) 2002-2013 [Lee Salzman](http://enet.bespin.org/License.html) 47 | -------------------------------------------------------------------------------- /Tutorial.md: -------------------------------------------------------------------------------- 1 | ### ENet Quick Tutorial 2 | 3 | Following the same steps as the native C library [tutorial](http://enet.bespin.org/Tutorial.html) ... 4 | 5 | ### Initialisation 6 | 7 | var enet = require("enet"); 8 | 9 | optionally initialise enet with a packet-filtering function. It will be applied 10 | to all incoming packets for all hosts: 11 | 12 | enet.init(function(ipaddress /*String*/, port /*Number*/){ 13 | if(ipaddress === '192.168.0.22'){ 14 | return 0; //drop the packet 15 | } 16 | return 1; //permit the packet 17 | }); 18 | 19 | ### Creating an ENet server (instance of enet.Host) 20 | 21 | Specify address and port to listen on, 22 | 23 | var addr = new enet.Address("0.0.0.0", /* ANY ADDRESS */ 24 | 7777 /* UDP Port 7777 */); 25 | or 26 | 27 | var addr = {address:"0.0.0.0", port:7777} 28 | 29 | Create the server, it will be returned in the callback, 30 | 31 | enet.createServer({ 32 | address: addr, /* the address the server host will bind to */ 33 | peers:32, /* allow up to 32 clients and/or outgoing connections */ 34 | channels:2, /* allow up to 2 channels to be used, 0 and 1 */ 35 | down:0, /* assume any amount of incoming bandwidth */ 36 | up:0 /* assume any amount of outgoing bandwidth */ 37 | 38 | },function(err, host){ 39 | if(err){ 40 | return; /* host creation failed */ 41 | } 42 | 43 | //setup event handlers.. 44 | host.on("connect",function(peer,data){ 45 | //incoming peer connection 46 | peer.on("message",function(packet,channel){ 47 | console.log("received packet contents:",packet.data()); 48 | }); 49 | }); 50 | 51 | //start polling the host for events at 50ms intervals 52 | host.start(50); 53 | }); 54 | 55 | When done with a host, the host should be destroyed with the destroy() method. 56 | All connected peers to the host will be reset, and the resources used by the host will be freed. 57 | 58 | server.destroy(); 59 | 60 | ### Creating an ENet client (instance of enet.Host) 61 | 62 | Create the host, no address need to be specified to bind the host to. Bandwidth may be specified for the client host as in the above example. The peers count controls the maximum number of connections to other server hosts that may be simultaneously open. 63 | A client host will not accept incoming connections. 64 | 65 | enet.createClient({ 66 | peers: 1, /* only allow 1 outgoing connection */ 67 | channels: 2, /* allow up to 2 channels to be used, 0 and 1 */ 68 | down: 57600 / 8, /* 56K modem with 56 Kbps downstream bandwidth */ 69 | up: 14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */ 70 | },function(err, host){ 71 | if(err){ 72 | return; /* host creation failed */ 73 | } 74 | //setup event handler 75 | host.on("connect",function(peer,data){ 76 | //incoming peer connection 77 | peer.on("message",function(packet,channel){ 78 | console.log("received packet contents:",packet.data()); 79 | }); 80 | }); 81 | }); 82 | 83 | Polling the host for events begins automatically when the host makes its first outgoing connection. 84 | 85 | ### Managing an enet.Host 86 | enet.Host emits the following events: 87 | 88 | **connect** event is emitted when either a new client host has connected to the server host or when an attempt to establish a connection with a foreign host has succeeded. 89 | 90 | host.on("connect", function(peer, data, outgoing){ 91 | //handle new connected peer 92 | }); 93 | 94 | `outgoing` is `true` if the local host initiated connection. 95 | `data` is optional connect data sent by foreign host (the `peer`) 96 | for an incoming connection, and `undefined` if connection was initiated from local host. 97 | 98 | 99 | **message** event is emitted when a packet is received from a connected peer. 100 | 101 | host.on("message", function(peer, packet, channel){ 102 | //handle incoming packet 103 | }); 104 | 105 | An enet `packet` was received on channel number `channel`, from `peer`. 106 | The packet data as a Buffer is retrieved with packet.data() 107 | the packet will be automatically destroyed when the callback returns, 108 | so do not pass the packet to an async function, instead pass the Buffer. 109 | 110 | **destory** event will be emitted when the host is destroyed. 111 | 112 | **telex** event is emitted when a raw JSON packet (telehash telex) is received. 113 | 114 | host.on("telex", function(buffer /*Buffer*/,source){ 115 | //hand of to telehash switch for processing 116 | }); 117 | 118 | source is an object with `address` and `port` properties (source of udp packet) 119 | 120 | 121 | ### Connecting to an ENet host 122 | /* connect to server 192.168.1.55:7777 */ 123 | var server_addr = new enet.Address("192.168.1.55",7777); 124 | 125 | /* Initiate the connection, allocating the two channels 0 and 1. */ 126 | var peer = client.connect(server_addr, 127 | 2, /* channels */ 128 | 1337, /* data to send, (received in 'connect' event at server) */ 129 | function(err,peer){ /* a connect callback function */ 130 | if(err){ 131 | console.error(err);//either connect timeout or maximum peers exceeded 132 | return; 133 | } 134 | //connection to the remote host succeeded 135 | peer.ping(); 136 | }); 137 | 138 | //succesful connect event can also be handled with an event handler 139 | peer.on("connect",function(){ 140 | //connection to the remote host succeeded 141 | peer.ping(); 142 | }); 143 | 144 | ### Sending a packet to an ENet peer 145 | 146 | Packets in enet can be constructed from strings or Buffers. 147 | 148 | var packet = new enet.Packet(new Buffer("hello, world"), enet.PACKET_FLAG.RELIABLE); 149 | 150 | or 151 | 152 | var packet = new enet.Packet("hello"); //unreliable packet 153 | 154 | enet.PACKET_FLAG.RELIABLE specifies that the packet must use reliable delivery. A reliable packet is guaranteed to be delivered, and a number of retry attempts will be made until an acknowledgement is received from the peer. If a certain number of retry attempts is reached without any acknowledgement, ENet will assume the peer has disconnected and forcefully reset the connection. If this flag is not specified, the packet is assumed an unreliable packet, and no retry attempts will be made nor acknowledgements generated. 155 | 156 | A packet is sent to a peer with the peer.send() method, which accepts a channel id over which to send the packet and the packet. 157 | 158 | var err = peer.send(0 /*channel*/, packet); 159 | 160 | peer.send() will return `true` if we attempt to send a packet when peer is not connected, or if an error occurs queuing the packet for delivery. 161 | 162 | 163 | peer.send() can also accept an optional callback function: 164 | 165 | var err = peer.send(0, packet, function(err){ 166 | if (err) { 167 | console.error("error sending packet!", err); 168 | } else { 169 | console.log("packet sent successfully."); 170 | } 171 | }); 172 | 173 | The callback function will be called immediately (synchronously) with an error if either the peer is not connected, or there was an error queuing the outgoing packet, otherwise packet will be queued for delivery. 174 | 175 | Once a packet is queued for delivery it is managed by enet and destroyed when no longer required. The callback is called when enet internally destroys the packet. For reliable packets this occurs when the peer acknowledges receipt of the packet or when the peer is reset/disconnected. For unreliable packets this will happen when then the packet is transmitted. 176 | 177 | We can also pass in a string or buffer instead of a packet. It will be converted internally into a reliable packet. 178 | 179 | sending a string on channel 0 180 | 181 | peer.send(0, "Hello ENet"); 182 | 183 | send a buffer 184 | 185 | peer.send(0, new Buffer("Hello World")); 186 | 187 | serialising an object and sending it as a JSON string 188 | 189 | peer.send(0, JSON.stringify(myObject)); 190 | 191 | 192 | ### Peer events 193 | 194 | **connect** event is emitted when the peer successfully connects to a remote host. 195 | 196 | **message** event is emitted when a packet is received from a the peer. 197 | 198 | peer.on("message", function(packet, channel_id){ 199 | //handle packet from peer 200 | }); 201 | 202 | **disconnect** event is emitted when a the peer has either explicitly disconnected or timed out. 203 | 204 | peer.on("disconnect", function(data){ 205 | //peer disconnected 206 | }); 207 | 208 | `data` is optional data sent by remote peer when disconnecting. 209 | 210 | 211 | ### Disconnecting an ENet peer 212 | 213 | peer.disconnect(999); /*send 999 as data with disconnect message*/ 214 | 215 | ### Streams 216 | 217 | To communicate with a peer using the streams API we can turn a channel into a readable stream or writeable stream. 218 | 219 | For example use createReadStream method to create a readable stream: 220 | 221 | var stream = peer.createReadStream(0); 222 | stream.pipe(process.stdout); 223 | 224 | will pipe the data coming in on channel 0 from peer to stdout. 225 | 226 | A writeable stream can be created using createWriteStream method of peer: 227 | 228 | var file = fs.createReadStream("data.txt"); 229 | var stream = peer.createWriteStream(2); 230 | file.pipe(stream); 231 | 232 | will send the contents of data.txt file to the peer on channel 2 233 | 234 | A duplex stream can also be created with peer.createDuplexStream() method 235 | 236 | Ideally streams should be created after a peer is in CONNECTED state. (in the connect event listeners) 237 | If you try to read from or write to a stream of a disconnected peer it will raise the error event on the stream. 238 | 239 | Its important to 'throttle' when writing to a stream to prevent emscripten from growing its memory arrays too much 240 | to make more memory available when allocating dynamic memory for the packets. (See the serve-file.js example howto throttle) 241 | -------------------------------------------------------------------------------- /examples/chrome/README: -------------------------------------------------------------------------------- 1 | run the ./build.sh script 2 | to generate the bundle.js in the chrome app folder 3 | Or you can just unzip the precompiled bundle.zip 4 | -------------------------------------------------------------------------------- /examples/chrome/app/background.js: -------------------------------------------------------------------------------- 1 | chrome.app.runtime.onLaunched.addListener(function() { 2 | chrome.app.window.create('index.html', { 3 | 'width': 600, 4 | 'height': 300, 5 | 'type': 'panel' 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /examples/chrome/app/bundle.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnaamani/enet-npm/cf3ba625f1ba1c83a4aff6d322d91d83427d5585/examples/chrome/app/bundle.zip -------------------------------------------------------------------------------- /examples/chrome/app/client.js: -------------------------------------------------------------------------------- 1 | var enet = ENET; 2 | var Buffer = ENET.Buffer; 3 | 4 | var s_addr = new enet.Address("127.0.0.1", 6666); 5 | 6 | enet.createClient(function (err, client) { 7 | if (err) { 8 | console.log(err); 9 | return; 10 | } 11 | client.enableCompression(); 12 | client.on("destroy", function () { 13 | console.log("shutdown!"); 14 | }); 15 | 16 | connect(); 17 | 18 | console.log("connecting..."); 19 | 20 | function connect() { 21 | client.connect(s_addr, 1, 0, function (err, peer, data) { 22 | if (err) { 23 | console.log(err); 24 | if (err.message === "host-destroyed") process.exit(); 25 | console.log("retrying..."); 26 | setTimeout(connect, 1000); 27 | return; 28 | } 29 | console.log("connected"); 30 | console.log("connected to:", peer.address()); 31 | 32 | peer.on("message", function (packet, chan) { 33 | console.log("got message:", packet.data().toString()); 34 | }); 35 | 36 | peer.once("disconnect", function () { 37 | console.log("disconnected."); 38 | console.log("shutting down..."); 39 | client.destroy(); 40 | }); 41 | 42 | var packet = new enet.Packet(new Buffer("Hello\n"), enet.PACKET_FLAG.RELIABLE); 43 | 44 | peer.send(0, packet, function (err) { 45 | if (err) console.log("error sending packet:", e); 46 | }); 47 | 48 | peer.send(0, "test 123...\n"); 49 | 50 | }); 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /examples/chrome/app/echo-server.js: -------------------------------------------------------------------------------- 1 | var global_server; 2 | 3 | ENET.createServer({ 4 | address: { 5 | address: "0.0.0.0", 6 | port: "6666" 7 | }, 8 | }, 9 | function (err, host) { 10 | if (err) { 11 | console.log(err); 12 | return; 13 | } 14 | global_server = host; 15 | console.log("host ready on %s:%s", host.address().address, host.address().port); 16 | 17 | host.on("connect", function (peer, data) { 18 | console.log("peer connected"); 19 | peer.createReadStream(0).pipe(peer.createWriteStream(0)); 20 | }); 21 | 22 | host.start(); 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /examples/chrome/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
Testing ENET in Chrome App
9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/chrome/app/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "ENET-Test", 4 | "description":"ENet in chrome app, using chrome.socket", 5 | "version":"0.1", 6 | "permissions":[ 7 | { 8 | "socket": ["udp-send-to:*:*","udp-bind"]} 9 | ], 10 | "app":{ 11 | "background":{ 12 | "scripts":["background.js"] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/chrome/build.sh: -------------------------------------------------------------------------------- 1 | #browserify enet and some methods to process shim to make emscripten runtime think it is in NODE environment 2 | browserify --im ../../index.js -s ENET | sed -e "s/var process = module.exports = {};/var process=module.exports={};process.platform='browser';process.stdout={write:function(x){console.log(x)}};process.stderr={write:function(x){console.error(x)}};process.exit=noop;/" > app/bundle.js 3 | -------------------------------------------------------------------------------- /examples/client.js: -------------------------------------------------------------------------------- 1 | var enet = require("../index.js"); 2 | 3 | var s_addr = new enet.Address("127.0.0.1", 6666); 4 | 5 | enet.createClient(function (err, client) { 6 | if (err) { 7 | console.log(err); 8 | return; 9 | } 10 | client.enableCompression(); 11 | client.on("destroy", function () { 12 | console.log("shutdown!"); 13 | }); 14 | 15 | connect(); 16 | 17 | console.log("connecting..."); 18 | 19 | function connect() { 20 | client.connect(s_addr, 1, 0, function (err, peer, data) { 21 | if (err) { 22 | console.log(err); 23 | if (err.message === "host-destroyed") process.exit(); 24 | console.log("retrying..."); 25 | setTimeout(connect, 1000); 26 | return; 27 | } 28 | 29 | console.log("connected to:", peer.address()); 30 | 31 | peer.on("message", function (packet, chan) { 32 | console.log("got message:", packet.data().toString()); 33 | }); 34 | 35 | peer.on("disconnect", function () { 36 | console.log("disconnected, sending final packet"); 37 | peer.send(0, "final packet", function (err) { 38 | console.log(err || "final packet sent!"); 39 | }); 40 | 41 | console.log("shutting down"); 42 | setTimeout(function () { 43 | client.destroy(); 44 | }); 45 | }); 46 | 47 | var packet1 = new enet.Packet(new Buffer("Hello\n"), enet.PACKET_FLAG.RELIABLE); 48 | console.log("sending packet 1..."); 49 | peer.send(0, packet1, function (err) { 50 | if (err) { 51 | console.log("error sending packet 1:", err); 52 | } else { 53 | console.log("packet 1 sent."); 54 | } 55 | }); 56 | 57 | var packet2 = new enet.Packet(new Buffer("test unreliable packet\n"), enet.PACKET_FLAG.UNRELIABLE); 58 | console.log("sending packet 2..."); 59 | peer.send(0, packet2, function (err) { 60 | if (err) { 61 | console.log("error sending packet 2:", err); 62 | } else { 63 | console.log("packet 2 sent."); 64 | } 65 | }); 66 | 67 | peer.disconnectLater(); 68 | 69 | var packet3 = new enet.Packet(new Buffer("test after disconnect\n"), enet.PACKET_FLAG.RELIABLE); 70 | console.log("sending packet 3..."); 71 | peer.send(0, packet3, function (err) { 72 | if (err) { 73 | console.log("error sending packet 3:", err); 74 | } else { 75 | console.log("packet 3 sent."); 76 | } 77 | }); 78 | }); 79 | } 80 | }); 81 | -------------------------------------------------------------------------------- /examples/custom-socket.js: -------------------------------------------------------------------------------- 1 | var enet = require("../index.js"); 2 | var assert = require("assert"); 3 | 4 | //create a custom socket for enet host 5 | //in this example we are using a node dgram, 6 | //we could pass in any object that is an event emitter and follows the same dgram API 7 | //possibly a proxied UDP connection over HTTP/WebSockets 8 | 9 | var mysocket = require("dgram").createSocket("udp4"); 10 | mysocket.on("listening", function () { 11 | console.log("mysocket listening..."); 12 | start_server(mysocket); 13 | }); 14 | mysocket.bind(6666); 15 | 16 | function start_server(socket) { 17 | console.log("starting server"); 18 | enet.createServerFromSocket({ 19 | socket: socket 20 | }, 21 | function (err, host) { 22 | if (err) { 23 | console.log(err); 24 | return; 25 | } 26 | host.enableCompression(); 27 | console.log("host ready on %s:%s", host.address().address, host.address().port); 28 | host.on("connect", function (peer, data) { 29 | console.log("peer connected"); 30 | peer.createWriteStream(peer, 0).write("hello I'm the server!"); 31 | peer.createReadStream(0).pipe(process.stdout); 32 | setTimeout(function () { 33 | peer.disconnect(); 34 | }, 2000); 35 | 36 | peer.on("disconnect", function () { 37 | console.log("disconnected peer"); 38 | host.stop(); 39 | }); 40 | }); 41 | 42 | host.on("destroy", function () { 43 | console.log("Host Destroyed, but socket should still be open."); 44 | assert(mysocket._receiving === true); 45 | mysocket.close(); 46 | }); 47 | 48 | host.start(); 49 | } 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /examples/get-file.js: -------------------------------------------------------------------------------- 1 | var enet = require("../index.js"); 2 | var fs = require("fs"); 3 | 4 | var s_addr = new enet.Address("127.0.0.1", 6666); 5 | 6 | enet.createClient(function (err, host) { 7 | if (err) { 8 | console.log(err); 9 | return; 10 | } 11 | //host.enableCompression(); 12 | console.log("client ready, connecting..."); 13 | var peer = host.connect(s_addr, 1, 0); 14 | peer.on("connect", function () { 15 | console.log("connected"); 16 | var stream = peer.createReadStream(0); 17 | stream.pipe(fs.createWriteStream("./got-file.txt")); 18 | stream.on("end", function () { 19 | console.log("received file."); 20 | }); 21 | stream.on("error", function (e) { 22 | console.log("streaming error:", e); 23 | }); 24 | }); 25 | 26 | peer.on("disconnect", function () { 27 | console.log("disconnected."); 28 | host.stop(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /examples/serve-file.js: -------------------------------------------------------------------------------- 1 | var enet = require("../index.js"); 2 | var fs = require("fs"); 3 | var Throttle = require("throttle"); 4 | 5 | var server = enet.createServer({ 6 | address: new enet.Address("0.0.0.0", 6666), 7 | peers: 32, 8 | channels: 1, 9 | down: 0, 10 | up: 0 11 | }, function (err, server) { 12 | if (err) { 13 | console.log(err); 14 | return; 15 | } 16 | console.log("server ready"); 17 | //server.enableCompression(); 18 | server.on("connect", function (peer, data) { 19 | console.log("sending file:", process.argv[2]); 20 | 21 | var file = fs.createReadStream(process.argv[2]); 22 | //always create writestreams after connection is made 23 | var stream = peer.createWriteStream(0); 24 | 25 | var throttle = new Throttle(1024 * 1024 * 5); 26 | 27 | file.pipe(throttle).pipe(stream); 28 | 29 | throttle.on("end", function () { 30 | console.log("served file."); 31 | peer.disconnectLater(); 32 | }); 33 | 34 | stream.on("error", function (e) { 35 | console.log("stream error.", e); 36 | }); 37 | 38 | }); 39 | 40 | server.start(); 41 | }); 42 | -------------------------------------------------------------------------------- /examples/server.js: -------------------------------------------------------------------------------- 1 | var enet = require("../index.js"); 2 | 3 | enet.createServer({ 4 | address: { 5 | address: "0.0.0.0", 6 | port: "6666" 7 | }, 8 | peers: 32, 9 | channels: 1, 10 | down: 0, 11 | up: 0 12 | }, 13 | function (err, host) { 14 | if (err) { 15 | console.log(err); 16 | return; 17 | } 18 | host.enableCompression(); 19 | console.log("host ready on %s:%s", host.address().address, host.address().port); 20 | 21 | host.on("connect", function (peer, data) { 22 | console.log("peer connected"); 23 | peer.createWriteStream(0).write("hello I'm the server!"); 24 | peer.createReadStream(0).pipe(process.stdout); 25 | setTimeout(function () { 26 | peer.disconnectLater(); 27 | }, 2000); 28 | 29 | peer.on("disconnect", function () { 30 | console.log("peer disconnected"); 31 | }); 32 | }); 33 | 34 | host.start(); 35 | } 36 | ); 37 | -------------------------------------------------------------------------------- /find-emcc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import os 3 | exec(open(os.path.expanduser("~/.emscripten")).read()) 4 | print(EMSCRIPTEN_ROOT) 5 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var ENETModule = require("./build/enet.js"); 2 | 3 | var jsapi_ = ENETModule.jsapi; 4 | 5 | var enet = module.exports = {}; 6 | 7 | enet.Host = require("./lib/Host.js").Host; 8 | enet.createServer = require("./lib/Host.js").createServer; 9 | enet.createClient = require("./lib/Host.js").createClient; 10 | enet.createServerFromSocket = require("./lib/Host.js").createServerFromSocket; 11 | enet.Event = require("./lib/Event.js").Event; 12 | enet.Address = require("./lib/Address.js").Address; 13 | enet.Packet = require("./lib/Packet.js").Packet; 14 | enet.Peer = require("./lib/Peer.js").Peer; 15 | enet.Buffer = require("buffer").Buffer; //for use in chrome app when creating packets 16 | enet.PACKET_FLAG = require("./lib/PACKET_FLAG.js").PACKET_FLAG; 17 | enet.PEER_STATE = require("./lib/PEER_STATE.js").PEER_STATE; 18 | 19 | enet.init = function (func) { 20 | var funcPointer = ENETModule["Runtime_addFunction"](function (host_ptr) { 21 | var addr = new enet.Address(jsapi_.host_get_receivedAddress(host_ptr)); 22 | return func(addr.address(), addr.port()); 23 | }); 24 | jsapi_.init(funcPointer); 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /lib/Address.js: -------------------------------------------------------------------------------- 1 | var ENETModule = require("../build/enet.js"); 2 | var jsapi_ = ENETModule.jsapi; 3 | 4 | module.exports.Address = Address; 5 | 6 | function ip2long(ipstr) { 7 | var b = ipstr.split('.'); 8 | return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; 9 | } 10 | 11 | function long2ip(addr) { 12 | return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 13 | 0xff); 14 | } 15 | 16 | function Address() { 17 | if (arguments.length == 1 && typeof arguments[0] == 'object') { 18 | if (arguments[0] instanceof Address) { 19 | this._host = arguments[0].host(); 20 | this._port = arguments[0].port(); 21 | } else { 22 | this._host = ip2long((arguments[0]).address || 0); 23 | this._port = parseInt(arguments[0].port || 0); 24 | } 25 | return this; 26 | } 27 | if (arguments.length == 1 && typeof arguments[0] == 'number') { 28 | this._pointer = arguments[0]; 29 | return this; 30 | } 31 | if (arguments.length == 1 && typeof arguments[0] == 'string') { 32 | var ipp = arguments[0].split(':'); 33 | this._host = ip2long(ipp[0]); 34 | this._port = parseInt(ipp[1] || 0); 35 | return this; 36 | } 37 | if (arguments.length == 2) { 38 | if (typeof arguments[0] == 'string') { 39 | this._host = ip2long((arguments[0])); 40 | } else { 41 | this._host = arguments[0]; 42 | } 43 | this._port = parseInt(arguments[1]); 44 | return this; 45 | } 46 | throw ("bad parameters creating Address"); 47 | } 48 | 49 | Address.prototype.host = function () { 50 | if (this._pointer) { 51 | var hostptr = jsapi_.address_get_host(this._pointer); 52 | return ENETModule["HEAPU32"][hostptr >> 2]; 53 | } else { 54 | return this._host; 55 | } 56 | }; 57 | 58 | Address.prototype.port = function () { 59 | if (this._pointer) { 60 | return jsapi_.address_get_port(this._pointer); 61 | } else { 62 | return this._port; 63 | } 64 | }; 65 | 66 | Address.prototype.address = function () { 67 | if (this._pointer) return long2ip(this.host(), 'Address.prototype.address from pointer'); 68 | return long2ip(this.host(), 'Address.prototype.address from local'); 69 | }; 70 | -------------------------------------------------------------------------------- /lib/Event.js: -------------------------------------------------------------------------------- 1 | var ENETModule = require("../build/enet.js"); 2 | var enet = require("../index.js"); 3 | 4 | var jsapi_ = ENETModule.jsapi; 5 | 6 | module.exports.Event = Event; 7 | 8 | function Event() { 9 | this._pointer = jsapi_.event_new(); 10 | } 11 | 12 | Event.prototype.free = function () { 13 | jsapi_.event_free(this._pointer); 14 | }; 15 | 16 | Event.prototype.type = function () { 17 | return jsapi_.event_get_type(this._pointer); 18 | }; 19 | Event.prototype.peer = function () { 20 | var ptr = jsapi_.event_get_peer(this._pointer); 21 | return new enet.Peer(ptr); 22 | }; 23 | Event.prototype.peerPtr = function () { 24 | return jsapi_.event_get_peer(this._pointer); 25 | }; 26 | Event.prototype.packet = function () { 27 | var ptr = jsapi_.event_get_packet(this._pointer); 28 | return new enet.Packet(ptr); 29 | }; 30 | Event.prototype.data = function () { 31 | return jsapi_.event_get_data(this._pointer); 32 | }; 33 | Event.prototype.channelID = function () { 34 | return jsapi_.event_get_channelID(this._pointer); 35 | }; 36 | -------------------------------------------------------------------------------- /lib/Host.js: -------------------------------------------------------------------------------- 1 | var Buffer = require("buffer").Buffer; 2 | var events = require("events"); 3 | var util = require("util"); 4 | var ENETModule = require("../build/enet.js"); 5 | var enet = require("../index.js"); 6 | 7 | var jsapi_ = ENETModule.jsapi; 8 | var enet_ = ENETModule.libenet; 9 | 10 | var ENET_HOST_SERVICE_INTERVAL = 10; //milliseconds 11 | 12 | util.inherits(Host, events.EventEmitter); 13 | 14 | module.exports.Host = Host; 15 | module.exports.createServer = createServer; 16 | module.exports.createClient = createClient; 17 | module.exports.createServerFromSocket = createServerFromSocket; 18 | 19 | function createServer(arg, callback) { 20 | return createHost(arg, callback, "server"); 21 | } 22 | 23 | function createClient(arg, callback) { 24 | return createHost(arg, callback, "client"); 25 | } 26 | 27 | function createServerFromSocket(arg, callback) { 28 | return createHost(arg, callback, "custom"); 29 | } 30 | 31 | function createHost(arg, callback, host_type) { 32 | var host, socket; 33 | var opt = {}; 34 | 35 | if (typeof arg === "function") { 36 | callback = arg; 37 | } else { 38 | opt = arg || opt; 39 | } 40 | 41 | callback = callback || function () {}; 42 | 43 | try { 44 | host = new Host(opt.address, opt.peers, opt.channels, opt.down, opt.up, host_type, opt.socket); 45 | } catch (e) { 46 | if (typeof callback === 'function') callback(e); 47 | return undefined; 48 | } 49 | 50 | if (!host || host._pointer === 0) { 51 | setTimeout(function () { 52 | callback(new Error("host-creation-error")); 53 | }); 54 | return undefined; 55 | } 56 | 57 | socket = host._socket; 58 | 59 | if (!socket) { 60 | setTimeout(function () { 61 | callback(new Error("socket-creation-error")); 62 | }); 63 | return undefined; 64 | } 65 | 66 | //catch socket bind errors 67 | socket.on("error", function (e) { 68 | host._socket_closed = true; 69 | 70 | //server will bind so error will be called before listening if error occurs 71 | //so we can return the error in the callback 72 | if (host_type === "server") { 73 | callback(e); 74 | } else { 75 | //for client and custom host application can listen for the error event 76 | host.emit("error", e); 77 | } 78 | 79 | host.destroy(); 80 | }); 81 | 82 | socket.on("close", function () { 83 | host._socket_closed = true; 84 | host.destroy(); 85 | }); 86 | 87 | socket.on("listening", function () { 88 | socket.setBroadcast(true); 89 | //for server host callback when socket is listening 90 | if (host_type === "server" && typeof callback === 'function') callback(undefined, host); 91 | }); 92 | 93 | //bind the socket 94 | if (host_type === "server" || host_type === "custom") jsapi_.enet_host_bind(host._pointer); 95 | 96 | if ((host_type === "client" || host_type === "custom") && typeof callback === 'function') { 97 | setTimeout(function () { 98 | callback(undefined, host); //clients get host in callback before socket is listening. 99 | }); 100 | } 101 | 102 | return host; 103 | } 104 | 105 | function Host(address, maxpeers, maxchannels, bw_down, bw_up, host_type, custom_socket) { 106 | events.EventEmitter.call(this); 107 | this.setMaxListeners(0); 108 | this.connectedPeers = {}; 109 | var enetAddr; 110 | var self = this; 111 | var pointer = 0; 112 | var socketfd, stream; 113 | 114 | switch (host_type) { 115 | case "client": 116 | this._type = "client"; 117 | pointer = jsapi_.enet_host_create_client(maxpeers || 128, maxchannels || 5, bw_down || 0, bw_up || 118 | 0); 119 | break; 120 | 121 | case "custom": 122 | this._type = "custom"; 123 | //insert a socket into emscrtipten FS 124 | socketfd = ENETModule["createStreamFromSocket"](custom_socket); 125 | pointer = jsapi_.enet_host_from_socket(socketfd, 0, maxpeers || 128, maxchannels || 5, bw_down || 126 | 0, 127 | bw_up || 128 | 0); 129 | break; 130 | 131 | case "server": 132 | this._type = "server"; 133 | address = address || { 134 | address: "0.0.0.0", 135 | port: 0 136 | }; 137 | enetAddr = (address instanceof enet.Address) ? address : new enet.Address(address); 138 | pointer = jsapi_.enet_host_create_server(enetAddr.host(), enetAddr.port(), maxpeers || 128, 139 | maxchannels || 140 | 5, 141 | bw_down || 0, 142 | bw_up || 0); 143 | break; 144 | 145 | default: 146 | //create a host using the createClient and createServer methods. 147 | throw (new Error( 148 | "Do not create a new instance of enet.Host. Use enet.createServer() and enet.createClient() instead." 149 | )); 150 | } 151 | 152 | if (pointer === 0) { 153 | throw ('failed to create ENet host'); 154 | } 155 | 156 | self._event = new enet.Event(); //allocate memory for events - free it when we destroy the host 157 | self._pointer = pointer; 158 | socketfd = jsapi_.host_get_socket(self._pointer); 159 | self._socket = ENETModule["getStreamSocket"](socketfd); 160 | 161 | self._packet_free_func_ptr = ENETModule["Runtime_addFunction"](function (packet_ptr) { 162 | //grab the callback from peer._packet_callback_functions, call its callback indicate if sent flag 163 | //delete from peer._packet_callback_functions 164 | var packet, callback; 165 | Object.keys(self._packet_callback_functions).forEach(function (ptr) { 166 | //keys are strings 167 | if (Number(ptr) === packet_ptr) { 168 | packet = new enet.Packet(packet_ptr); 169 | callback = self._packet_callback_functions[ptr]; 170 | delete self._packet_callback_functions[ptr]; 171 | callback(packet.wasSent() ? undefined : "packet-not-delivered"); 172 | return; 173 | } 174 | }); 175 | }); 176 | 177 | self._packet_callback_functions = {}; //packet pointers and their free callback function 178 | } 179 | 180 | Host.prototype._addPacketCallback = function (packet, callback) { 181 | packet._attachFreeCallback(this._packet_free_func_ptr); 182 | this._packet_callback_functions[packet._pointer] = callback; 183 | }; 184 | 185 | Host.prototype.isOffline = function () { 186 | return (typeof this._pointer === "undefined" || this._pointer === 0 || this._shutting_down || this._socket_closed); 187 | }; 188 | 189 | Host.prototype.isOnline = function () { 190 | return (this.isOffline() === false); 191 | }; 192 | 193 | Host.prototype._service = function () { 194 | var self = this; 195 | var peer; 196 | var recvdAddr; 197 | if (self._servicing) return; 198 | self._servicing = true; 199 | 200 | if (!self._pointer || !self._event || self._socket_closed) return; 201 | var err = enet_.host_service(self._pointer, self._event._pointer, 0); 202 | while (err > 0) { 203 | 204 | switch (self._event.type()) { 205 | case 1: //connect 206 | peer = self.connectedPeers[self._event.peerPtr()]; 207 | if (peer) { 208 | //outgoing connection 209 | peer.emit("connect"); 210 | self.emit("connect", 211 | peer, 212 | undefined, 213 | true //local host initiated the connection to foriegn host 214 | ); 215 | } else { 216 | peer = self.connectedPeers[self._event.peerPtr()] = self._event.peer(); 217 | peer._host = self; 218 | //incoming connection 219 | self.emit("connect", 220 | peer, 221 | self._event.data(), 222 | false //foreign host initiated connection to local host 223 | ); 224 | } 225 | break; 226 | case 2: //disconnect 227 | peer = self.connectedPeers[self._event.peerPtr()]; 228 | if (peer) { 229 | peer._delete(true, self._event.data()); 230 | } 231 | break; 232 | case 3: //receive 233 | peer = self.connectedPeers[self._event.peerPtr()] || self._event.peer(); 234 | self.emit("message", 235 | peer, 236 | self._event.packet(), 237 | self._event.channelID() 238 | ); 239 | //todo - return packet.data() not packet (incase app wants to handle the packet asynchronously) 240 | peer.emit("message", self._event.packet(), self._event.channelID()); 241 | self._event.packet().destroy(); 242 | break; 243 | case 100: //JSON,telex 244 | recvdAddr = self.receivedAddress(); 245 | self.emit("telex", 246 | self._event.packet().data(), { 247 | 'address': recvdAddr.address, 248 | 'port': recvdAddr.port 249 | } 250 | ); 251 | self._event.packet().destroy(); 252 | break; 253 | } 254 | if (!self._pointer || !self._event || self._socket_closed) return; 255 | 256 | err = enet_.host_service(self._pointer, self._event._pointer, 0); 257 | } 258 | if (err < 0) console.error("Error servicing host: ", err); 259 | self._servicing = false; 260 | }; 261 | 262 | Host.prototype.destroy = function () { 263 | var self = this; 264 | var peer, peer_ptr; 265 | if (self._shutting_down) return; 266 | self._shutting_down = true; 267 | 268 | if (self._io_loop) { 269 | clearInterval(self._io_loop); 270 | } 271 | 272 | if (typeof self._pointer === 'undefined' || self._pointer === 0) return; 273 | 274 | for (peer_ptr in self.connectedPeers) { 275 | peer = self.connectedPeers[peer_ptr]; 276 | if (peer && peer._pointer !== 0) { 277 | if (!self._socket_closed) enet_.peer_disconnect_now(peer_ptr, 0); 278 | peer._pointer = 0; 279 | peer.emit("disconnect", 0); 280 | } 281 | } 282 | delete self.connectedPeers; 283 | self.flush(); 284 | 285 | if (self._event) self._event.free(); 286 | 287 | try { 288 | if (self._pointer) enet_.host_destroy(self._pointer); 289 | } catch (e) {} 290 | 291 | if (self._packet_free_func_ptr) ENETModule["Runtime_removeFunction"](self._packet_free_func_ptr); 292 | delete self._packet_callback_functions; 293 | 294 | delete self._pointer; 295 | delete self._event; 296 | delete self._io_loop; 297 | delete self._socket; 298 | self.emit("destroy"); 299 | }; 300 | 301 | Host.prototype.stop = Host.prototype.destroy; 302 | 303 | Host.prototype.receivedAddress = function () { 304 | if (this.isOffline()) return; 305 | var ptr = jsapi_.host_get_receivedAddress(this._pointer); 306 | var addr = new enet.Address(ptr); 307 | return ({ 308 | address: addr.address(), 309 | port: addr.port() 310 | }); 311 | }; 312 | 313 | Host.prototype.address = function () { 314 | if (this.isOffline()) return; 315 | return this._socket.address(); 316 | }; 317 | 318 | Host.prototype.send = function (ip, port, buff, callback) { 319 | if (this.isOffline()) return; 320 | this._socket.send(buff, 0, buff.length, port, ip, callback); 321 | }; 322 | 323 | Host.prototype.flush = function () { 324 | if (this.isOffline()) return; 325 | enet_.host_flush(this._pointer); 326 | }; 327 | 328 | Host.prototype.connect = function (address, channelCount, data, callback) { 329 | if (this.isOffline()) { 330 | if (typeof callback === 'function') callback(new Error("host-destroyed")); 331 | return; 332 | } 333 | 334 | var self = this; 335 | var peer; 336 | var enetAddr = (address instanceof enet.Address) ? address : new enet.Address(address); 337 | var ptr = jsapi_.enet_host_connect(this._pointer, enetAddr.host(), enetAddr.port(), channelCount || 5, 338 | data || 339 | 0); 340 | 341 | self.firstStart(); //start servicing if not yet started 342 | 343 | var succeeded = false; 344 | 345 | if (ptr) { 346 | peer = new enet.Peer(ptr); 347 | peer._host = self; 348 | self.connectedPeers[ptr] = peer; 349 | if (typeof callback === 'function') { 350 | peer.on("connect", function () { 351 | succeeded = true; 352 | callback(undefined, peer); 353 | }); 354 | peer.on("disconnect", function () { 355 | if (!succeeded) callback(new Error("failed")); 356 | }); 357 | } 358 | return peer; 359 | } 360 | 361 | if (typeof callback === 'function') { 362 | setTimeout(function () { 363 | callback(new Error("maxpeers")); 364 | }); 365 | } 366 | 367 | return undefined; 368 | }; 369 | 370 | Host.prototype.throttleBandwidth = function () { 371 | if (this.isOffline()) return; 372 | enet_.host_bandwidth_throttle(this._pointer); 373 | return this; 374 | }; 375 | 376 | Host.prototype.enableCompression = function () { 377 | if (this._pointer) { 378 | enet_.host_compress_with_range_coder(this._pointer); 379 | } 380 | return this; 381 | }; 382 | 383 | Host.prototype.disableCompression = function () { 384 | if (this._pointer) { 385 | enet_.host_compress(this._pointer, 0); //passing a 0 disables compression 386 | } 387 | return this; 388 | }; 389 | 390 | Host.prototype.broadcast = function (channel, packet) { 391 | if (this.isOffline()) return; 392 | 393 | if (packet instanceof Buffer) packet = new enet.Packet(packet, enet.PACKET_FLAG.RELIABLE); 394 | 395 | enet_.host_broadcast(this._pointer, channel, packet._pointer); 396 | }; 397 | 398 | Host.prototype.peers = function () { 399 | var peer_ptr, peers = []; 400 | for (peer_ptr in this.connectedPeers) { 401 | peers.push(this.connectedPeers[peer_ptr]); 402 | } 403 | return peers; 404 | }; 405 | 406 | Host.prototype.firstStart = function () { 407 | var self = this; 408 | if (!self._io_loop) { 409 | self._io_loop = setInterval(function () { 410 | self._service(); 411 | }, ENET_HOST_SERVICE_INTERVAL); 412 | } 413 | }; 414 | 415 | Host.prototype.start = function (ms_interval) { 416 | var self = this; 417 | if (!self._pointer) return; //cannot start a host that is not initialised 418 | if (self._io_loop) { 419 | clearInterval(self._io_loop); 420 | } 421 | self._io_loop = setInterval(function () { 422 | self._service(); 423 | }, ms_interval || ENET_HOST_SERVICE_INTERVAL); 424 | }; 425 | -------------------------------------------------------------------------------- /lib/PACKET_FLAG.js: -------------------------------------------------------------------------------- 1 | module.exports.PACKET_FLAG = { 2 | RELIABLE: 1, 3 | UNSEQUENCED: 1 << 1, 4 | UNRELIABLE_FRAGMENT: 1 << 3, 5 | SENT: (1 << 8) 6 | }; 7 | -------------------------------------------------------------------------------- /lib/PEER_STATE.js: -------------------------------------------------------------------------------- 1 | module.exports.PEER_STATE = { 2 | DISCONNECTED: 0, 3 | CONNECTING: 1, 4 | ACKNOWLEDGING_CONNECT: 2, 5 | CONNECTION_PENDING: 3, 6 | CONNECTION_SUCCEEDED: 4, 7 | CONNECTED: 5, 8 | DISCONNECT_LATER: 6, 9 | DISCONNECTING: 7, 10 | ACKNOWLEDGING_DISCONNECT: 8, 11 | ZOMBIE: 9 12 | }; 13 | -------------------------------------------------------------------------------- /lib/Packet.js: -------------------------------------------------------------------------------- 1 | var Buffer = require("buffer").Buffer; 2 | var ENETModule = require("../build/enet.js"); 3 | var enet = require("../index.js"); 4 | 5 | var jsapi_ = ENETModule.jsapi; 6 | var enet_ = ENETModule.libenet; 7 | 8 | module.exports.Packet = Packet; 9 | 10 | function Packet() { 11 | var packet = this; 12 | 13 | var buf, flags; 14 | 15 | //packet from pointer 16 | if (arguments.length === 1 && typeof arguments[0] === 'number') { 17 | packet._pointer = arguments[0]; 18 | return packet; 19 | } 20 | 21 | //packet from buffer 22 | if (arguments.length > 0 && typeof arguments[0] === 'object') { 23 | //construct a new packet from node buffer 24 | buf = arguments[0]; 25 | 26 | if (typeof arguments[1] === 'number') { 27 | flags = arguments[1]; 28 | } 29 | 30 | flags = flags || 0; //defaults to unreliable packet 31 | 32 | packet._packetFromBuffer(buf, flags); 33 | 34 | return packet; 35 | } 36 | 37 | //packet from string 38 | if (arguments.length > 0 && typeof arguments[0] == 'string') { 39 | return new Packet(new Buffer(arguments[0]), arguments[1]); 40 | } 41 | } 42 | 43 | Packet.prototype._packetFromBuffer = function (buf, flags) { 44 | var packet = this, 45 | begin, end, c, i; 46 | packet._pointer = enet_.packet_create(0, buf.length, flags); 47 | if (!packet._pointer) return; //no memory allocated for packet 48 | begin = jsapi_.packet_get_data(packet._pointer); 49 | end = begin + buf.length; 50 | c = 0; 51 | i = begin; 52 | for (; i < end; i++, c++) { 53 | ENETModule["HEAPU8"][i] = buf.readUInt8(c); 54 | } 55 | }; 56 | 57 | Packet.prototype._attachFreeCallback = function (free_ptr) { 58 | jsapi_.packet_set_free_callback(this._pointer, free_ptr); 59 | }; 60 | 61 | Packet.prototype.flags = function () { 62 | if (!this._pointer) return 0; 63 | return jsapi_.packet_flags(this._pointer); 64 | }; 65 | 66 | Packet.prototype.wasSent = function () { 67 | return ((this.flags() & enet.PACKET_FLAG.SENT) == enet.PACKET_FLAG.SENT); 68 | }; 69 | 70 | Packet.prototype.data = function () { 71 | var begin, end; 72 | if (!this._pointer) return undefined; 73 | begin = jsapi_.packet_get_data(this._pointer); 74 | end = begin + jsapi_.packet_get_dataLength(this._pointer); 75 | return new Buffer(ENETModule["HEAPU8"].subarray(begin, end), "byte"); 76 | //return HEAPU8.subarray(begin,end); 77 | }; 78 | 79 | Packet.prototype.dataLength = function () { 80 | if (!this._pointer) return 0; 81 | return jsapi_.packet_get_dataLength(this._pointer); 82 | }; 83 | 84 | Packet.prototype.destroy = function () { 85 | if (!this._pointer) return; 86 | enet_.packet_destroy(this._pointer); 87 | this._pointer = 0; 88 | }; 89 | -------------------------------------------------------------------------------- /lib/Peer.js: -------------------------------------------------------------------------------- 1 | var Buffer = require("buffer").Buffer; 2 | var events = require("events"); 3 | var util = require("util"); 4 | var Stream = require("stream"); 5 | var ENETModule = require("../build/enet.js"); 6 | var enet = require("../index.js"); 7 | 8 | var jsapi_ = ENETModule.jsapi; 9 | var enet_ = ENETModule.libenet; 10 | 11 | util.inherits(Peer, events.EventEmitter); 12 | 13 | module.exports.Peer = Peer; 14 | 15 | function Peer(pointer) { 16 | var peer = this; 17 | if (!pointer || !(typeof pointer === 'number') || pointer === 0) throw ("Peer null pointer"); 18 | peer._pointer = pointer; 19 | events.EventEmitter.call(peer); 20 | peer.setMaxListeners(0); 21 | } 22 | 23 | Peer.prototype.state = function () { 24 | if (this._pointer) { 25 | return jsapi_.peer_get_state(this._pointer); 26 | } 27 | return enet.PEER_STATE.DISCONNECTED; 28 | }; 29 | 30 | Peer.prototype.incomingDataTotal = function () { 31 | if (this._pointer) { 32 | return jsapi_.peer_get_incomingDataTotal(this._pointer); 33 | } 34 | return 0; 35 | }; 36 | 37 | Peer.prototype.outgoingDataTotal = function () { 38 | if (this._pointer) { 39 | return jsapi_.peer_get_outgoingDataTotal(this._pointer); 40 | } 41 | return 0; 42 | }; 43 | 44 | Peer.prototype.reliableDataInTransit = function () { 45 | if (!this._pointer) return 0; 46 | return jsapi._peer_get_reliableDataInTransit(this._pointer); 47 | }; 48 | 49 | Peer.prototype.send = function (channel, packet, callback) { 50 | var peer = this; 51 | if (peer._host.isOffline()) { 52 | if (typeof callback === 'function') callback(new Error("host-destroyed")); 53 | return true; 54 | } 55 | 56 | if (!peer._pointer) { 57 | if (typeof callback === 'function') callback(new Error("Peer is disconnected")); 58 | return true; 59 | } 60 | 61 | if (!(packet instanceof enet.Packet)) packet = new enet.Packet(packet, enet.PACKET_FLAG.RELIABLE); 62 | 63 | if (!packet._pointer || packet._pointer == 0) { 64 | if (typeof callback === 'function') callback(new Error("null packet")); 65 | return true; 66 | } 67 | 68 | if (typeof callback === 'function') { 69 | peer._host._addPacketCallback(packet, callback); 70 | } 71 | 72 | if (enet_.peer_send(peer._pointer, channel, packet._pointer) !== 0) { 73 | if (typeof callback === 'function') callback(new Error('Packet not queued')); 74 | return true; //packet not queued - error 75 | } 76 | 77 | return false; //packed queued - no error 78 | }; 79 | 80 | Peer.prototype._delete = function (emitDisconnect, disconnectData) { 81 | var peer = this; 82 | if (!peer._pointer) return; 83 | if (peer._host) delete peer._host.connectedPeers[peer._pointer]; 84 | peer._pointer = 0; 85 | if (emitDisconnect) peer.emit("disconnect", disconnectData); 86 | }; 87 | 88 | Peer.prototype.reset = function () { 89 | var peer = this; 90 | if (peer._pointer) { 91 | enet_.peer_reset(this._pointer); 92 | peer._delete(false); 93 | } 94 | return peer; 95 | }; 96 | 97 | Peer.prototype.ping = function () { 98 | var peer = this; 99 | if (peer._pointer) enet_.peer_ping(peer._pointer); 100 | return peer; 101 | }; 102 | 103 | Peer.prototype.disconnect = function (data) { 104 | var peer = this; 105 | if (peer._pointer) { 106 | enet_.peer_disconnect(peer._pointer, data || 0); 107 | } 108 | return peer; 109 | }; 110 | 111 | Peer.prototype.disconnectNow = function (data) { 112 | var peer = this; 113 | if (peer._pointer) { 114 | enet_.peer_disconnect_now(peer._pointer, data || 0); 115 | peer._delete(true); 116 | } 117 | return peer; 118 | }; 119 | 120 | Peer.prototype.disconnectLater = function (data) { 121 | var peer = this; 122 | if (peer._pointer) { 123 | enet_.peer_disconnect_later(peer._pointer, data || 0); 124 | } 125 | return peer; 126 | }; 127 | 128 | Peer.prototype.address = function () { 129 | var peer = this; 130 | if (!peer._pointer) { 131 | if (peer._address) return peer._address; 132 | return; 133 | } 134 | var ptr = jsapi_.peer_get_address(peer._pointer); 135 | var addr = new enet.Address(ptr); 136 | //save the address so we can check it after disconnect 137 | peer._address = { 138 | address: addr.address(), 139 | port: addr.port() 140 | }; 141 | return peer._address; 142 | }; 143 | 144 | //turn a channel with peer into a node writeable Stream 145 | //ref: https://github.com/substack/stream-handbook 146 | 147 | //todo - for stream, some additional error checking - make sure channel is a number 148 | //and not larger than the number of channels supported by peer. Dont allow creating 149 | //allow more than one write/readable stream for same channel? 150 | 151 | Peer.prototype.createWriteStream = function (channel) { 152 | var peer = this; 153 | if (!peer._pointer) return; 154 | 155 | var connected = (peer.state() === enet.PEER_STATE.CONNECTED); 156 | var error = false; 157 | 158 | var s = new Stream.Writable(); 159 | 160 | peer.on("connect", function () { 161 | connected = true; 162 | }); 163 | 164 | peer.on("disconnect", function (data) { 165 | connected = false; 166 | }); 167 | 168 | s._write = function (buf, enc, next) { 169 | if (!connected) { 170 | next("peer-not-connected"); 171 | return; 172 | } 173 | 174 | if (error) { 175 | next("packet-queuing-error"); 176 | return; 177 | } 178 | 179 | var packet = new enet.Packet(buf, enet.PACKET_FLAG.RELIABLE); 180 | 181 | error = peer.send(channel, packet); 182 | 183 | if (error) { 184 | next("packet-queuing-error"); 185 | return; 186 | } 187 | 188 | next(); 189 | }; 190 | 191 | return s; 192 | }; 193 | 194 | Peer.prototype.createReadStream = function (channel) { 195 | var peer = this; 196 | if (!peer._pointer) return; 197 | 198 | var s = new Stream.Readable(); 199 | 200 | var connected = (peer.state() === enet.PEER_STATE.CONNECTED); 201 | 202 | peer.on("connect", function () { 203 | connected = true; 204 | }); 205 | 206 | peer.on("disconnect", function (data) { 207 | connected = false; 208 | s.push(null); //signals end of data 209 | }); 210 | 211 | peer.on("message", function (_packet, _channel) { 212 | if (channel === _channel) { 213 | s.push(_packet.data()); 214 | } 215 | }); 216 | 217 | s._read = function (size) { 218 | if (!connected) s.push(null); 219 | }; 220 | 221 | return s; 222 | 223 | }; 224 | 225 | Peer.prototype.createDuplexStream = function (channel) { 226 | var peer = this; 227 | if (!peer._pointer) return; 228 | 229 | var s = new Stream.Duplex(); 230 | var error = false; 231 | 232 | var connected = (peer.state() === enet.PEER_STATE.CONNECTED); 233 | 234 | peer.on("connect", function () { 235 | connected = true; 236 | }); 237 | 238 | peer.on("disconnect", function (data) { 239 | connected = false; 240 | s.push(null); //signals end of data 241 | }); 242 | 243 | s._write = function (buf, enc, next) { 244 | if (!connected) { 245 | next("peer-not-connected"); 246 | return; 247 | } 248 | 249 | if (error) { 250 | next("packet-queuing-error"); 251 | return; 252 | } 253 | 254 | var packet = new enet.Packet(buf, enet.PACKET_FLAG.RELIABLE); 255 | 256 | error = peer.send(channel, packet); 257 | 258 | if (error) { 259 | next("packet-queuing-error"); 260 | return; 261 | } 262 | 263 | next(); 264 | }; 265 | 266 | peer.on("message", function (_packet, _channel) { 267 | if (channel === _channel) { 268 | s.push(_packet.data()); 269 | } 270 | }); 271 | 272 | s._read = function (size) { 273 | if (!connected) s.push(null); 274 | }; 275 | 276 | return s; 277 | }; 278 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enet", 3 | "version": "v0.2.9", 4 | "main": "index.js", 5 | "description": "The ENet Networking Library cross compiled to javascript", 6 | "keywords": [ 7 | "enet", 8 | "protocol", 9 | "udp", 10 | "network" 11 | ], 12 | "homepage": "https://github.com/mnaamani/enet-npm", 13 | "author": { 14 | "name": "Mokhtar Naamani", 15 | "email": "mokhtar.naamani@gmail.com", 16 | "url": "https://github.com/mnaamani" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git@github.com:mnaamani/enet-npm.git" 21 | }, 22 | "license": "MIT", 23 | "devDependencies": { 24 | "throttle": "^1.0.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/enet/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, NULL }; 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 | if (inits -> packet_filter != NULL) 29 | callbacks.packet_filter = inits -> packet_filter; 30 | 31 | return enet_initialize (); 32 | } 33 | 34 | void * 35 | enet_malloc (size_t size) 36 | { 37 | void * memory = callbacks.malloc (size); 38 | 39 | if (memory == NULL) 40 | callbacks.no_memory (); 41 | 42 | return memory; 43 | } 44 | 45 | void 46 | enet_free (void * memory) 47 | { 48 | callbacks.free (memory); 49 | } 50 | 51 | /* 52 | return value 0 means drop the packet. 53 | any other value means continue processing the packet. 54 | */ 55 | int 56 | enet_packet_filter (ENetHost *host){ 57 | if(host->receivedDataLength <= 0) return 1;//can't process a 0 or -ve length packet! 58 | 59 | if(callbacks.packet_filter != NULL){ 60 | //packet filter can modify buffer - (better to pass a copy?) 61 | return callbacks.packet_filter(host); 62 | } 63 | //no packet filter is defined - continue processing 64 | return 1; 65 | } 66 | -------------------------------------------------------------------------------- /src/enet/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 | -------------------------------------------------------------------------------- /src/enet/host.c: -------------------------------------------------------------------------------- 1 | /** 2 | @file host.c 3 | @brief ENet host management functions 4 | */ 5 | #define ENET_BUILDING_LIB 1 6 | #define __MINGW_USE_VC2005_COMPAT 1 7 | #include 8 | #include 9 | #include "enet/enet.h" 10 | 11 | /** @defgroup host ENet host functions 12 | @{ 13 | */ 14 | 15 | /** Creates a host for communicating to peers. 16 | 17 | @param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host. 18 | @param peerCount the maximum number of peers that should be allocated for the host. 19 | @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT 20 | @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. 21 | @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. 22 | 23 | @returns the host on success and NULL on failure 24 | 25 | @remarks ENet will strategically drop packets on specific sides of a connection between hosts 26 | to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine 27 | the window size of a connection which limits the amount of reliable packets that may be in transit 28 | at any given time. 29 | */ 30 | ENetHost * 31 | enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) 32 | { 33 | ENetHost * host; 34 | ENetPeer * currentPeer; 35 | 36 | if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) 37 | return NULL; 38 | 39 | host = (ENetHost *) enet_malloc (sizeof (ENetHost)); 40 | if (host == NULL) 41 | return NULL; 42 | memset (host, 0, sizeof (ENetHost)); 43 | 44 | host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer)); 45 | if (host -> peers == NULL) 46 | { 47 | enet_free (host); 48 | 49 | return NULL; 50 | } 51 | memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); 52 | 53 | host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); 54 | if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0)) 55 | { 56 | if (host -> socket != ENET_SOCKET_NULL) 57 | enet_socket_destroy (host -> socket); 58 | 59 | enet_free (host -> peers); 60 | enet_free (host); 61 | 62 | return NULL; 63 | } 64 | 65 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1); 66 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1); 67 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); 68 | enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); 69 | 70 | if (address != NULL) 71 | host -> address = * address; 72 | 73 | if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) 74 | channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; 75 | else 76 | if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) 77 | channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; 78 | 79 | host -> randomSeed = (enet_uint32) time(NULL) + (enet_uint32) (size_t) host; 80 | host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16); 81 | host -> channelLimit = channelLimit; 82 | host -> incomingBandwidth = incomingBandwidth; 83 | host -> outgoingBandwidth = outgoingBandwidth; 84 | host -> bandwidthThrottleEpoch = 0; 85 | host -> recalculateBandwidthLimits = 0; 86 | host -> mtu = ENET_HOST_DEFAULT_MTU; 87 | host -> peerCount = peerCount; 88 | host -> commandCount = 0; 89 | host -> bufferCount = 0; 90 | host -> checksum = NULL; 91 | host -> receivedAddress.host = ENET_HOST_ANY; 92 | host -> receivedAddress.port = 0; 93 | host -> receivedData = NULL; 94 | host -> receivedDataLength = 0; 95 | 96 | host -> totalSentData = 0; 97 | host -> totalSentPackets = 0; 98 | host -> totalReceivedData = 0; 99 | host -> totalReceivedPackets = 0; 100 | 101 | host -> compressor.context = NULL; 102 | host -> compressor.compress = NULL; 103 | host -> compressor.decompress = NULL; 104 | host -> compressor.destroy = NULL; 105 | host -> isClient = 0; 106 | 107 | enet_list_clear (& host -> dispatchQueue); 108 | 109 | for (currentPeer = host -> peers; 110 | currentPeer < & host -> peers [host -> peerCount]; 111 | ++ currentPeer) 112 | { 113 | currentPeer -> host = host; 114 | currentPeer -> incomingPeerID = currentPeer - host -> peers; 115 | currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF; 116 | currentPeer -> data = NULL; 117 | 118 | enet_list_clear (& currentPeer -> acknowledgements); 119 | enet_list_clear (& currentPeer -> sentReliableCommands); 120 | enet_list_clear (& currentPeer -> sentUnreliableCommands); 121 | enet_list_clear (& currentPeer -> outgoingReliableCommands); 122 | enet_list_clear (& currentPeer -> outgoingUnreliableCommands); 123 | enet_list_clear (& currentPeer -> dispatchedCommands); 124 | 125 | enet_peer_reset (currentPeer); 126 | } 127 | 128 | return host; 129 | } 130 | 131 | /** Destroys the host and all resources associated with it. 132 | @param host pointer to the host to destroy 133 | */ 134 | void 135 | enet_host_destroy (ENetHost * host) 136 | { 137 | ENetPeer * currentPeer; 138 | 139 | if (host == NULL) 140 | return; 141 | 142 | enet_socket_destroy (host -> socket); 143 | 144 | for (currentPeer = host -> peers; 145 | currentPeer < & host -> peers [host -> peerCount]; 146 | ++ currentPeer) 147 | { 148 | enet_peer_reset (currentPeer); 149 | } 150 | 151 | if (host -> compressor.context != NULL && host -> compressor.destroy) 152 | (* host -> compressor.destroy) (host -> compressor.context); 153 | 154 | enet_free (host -> peers); 155 | enet_free (host); 156 | } 157 | 158 | /** Initiates a connection to a foreign host. 159 | @param host host seeking the connection 160 | @param address destination for the connection 161 | @param channelCount number of channels to allocate 162 | @param data user data supplied to the receiving host 163 | @returns a peer representing the foreign host on success, NULL on failure 164 | @remarks The peer returned will have not completed the connection until enet_host_service() 165 | notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. 166 | */ 167 | ENetPeer * 168 | enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data) 169 | { 170 | ENetPeer * currentPeer; 171 | ENetChannel * channel; 172 | ENetProtocol command; 173 | 174 | if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) 175 | channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; 176 | else 177 | if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) 178 | channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; 179 | 180 | for (currentPeer = host -> peers; 181 | currentPeer < & host -> peers [host -> peerCount]; 182 | ++ currentPeer) 183 | { 184 | if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) 185 | break; 186 | } 187 | 188 | if (currentPeer >= & host -> peers [host -> peerCount]) 189 | return NULL; 190 | 191 | currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); 192 | if (currentPeer -> channels == NULL) 193 | return NULL; 194 | currentPeer -> channelCount = channelCount; 195 | currentPeer -> state = ENET_PEER_STATE_CONNECTING; 196 | currentPeer -> address = * address; 197 | currentPeer -> connectID = ++ host -> randomSeed; 198 | 199 | if (host -> outgoingBandwidth == 0) 200 | currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; 201 | else 202 | currentPeer -> windowSize = (host -> outgoingBandwidth / 203 | ENET_PEER_WINDOW_SIZE_SCALE) * 204 | ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; 205 | 206 | if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) 207 | currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; 208 | else 209 | if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) 210 | currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; 211 | 212 | for (channel = currentPeer -> channels; 213 | channel < & currentPeer -> channels [channelCount]; 214 | ++ channel) 215 | { 216 | channel -> outgoingReliableSequenceNumber = 0; 217 | channel -> outgoingUnreliableSequenceNumber = 0; 218 | channel -> incomingReliableSequenceNumber = 0; 219 | channel -> incomingUnreliableSequenceNumber = 0; 220 | 221 | enet_list_clear (& channel -> incomingReliableCommands); 222 | enet_list_clear (& channel -> incomingUnreliableCommands); 223 | 224 | channel -> usedReliableWindows = 0; 225 | memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); 226 | } 227 | 228 | command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; 229 | command.header.channelID = 0xFF; 230 | command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); 231 | command.connect.incomingSessionID = currentPeer -> incomingSessionID; 232 | command.connect.outgoingSessionID = currentPeer -> outgoingSessionID; 233 | command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu); 234 | command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize); 235 | command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount); 236 | command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth); 237 | command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); 238 | command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval); 239 | command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); 240 | command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); 241 | command.connect.connectID = currentPeer -> connectID; 242 | command.connect.data = ENET_HOST_TO_NET_32 (data); 243 | 244 | enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0); 245 | 246 | return currentPeer; 247 | } 248 | 249 | /** Queues a packet to be sent to all peers associated with the host. 250 | @param host host on which to broadcast the packet 251 | @param channelID channel on which to broadcast 252 | @param packet packet to broadcast 253 | */ 254 | void 255 | enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet) 256 | { 257 | ENetPeer * currentPeer; 258 | 259 | for (currentPeer = host -> peers; 260 | currentPeer < & host -> peers [host -> peerCount]; 261 | ++ currentPeer) 262 | { 263 | if (currentPeer -> state != ENET_PEER_STATE_CONNECTED) 264 | continue; 265 | 266 | enet_peer_send (currentPeer, channelID, packet); 267 | } 268 | 269 | if (packet -> referenceCount == 0) 270 | enet_packet_destroy (packet); 271 | } 272 | 273 | /** Sets the packet compressor the host should use to compress and decompress packets. 274 | @param host host to enable or disable compression for 275 | @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled 276 | */ 277 | void 278 | enet_host_compress (ENetHost * host, const ENetCompressor * compressor) 279 | { 280 | if (host -> compressor.context != NULL && host -> compressor.destroy) 281 | (* host -> compressor.destroy) (host -> compressor.context); 282 | 283 | if (compressor) 284 | host -> compressor = * compressor; 285 | else 286 | host -> compressor.context = NULL; 287 | } 288 | 289 | /** Limits the maximum allowed channels of future incoming connections. 290 | @param host host to limit 291 | @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT 292 | */ 293 | void 294 | enet_host_channel_limit (ENetHost * host, size_t channelLimit) 295 | { 296 | if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) 297 | channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; 298 | else 299 | if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) 300 | channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; 301 | 302 | host -> channelLimit = channelLimit; 303 | } 304 | 305 | 306 | /** Adjusts the bandwidth limits of a host. 307 | @param host host to adjust 308 | @param incomingBandwidth new incoming bandwidth 309 | @param outgoingBandwidth new outgoing bandwidth 310 | @remarks the incoming and outgoing bandwidth parameters are identical in function to those 311 | specified in enet_host_create(). 312 | */ 313 | void 314 | enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) 315 | { 316 | host -> incomingBandwidth = incomingBandwidth; 317 | host -> outgoingBandwidth = outgoingBandwidth; 318 | host -> recalculateBandwidthLimits = 1; 319 | } 320 | 321 | void 322 | enet_host_bandwidth_throttle (ENetHost * host) 323 | { 324 | enet_uint32 timeCurrent = enet_time_get (), 325 | elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch, 326 | peersTotal = 0, 327 | dataTotal = 0, 328 | peersRemaining, 329 | bandwidth, 330 | throttle = 0, 331 | bandwidthLimit = 0; 332 | int needsAdjustment = 0; 333 | ENetPeer * peer; 334 | ENetProtocol command; 335 | 336 | if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) 337 | return; 338 | 339 | host -> bandwidthThrottleEpoch = timeCurrent; 340 | 341 | for (peer = host -> peers; 342 | peer < & host -> peers [host -> peerCount]; 343 | ++ peer) 344 | { 345 | if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) 346 | continue; 347 | 348 | if (peer -> incomingBandwidth != 0) 349 | needsAdjustment = 1; 350 | 351 | ++ peersTotal; 352 | dataTotal += peer -> outgoingDataTotal; 353 | } 354 | 355 | if (peersTotal == 0) 356 | return; 357 | 358 | peersRemaining = peersTotal; 359 | 360 | if (host -> outgoingBandwidth == 0) 361 | bandwidth = ~0; 362 | else 363 | bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000; 364 | 365 | while (peersRemaining > 0 && needsAdjustment != 0) 366 | { 367 | needsAdjustment = 0; 368 | 369 | if (dataTotal < bandwidth) 370 | throttle = ENET_PEER_PACKET_THROTTLE_SCALE; 371 | else 372 | throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; 373 | 374 | for (peer = host -> peers; 375 | peer < & host -> peers [host -> peerCount]; 376 | ++ peer) 377 | { 378 | enet_uint32 peerBandwidth; 379 | 380 | if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || 381 | peer -> incomingBandwidth == 0 || 382 | peer -> outgoingBandwidthThrottleEpoch == timeCurrent) 383 | continue; 384 | 385 | peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000; 386 | if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) 387 | continue; 388 | 389 | peer -> packetThrottleLimit = (peerBandwidth * 390 | ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal; 391 | 392 | if (peer -> packetThrottleLimit == 0) 393 | peer -> packetThrottleLimit = 1; 394 | 395 | if (peer -> packetThrottle > peer -> packetThrottleLimit) 396 | peer -> packetThrottle = peer -> packetThrottleLimit; 397 | 398 | peer -> outgoingBandwidthThrottleEpoch = timeCurrent; 399 | 400 | peer -> incomingDataTotal = 0; 401 | peer -> outgoingDataTotal = 0; 402 | 403 | needsAdjustment = 1; 404 | -- peersRemaining; 405 | bandwidth -= peerBandwidth; 406 | dataTotal -= peerBandwidth; 407 | } 408 | } 409 | 410 | if (peersRemaining > 0) 411 | { 412 | if (dataTotal < bandwidth) 413 | throttle = ENET_PEER_PACKET_THROTTLE_SCALE; 414 | else 415 | throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; 416 | 417 | for (peer = host -> peers; 418 | peer < & host -> peers [host -> peerCount]; 419 | ++ peer) 420 | { 421 | if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || 422 | peer -> outgoingBandwidthThrottleEpoch == timeCurrent) 423 | continue; 424 | 425 | peer -> packetThrottleLimit = throttle; 426 | 427 | if (peer -> packetThrottle > peer -> packetThrottleLimit) 428 | peer -> packetThrottle = peer -> packetThrottleLimit; 429 | 430 | peer -> incomingDataTotal = 0; 431 | peer -> outgoingDataTotal = 0; 432 | } 433 | } 434 | 435 | if (host -> recalculateBandwidthLimits) 436 | { 437 | host -> recalculateBandwidthLimits = 0; 438 | 439 | peersRemaining = peersTotal; 440 | bandwidth = host -> incomingBandwidth; 441 | needsAdjustment = 1; 442 | 443 | if (bandwidth == 0) 444 | bandwidthLimit = 0; 445 | else 446 | while (peersRemaining > 0 && needsAdjustment != 0) 447 | { 448 | needsAdjustment = 0; 449 | bandwidthLimit = bandwidth / peersRemaining; 450 | 451 | for (peer = host -> peers; 452 | peer < & host -> peers [host -> peerCount]; 453 | ++ peer) 454 | { 455 | if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || 456 | peer -> incomingBandwidthThrottleEpoch == timeCurrent) 457 | continue; 458 | 459 | if (peer -> outgoingBandwidth > 0 && 460 | peer -> outgoingBandwidth >= bandwidthLimit) 461 | continue; 462 | 463 | peer -> incomingBandwidthThrottleEpoch = timeCurrent; 464 | 465 | needsAdjustment = 1; 466 | -- peersRemaining; 467 | bandwidth -= peer -> outgoingBandwidth; 468 | } 469 | } 470 | 471 | for (peer = host -> peers; 472 | peer < & host -> peers [host -> peerCount]; 473 | ++ peer) 474 | { 475 | if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) 476 | continue; 477 | 478 | command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; 479 | command.header.channelID = 0xFF; 480 | command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); 481 | 482 | if (peer -> incomingBandwidthThrottleEpoch == timeCurrent) 483 | command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth); 484 | else 485 | command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit); 486 | 487 | enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); 488 | } 489 | } 490 | } 491 | 492 | /** @} */ 493 | -------------------------------------------------------------------------------- /src/enet/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 | #ifdef __cplusplus 9 | extern "C" 10 | { 11 | #endif 12 | 13 | #include 14 | 15 | #ifdef WIN32 16 | #include "win32.h" 17 | #else 18 | #include "unix.h" 19 | #endif 20 | 21 | #include "types.h" 22 | #include "protocol.h" 23 | #include "list.h" 24 | 25 | #define ENET_VERSION_MAJOR 1 26 | #define ENET_VERSION_MINOR 3 27 | #define ENET_VERSION_PATCH 5 28 | #define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) 29 | #define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) 30 | 31 | typedef enet_uint32 ENetVersion; 32 | 33 | typedef enum _ENetSocketType 34 | { 35 | ENET_SOCKET_TYPE_STREAM = 1, 36 | ENET_SOCKET_TYPE_DATAGRAM = 2 37 | } ENetSocketType; 38 | 39 | typedef enum _ENetSocketWait 40 | { 41 | ENET_SOCKET_WAIT_NONE = 0, 42 | ENET_SOCKET_WAIT_SEND = (1 << 0), 43 | ENET_SOCKET_WAIT_RECEIVE = (1 << 1) 44 | } ENetSocketWait; 45 | 46 | typedef enum _ENetSocketOption 47 | { 48 | ENET_SOCKOPT_NONBLOCK = 1, 49 | ENET_SOCKOPT_BROADCAST = 2, 50 | ENET_SOCKOPT_RCVBUF = 3, 51 | ENET_SOCKOPT_SNDBUF = 4, 52 | ENET_SOCKOPT_REUSEADDR = 5, 53 | ENET_SOCKOPT_RCVTIMEO = 6, 54 | ENET_SOCKOPT_SNDTIMEO = 7 55 | } ENetSocketOption; 56 | 57 | typedef enum _ENetSocketShutdown 58 | { 59 | ENET_SOCKET_SHUTDOWN_READ = 0, 60 | ENET_SOCKET_SHUTDOWN_WRITE = 1, 61 | ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 62 | } ENetSocketShutdown; 63 | 64 | enum 65 | { 66 | ENET_HOST_ANY = 0, /**< specifies the default server host */ 67 | ENET_HOST_BROADCAST = 0xFFFFFFFF, /**< specifies a subnet-wide broadcast */ 68 | 69 | ENET_PORT_ANY = 0 /**< specifies that a port should be automatically chosen */ 70 | }; 71 | 72 | /** 73 | * Portable internet address structure. 74 | * 75 | * The host must be specified in network byte-order, and the port must be in host 76 | * byte-order. The constant ENET_HOST_ANY may be used to specify the default 77 | * server host. The constant ENET_HOST_BROADCAST may be used to specify the 78 | * broadcast address (255.255.255.255). This makes sense for enet_host_connect, 79 | * but not for enet_host_create. Once a server responds to a broadcast, the 80 | * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. 81 | */ 82 | typedef struct _ENetAddress 83 | { 84 | enet_uint32 host; 85 | enet_uint16 port; 86 | } ENetAddress; 87 | 88 | /** 89 | * Packet flag bit constants. 90 | * 91 | * The host must be specified in network byte-order, and the port must be in 92 | * host byte-order. The constant ENET_HOST_ANY may be used to specify the 93 | * default server host. 94 | 95 | @sa ENetPacket 96 | */ 97 | typedef enum _ENetPacketFlag 98 | { 99 | /** packet must be received by the target peer and resend attempts should be 100 | * made until the packet is delivered */ 101 | ENET_PACKET_FLAG_RELIABLE = (1 << 0), 102 | /** packet will not be sequenced with other packets 103 | * not supported for reliable packets 104 | */ 105 | ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), 106 | /** packet will not allocate data, and user must supply it instead */ 107 | ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), 108 | /** packet will be fragmented using unreliable (instead of reliable) sends 109 | * if it exceeds the MTU */ 110 | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), 111 | /** whether the packet has been sent from all queues it has been entered into */ 112 | ENET_PACKET_FLAG_SENT = (1<<8) 113 | 114 | } ENetPacketFlag; 115 | 116 | struct _ENetPacket; 117 | typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); 118 | 119 | /** 120 | * ENet packet structure. 121 | * 122 | * An ENet data packet that may be sent to or received from a peer. The shown 123 | * fields should only be read and never modified. The data field contains the 124 | * allocated data for the packet. The dataLength fields specifies the length 125 | * of the allocated data. The flags field is either 0 (specifying no flags), 126 | * or a bitwise-or of any combination of the following flags: 127 | * 128 | * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer 129 | * and resend attempts should be made until the packet is delivered 130 | * 131 | * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets 132 | * (not supported for reliable packets) 133 | * 134 | * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead 135 | 136 | @sa ENetPacketFlag 137 | */ 138 | typedef struct _ENetPacket 139 | { 140 | size_t referenceCount; /**< internal use only */ 141 | enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ 142 | enet_uint8 * data; /**< allocated data for packet */ 143 | size_t dataLength; /**< length of data */ 144 | ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ 145 | void * userData; /**< application private data, may be freely modified */ 146 | } ENetPacket; 147 | 148 | typedef struct _ENetAcknowledgement 149 | { 150 | ENetListNode acknowledgementList; 151 | enet_uint32 sentTime; 152 | ENetProtocol command; 153 | } ENetAcknowledgement; 154 | 155 | typedef struct _ENetOutgoingCommand 156 | { 157 | ENetListNode outgoingCommandList; 158 | enet_uint16 reliableSequenceNumber; 159 | enet_uint16 unreliableSequenceNumber; 160 | enet_uint32 sentTime; 161 | enet_uint32 roundTripTimeout; 162 | enet_uint32 roundTripTimeoutLimit; 163 | enet_uint32 fragmentOffset; 164 | enet_uint16 fragmentLength; 165 | enet_uint16 sendAttempts; 166 | ENetProtocol command; 167 | ENetPacket * packet; 168 | } ENetOutgoingCommand; 169 | 170 | typedef struct _ENetIncomingCommand 171 | { 172 | ENetListNode incomingCommandList; 173 | enet_uint16 reliableSequenceNumber; 174 | enet_uint16 unreliableSequenceNumber; 175 | ENetProtocol command; 176 | enet_uint32 fragmentCount; 177 | enet_uint32 fragmentsRemaining; 178 | enet_uint32 * fragments; 179 | ENetPacket * packet; 180 | } ENetIncomingCommand; 181 | 182 | typedef enum _ENetPeerState 183 | { 184 | ENET_PEER_STATE_DISCONNECTED = 0, 185 | ENET_PEER_STATE_CONNECTING = 1, 186 | ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, 187 | ENET_PEER_STATE_CONNECTION_PENDING = 3, 188 | ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, 189 | ENET_PEER_STATE_CONNECTED = 5, 190 | ENET_PEER_STATE_DISCONNECT_LATER = 6, 191 | ENET_PEER_STATE_DISCONNECTING = 7, 192 | ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, 193 | ENET_PEER_STATE_ZOMBIE = 9 194 | } ENetPeerState; 195 | 196 | #ifndef ENET_BUFFER_MAXIMUM 197 | #define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) 198 | #endif 199 | 200 | enum 201 | { 202 | ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, 203 | ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, 204 | ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, 205 | ENET_HOST_DEFAULT_MTU = 1400, 206 | 207 | ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, 208 | ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, 209 | ENET_PEER_PACKET_THROTTLE_SCALE = 32, 210 | ENET_PEER_PACKET_THROTTLE_COUNTER = 7, 211 | ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, 212 | ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, 213 | ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, 214 | ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), 215 | ENET_PEER_PACKET_LOSS_INTERVAL = 10000, 216 | ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, 217 | ENET_PEER_TIMEOUT_LIMIT = 32, 218 | ENET_PEER_TIMEOUT_MINIMUM = 5000, 219 | ENET_PEER_TIMEOUT_MAXIMUM = 30000, 220 | ENET_PEER_PING_INTERVAL = 500, 221 | ENET_PEER_UNSEQUENCED_WINDOWS = 64, 222 | ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, 223 | ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, 224 | ENET_PEER_RELIABLE_WINDOWS = 16, 225 | ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, 226 | ENET_PEER_FREE_RELIABLE_WINDOWS = 8 227 | }; 228 | 229 | typedef struct _ENetChannel 230 | { 231 | enet_uint16 outgoingReliableSequenceNumber; 232 | enet_uint16 outgoingUnreliableSequenceNumber; 233 | enet_uint16 usedReliableWindows; 234 | enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; 235 | enet_uint16 incomingReliableSequenceNumber; 236 | enet_uint16 incomingUnreliableSequenceNumber; 237 | ENetList incomingReliableCommands; 238 | ENetList incomingUnreliableCommands; 239 | } ENetChannel; 240 | 241 | /** 242 | * An ENet peer which data packets may be sent or received from. 243 | * 244 | * No fields should be modified unless otherwise specified. 245 | */ 246 | typedef struct _ENetPeer 247 | { 248 | ENetListNode dispatchList; 249 | struct _ENetHost * host; 250 | enet_uint16 outgoingPeerID; 251 | enet_uint16 incomingPeerID; 252 | enet_uint32 connectID; 253 | enet_uint8 outgoingSessionID; 254 | enet_uint8 incomingSessionID; 255 | ENetAddress address; /**< Internet address of the peer */ 256 | void * data; /**< Application private data, may be freely modified */ 257 | ENetPeerState state; 258 | ENetChannel * channels; 259 | size_t channelCount; /**< Number of channels allocated for communication with peer */ 260 | enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ 261 | enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ 262 | enet_uint32 incomingBandwidthThrottleEpoch; 263 | enet_uint32 outgoingBandwidthThrottleEpoch; 264 | enet_uint32 incomingDataTotal; 265 | enet_uint32 outgoingDataTotal; 266 | enet_uint32 lastSendTime; 267 | enet_uint32 lastReceiveTime; 268 | enet_uint32 nextTimeout; 269 | enet_uint32 earliestTimeout; 270 | enet_uint32 packetLossEpoch; 271 | enet_uint32 packetsSent; 272 | enet_uint32 packetsLost; 273 | enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ 274 | enet_uint32 packetLossVariance; 275 | enet_uint32 packetThrottle; 276 | enet_uint32 packetThrottleLimit; 277 | enet_uint32 packetThrottleCounter; 278 | enet_uint32 packetThrottleEpoch; 279 | enet_uint32 packetThrottleAcceleration; 280 | enet_uint32 packetThrottleDeceleration; 281 | enet_uint32 packetThrottleInterval; 282 | enet_uint32 pingInterval; 283 | enet_uint32 timeoutLimit; 284 | enet_uint32 timeoutMinimum; 285 | enet_uint32 timeoutMaximum; 286 | enet_uint32 lastRoundTripTime; 287 | enet_uint32 lowestRoundTripTime; 288 | enet_uint32 lastRoundTripTimeVariance; 289 | enet_uint32 highestRoundTripTimeVariance; 290 | enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ 291 | enet_uint32 roundTripTimeVariance; 292 | enet_uint32 mtu; 293 | enet_uint32 windowSize; 294 | enet_uint32 reliableDataInTransit; 295 | enet_uint16 outgoingReliableSequenceNumber; 296 | ENetList acknowledgements; 297 | ENetList sentReliableCommands; 298 | ENetList sentUnreliableCommands; 299 | ENetList outgoingReliableCommands; 300 | ENetList outgoingUnreliableCommands; 301 | ENetList dispatchedCommands; 302 | int needsDispatch; 303 | enet_uint16 incomingUnsequencedGroup; 304 | enet_uint16 outgoingUnsequencedGroup; 305 | enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; 306 | enet_uint32 eventData; 307 | } ENetPeer; 308 | 309 | /** An ENet packet compressor for compressing UDP packets before socket sends or receives. 310 | */ 311 | typedef struct _ENetCompressor 312 | { 313 | /** Context data for the compressor. Must be non-NULL. */ 314 | void * context; 315 | /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ 316 | size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); 317 | /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ 318 | size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); 319 | /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ 320 | void (ENET_CALLBACK * destroy) (void * context); 321 | } ENetCompressor; 322 | 323 | /** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ 324 | typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); 325 | 326 | /** An ENet host for communicating with peers. 327 | * 328 | * No fields should be modified unless otherwise stated. 329 | 330 | @sa enet_host_create() 331 | @sa enet_host_destroy() 332 | @sa enet_host_connect() 333 | @sa enet_host_service() 334 | @sa enet_host_flush() 335 | @sa enet_host_broadcast() 336 | @sa enet_host_compress() 337 | @sa enet_host_compress_with_range_coder() 338 | @sa enet_host_channel_limit() 339 | @sa enet_host_bandwidth_limit() 340 | @sa enet_host_bandwidth_throttle() 341 | */ 342 | typedef struct _ENetHost 343 | { 344 | ENetSocket socket; 345 | ENetAddress address; /**< Internet address of the host */ 346 | enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ 347 | enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ 348 | enet_uint32 bandwidthThrottleEpoch; 349 | enet_uint32 mtu; 350 | enet_uint32 randomSeed; 351 | int recalculateBandwidthLimits; 352 | ENetPeer * peers; /**< array of peers allocated for this host */ 353 | size_t peerCount; /**< number of peers allocated for this host */ 354 | size_t channelLimit; /**< maximum number of channels allowed for connected peers */ 355 | enet_uint32 serviceTime; 356 | ENetList dispatchQueue; 357 | int continueSending; 358 | size_t packetSize; 359 | enet_uint16 headerFlags; 360 | ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; 361 | size_t commandCount; 362 | ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; 363 | size_t bufferCount; 364 | ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ 365 | ENetCompressor compressor; 366 | enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; 367 | ENetAddress receivedAddress; 368 | enet_uint8 * receivedData; 369 | size_t receivedDataLength; 370 | enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ 371 | enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ 372 | enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ 373 | enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ 374 | int isClient; 375 | } ENetHost; 376 | 377 | /** 378 | * An ENet event type, as specified in @ref ENetEvent. 379 | */ 380 | typedef enum _ENetEventType 381 | { 382 | /** no event occurred within the specified time limit */ 383 | ENET_EVENT_TYPE_NONE = 0, 384 | 385 | /** a connection request initiated by enet_host_connect has completed. 386 | * The peer field contains the peer which successfully connected. 387 | */ 388 | ENET_EVENT_TYPE_CONNECT = 1, 389 | 390 | /** a peer has disconnected. This event is generated on a successful 391 | * completion of a disconnect initiated by enet_pper_disconnect, if 392 | * a peer has timed out, or if a connection request intialized by 393 | * enet_host_connect has timed out. The peer field contains the peer 394 | * which disconnected. The data field contains user supplied data 395 | * describing the disconnection, or 0, if none is available. 396 | */ 397 | ENET_EVENT_TYPE_DISCONNECT = 2, 398 | 399 | /** a packet has been received from a peer. The peer field specifies the 400 | * peer which sent the packet. The channelID field specifies the channel 401 | * number upon which the packet was received. The packet field contains 402 | * the packet that was received; this packet must be destroyed with 403 | * enet_packet_destroy after use. 404 | */ 405 | ENET_EVENT_TYPE_RECEIVE = 3 406 | } ENetEventType; 407 | 408 | /** 409 | * An ENet event as returned by enet_host_service(). 410 | 411 | @sa enet_host_service 412 | */ 413 | typedef struct _ENetEvent 414 | { 415 | ENetEventType type; /**< type of the event */ 416 | ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ 417 | enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ 418 | enet_uint32 data; /**< data associated with the event, if appropriate */ 419 | ENetPacket * packet; /**< packet associated with the event, if appropriate */ 420 | } ENetEvent; 421 | 422 | 423 | typedef struct _ENetCallbacks 424 | { 425 | void * (ENET_CALLBACK * malloc) (size_t size); 426 | void (ENET_CALLBACK * free) (void * memory); 427 | void (ENET_CALLBACK * no_memory) (void); 428 | int (ENET_CALLBACK * packet_filter) (ENetHost* host); 429 | } ENetCallbacks; 430 | 431 | /** @defgroup callbacks ENet internal callbacks 432 | @{ 433 | @ingroup private 434 | */ 435 | extern void * enet_malloc (size_t); 436 | extern void enet_free (void *); 437 | extern int enet_packet_filter (ENetHost*); 438 | /** @} */ 439 | 440 | 441 | /** @defgroup global ENet global functions 442 | @{ 443 | */ 444 | 445 | /** 446 | Initializes ENet globally. Must be called prior to using any functions in 447 | ENet. 448 | @returns 0 on success, < 0 on failure 449 | */ 450 | ENET_API int enet_initialize (void); 451 | 452 | /** 453 | 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. 454 | 455 | @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use 456 | @param inits user-overriden callbacks where any NULL callbacks will use ENet's defaults 457 | @returns 0 on success, < 0 on failure 458 | */ 459 | ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); 460 | 461 | /** 462 | Shuts down ENet globally. Should be called when a program that has 463 | initialized ENet exits. 464 | */ 465 | ENET_API void enet_deinitialize (void); 466 | 467 | /** @} */ 468 | 469 | /** @defgroup private ENet private implementation functions */ 470 | 471 | /** 472 | Returns the wall-time in milliseconds. Its initial value is unspecified 473 | unless otherwise set. 474 | */ 475 | ENET_API enet_uint32 enet_time_get (void); 476 | /** 477 | Sets the current wall-time in milliseconds. 478 | */ 479 | ENET_API void enet_time_set (enet_uint32); 480 | 481 | /** @defgroup socket ENet socket functions 482 | @{ 483 | */ 484 | ENET_API ENetSocket enet_socket_create (ENetSocketType); 485 | ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); 486 | ENET_API int enet_socket_listen (ENetSocket, int); 487 | ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); 488 | ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); 489 | ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); 490 | ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); 491 | ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); 492 | ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); 493 | ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown); 494 | ENET_API void enet_socket_destroy (ENetSocket); 495 | ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); 496 | 497 | /** @} */ 498 | 499 | /** @defgroup Address ENet address functions 500 | @{ 501 | */ 502 | /** Attempts to resolve the host named by the parameter hostName and sets 503 | the host field in the address parameter if successful. 504 | @param address destination to store resolved address 505 | @param hostName host name to lookup 506 | @retval 0 on success 507 | @retval < 0 on failure 508 | @returns the address of the given hostName in address on success 509 | */ 510 | ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); 511 | 512 | /** Gives the printable form of the ip address specified in the address parameter. 513 | @param address address printed 514 | @param hostName destination for name, must not be NULL 515 | @param nameLength maximum length of hostName. 516 | @returns the null-terminated name of the host in hostName on success 517 | @retval 0 on success 518 | @retval < 0 on failure 519 | */ 520 | ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); 521 | 522 | /** Attempts to do a reverse lookup of the host field in the address parameter. 523 | @param address address used for reverse lookup 524 | @param hostName destination for name, must not be NULL 525 | @param nameLength maximum length of hostName. 526 | @returns the null-terminated name of the host in hostName on success 527 | @retval 0 on success 528 | @retval < 0 on failure 529 | */ 530 | ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); 531 | 532 | /** @} */ 533 | 534 | ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); 535 | ENET_API void enet_packet_destroy (ENetPacket *); 536 | ENET_API int enet_packet_resize (ENetPacket *, size_t); 537 | ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t); 538 | 539 | ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); 540 | ENET_API void enet_host_destroy (ENetHost *); 541 | ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); 542 | ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); 543 | ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); 544 | ENET_API void enet_host_flush (ENetHost *); 545 | ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); 546 | ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); 547 | ENET_API int enet_host_compress_with_range_coder (ENetHost * host); 548 | ENET_API void enet_host_channel_limit (ENetHost *, size_t); 549 | ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); 550 | extern void enet_host_bandwidth_throttle (ENetHost *); 551 | 552 | ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); 553 | ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); 554 | ENET_API void enet_peer_ping (ENetPeer *); 555 | ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32); 556 | ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); 557 | ENET_API void enet_peer_reset (ENetPeer *); 558 | ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); 559 | ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); 560 | ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); 561 | ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); 562 | extern int enet_peer_throttle (ENetPeer *, enet_uint32); 563 | extern void enet_peer_reset_queues (ENetPeer *); 564 | extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); 565 | extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); 566 | extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32); 567 | extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); 568 | extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); 569 | extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); 570 | 571 | ENET_API void * enet_range_coder_create (void); 572 | ENET_API void enet_range_coder_destroy (void *); 573 | ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); 574 | ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); 575 | 576 | extern size_t enet_protocol_command_size (enet_uint8); 577 | 578 | #ifdef __cplusplus 579 | } 580 | #endif 581 | 582 | #endif /* __ENET_ENET_H__ */ 583 | 584 | -------------------------------------------------------------------------------- /src/enet/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 | extern void enet_list_clear (ENetList *); 24 | 25 | extern ENetListIterator enet_list_insert (ENetListIterator, void *); 26 | extern void * enet_list_remove (ENetListIterator); 27 | extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); 28 | 29 | extern size_t enet_list_size (ENetList *); 30 | 31 | #define enet_list_begin(list) ((list) -> sentinel.next) 32 | #define enet_list_end(list) (& (list) -> sentinel) 33 | 34 | #define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) 35 | 36 | #define enet_list_next(iterator) ((iterator) -> next) 37 | #define enet_list_previous(iterator) ((iterator) -> previous) 38 | 39 | #define enet_list_front(list) ((void *) (list) -> sentinel.next) 40 | #define enet_list_back(list) ((void *) (list) -> sentinel.previous) 41 | 42 | #endif /* __ENET_LIST_H__ */ 43 | 44 | -------------------------------------------------------------------------------- /src/enet/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 "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_PACKET_SIZE = 1024 * 1024 * 1024, 21 | ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 22 | }; 23 | 24 | typedef enum _ENetProtocolCommand 25 | { 26 | ENET_PROTOCOL_COMMAND_NONE = 0, 27 | ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, 28 | ENET_PROTOCOL_COMMAND_CONNECT = 2, 29 | ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, 30 | ENET_PROTOCOL_COMMAND_DISCONNECT = 4, 31 | ENET_PROTOCOL_COMMAND_PING = 5, 32 | ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, 33 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, 34 | ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, 35 | ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, 36 | ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, 37 | ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, 38 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, 39 | ENET_PROTOCOL_COMMAND_COUNT = 13, 40 | 41 | ENET_PROTOCOL_COMMAND_MASK = 0x0F 42 | } ENetProtocolCommand; 43 | 44 | typedef enum _ENetProtocolFlag 45 | { 46 | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), 47 | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), 48 | 49 | ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), 50 | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), 51 | ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, 52 | 53 | ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), 54 | ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 55 | } ENetProtocolFlag; 56 | 57 | #ifdef _MSC_VER_ 58 | #pragma pack(push, 1) 59 | #define ENET_PACKED 60 | #elif defined(__GNUC__) || defined(__clang__) 61 | #define ENET_PACKED __attribute__ ((packed)) 62 | #else 63 | #define ENET_PACKED 64 | #endif 65 | 66 | typedef struct _ENetProtocolHeader 67 | { 68 | enet_uint16 peerID; 69 | enet_uint16 sentTime; 70 | } ENET_PACKED ENetProtocolHeader; 71 | 72 | typedef struct _ENetProtocolCommandHeader 73 | { 74 | enet_uint8 command; 75 | enet_uint8 channelID; 76 | enet_uint16 reliableSequenceNumber; 77 | } ENET_PACKED ENetProtocolCommandHeader; 78 | 79 | typedef struct _ENetProtocolAcknowledge 80 | { 81 | ENetProtocolCommandHeader header; 82 | enet_uint16 receivedReliableSequenceNumber; 83 | enet_uint16 receivedSentTime; 84 | } ENET_PACKED ENetProtocolAcknowledge; 85 | 86 | typedef struct _ENetProtocolConnect 87 | { 88 | ENetProtocolCommandHeader header; 89 | enet_uint16 outgoingPeerID; 90 | enet_uint8 incomingSessionID; 91 | enet_uint8 outgoingSessionID; 92 | enet_uint32 mtu; 93 | enet_uint32 windowSize; 94 | enet_uint32 channelCount; 95 | enet_uint32 incomingBandwidth; 96 | enet_uint32 outgoingBandwidth; 97 | enet_uint32 packetThrottleInterval; 98 | enet_uint32 packetThrottleAcceleration; 99 | enet_uint32 packetThrottleDeceleration; 100 | enet_uint32 connectID; 101 | enet_uint32 data; 102 | } ENET_PACKED ENetProtocolConnect; 103 | 104 | typedef struct _ENetProtocolVerifyConnect 105 | { 106 | ENetProtocolCommandHeader header; 107 | enet_uint16 outgoingPeerID; 108 | enet_uint8 incomingSessionID; 109 | enet_uint8 outgoingSessionID; 110 | enet_uint32 mtu; 111 | enet_uint32 windowSize; 112 | enet_uint32 channelCount; 113 | enet_uint32 incomingBandwidth; 114 | enet_uint32 outgoingBandwidth; 115 | enet_uint32 packetThrottleInterval; 116 | enet_uint32 packetThrottleAcceleration; 117 | enet_uint32 packetThrottleDeceleration; 118 | enet_uint32 connectID; 119 | } ENET_PACKED ENetProtocolVerifyConnect; 120 | 121 | typedef struct _ENetProtocolBandwidthLimit 122 | { 123 | ENetProtocolCommandHeader header; 124 | enet_uint32 incomingBandwidth; 125 | enet_uint32 outgoingBandwidth; 126 | } ENET_PACKED ENetProtocolBandwidthLimit; 127 | 128 | typedef struct _ENetProtocolThrottleConfigure 129 | { 130 | ENetProtocolCommandHeader header; 131 | enet_uint32 packetThrottleInterval; 132 | enet_uint32 packetThrottleAcceleration; 133 | enet_uint32 packetThrottleDeceleration; 134 | } ENET_PACKED ENetProtocolThrottleConfigure; 135 | 136 | typedef struct _ENetProtocolDisconnect 137 | { 138 | ENetProtocolCommandHeader header; 139 | enet_uint32 data; 140 | } ENET_PACKED ENetProtocolDisconnect; 141 | 142 | typedef struct _ENetProtocolPing 143 | { 144 | ENetProtocolCommandHeader header; 145 | } ENET_PACKED ENetProtocolPing; 146 | 147 | typedef struct _ENetProtocolSendReliable 148 | { 149 | ENetProtocolCommandHeader header; 150 | enet_uint16 dataLength; 151 | } ENET_PACKED ENetProtocolSendReliable; 152 | 153 | typedef struct _ENetProtocolSendUnreliable 154 | { 155 | ENetProtocolCommandHeader header; 156 | enet_uint16 unreliableSequenceNumber; 157 | enet_uint16 dataLength; 158 | } ENET_PACKED ENetProtocolSendUnreliable; 159 | 160 | typedef struct _ENetProtocolSendUnsequenced 161 | { 162 | ENetProtocolCommandHeader header; 163 | enet_uint16 unsequencedGroup; 164 | enet_uint16 dataLength; 165 | } ENET_PACKED ENetProtocolSendUnsequenced; 166 | 167 | typedef struct _ENetProtocolSendFragment 168 | { 169 | ENetProtocolCommandHeader header; 170 | enet_uint16 startSequenceNumber; 171 | enet_uint16 dataLength; 172 | enet_uint32 fragmentCount; 173 | enet_uint32 fragmentNumber; 174 | enet_uint32 totalLength; 175 | enet_uint32 fragmentOffset; 176 | } ENET_PACKED ENetProtocolSendFragment; 177 | 178 | typedef union _ENetProtocol 179 | { 180 | ENetProtocolCommandHeader header; 181 | ENetProtocolAcknowledge acknowledge; 182 | ENetProtocolConnect connect; 183 | ENetProtocolVerifyConnect verifyConnect; 184 | ENetProtocolDisconnect disconnect; 185 | ENetProtocolPing ping; 186 | ENetProtocolSendReliable sendReliable; 187 | ENetProtocolSendUnreliable sendUnreliable; 188 | ENetProtocolSendUnsequenced sendUnsequenced; 189 | ENetProtocolSendFragment sendFragment; 190 | ENetProtocolBandwidthLimit bandwidthLimit; 191 | ENetProtocolThrottleConfigure throttleConfigure; 192 | } ENET_PACKED ENetProtocol; 193 | 194 | #ifdef _MSC_VER_ 195 | #pragma pack(pop) 196 | #endif 197 | 198 | #endif /* __ENET_PROTOCOL_H__ */ 199 | 200 | -------------------------------------------------------------------------------- /src/enet/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 | -------------------------------------------------------------------------------- /src/enet/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 | -------------------------------------------------------------------------------- /src/enet/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 | 15 | typedef int ENetSocket; 16 | 17 | enum 18 | { 19 | ENET_SOCKET_NULL = -1 20 | }; 21 | 22 | #define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ 23 | #define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ 24 | 25 | #define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ 26 | #define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ 27 | 28 | typedef struct 29 | { 30 | void * data; 31 | size_t dataLength; 32 | } ENetBuffer; 33 | 34 | #define ENET_CALLBACK 35 | 36 | #define ENET_API extern 37 | 38 | typedef fd_set ENetSocketSet; 39 | 40 | #define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) 41 | #define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) 42 | #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) 43 | #define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) 44 | 45 | #endif /* __ENET_UNIX_H__ */ 46 | 47 | -------------------------------------------------------------------------------- /src/enet/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 | 11 | #endif /* __ENET_UTILITY_H__ */ 12 | 13 | -------------------------------------------------------------------------------- /src/enet/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 | -------------------------------------------------------------------------------- /src/enet/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 dataContents initial contents of the packet's data; the packet's data will remain uninitialized if dataContents 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 | return packet; 50 | } 51 | 52 | /** Destroys the packet and deallocates its data. 53 | @param packet packet to be destroyed 54 | */ 55 | void 56 | enet_packet_destroy (ENetPacket * packet) 57 | { 58 | if (packet == NULL) 59 | return; 60 | 61 | if (packet -> freeCallback != NULL) 62 | (* packet -> freeCallback) (packet); 63 | if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE) && 64 | packet -> data != NULL) 65 | enet_free (packet -> data); 66 | enet_free (packet); 67 | } 68 | 69 | /** Attempts to resize the data in the packet to length specified in the 70 | dataLength parameter 71 | @param packet packet to resize 72 | @param dataLength new size for the packet data 73 | @returns 0 on success, < 0 on failure 74 | */ 75 | int 76 | enet_packet_resize (ENetPacket * packet, size_t dataLength) 77 | { 78 | enet_uint8 * newData; 79 | 80 | if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) 81 | { 82 | packet -> dataLength = dataLength; 83 | 84 | return 0; 85 | } 86 | 87 | newData = (enet_uint8 *) enet_malloc (dataLength); 88 | if (newData == NULL) 89 | return -1; 90 | 91 | memcpy (newData, packet -> data, packet -> dataLength); 92 | enet_free (packet -> data); 93 | 94 | packet -> data = newData; 95 | packet -> dataLength = dataLength; 96 | 97 | return 0; 98 | } 99 | 100 | static int initializedCRC32 = 0; 101 | static enet_uint32 crcTable [256]; 102 | 103 | static enet_uint32 104 | reflect_crc (int val, int bits) 105 | { 106 | int result = 0, bit; 107 | 108 | for (bit = 0; bit < bits; bit ++) 109 | { 110 | if(val & 1) result |= 1 << (bits - 1 - bit); 111 | val >>= 1; 112 | } 113 | 114 | return result; 115 | } 116 | 117 | static void 118 | initialize_crc32 (void) 119 | { 120 | int byte; 121 | 122 | for (byte = 0; byte < 256; ++ byte) 123 | { 124 | enet_uint32 crc = reflect_crc (byte, 8) << 24; 125 | int offset; 126 | 127 | for(offset = 0; offset < 8; ++ offset) 128 | { 129 | if (crc & 0x80000000) 130 | crc = (crc << 1) ^ 0x04c11db7; 131 | else 132 | crc <<= 1; 133 | } 134 | 135 | crcTable [byte] = reflect_crc (crc, 32); 136 | } 137 | 138 | initializedCRC32 = 1; 139 | } 140 | 141 | enet_uint32 142 | enet_crc32 (const ENetBuffer * buffers, size_t bufferCount) 143 | { 144 | enet_uint32 crc = 0xFFFFFFFF; 145 | 146 | if (! initializedCRC32) initialize_crc32 (); 147 | 148 | while (bufferCount -- > 0) 149 | { 150 | const enet_uint8 * data = (const enet_uint8 *) buffers -> data, 151 | * dataEnd = & data [buffers -> dataLength]; 152 | 153 | while (data < dataEnd) 154 | { 155 | crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; 156 | } 157 | 158 | ++ buffers; 159 | } 160 | 161 | return ENET_HOST_TO_NET_32 (~ crc); 162 | } 163 | 164 | /** @} */ 165 | -------------------------------------------------------------------------------- /src/enet/peer.c: -------------------------------------------------------------------------------- 1 | /** 2 | @file peer.c 3 | @brief ENet peer management functions 4 | */ 5 | #include 6 | #define ENET_BUILDING_LIB 1 7 | #include "enet/enet.h" 8 | 9 | /** @defgroup peer ENet peer functions 10 | @{ 11 | */ 12 | 13 | /** Configures throttle parameter for a peer. 14 | 15 | Unreliable packets are dropped by ENet in response to the varying conditions 16 | of the Internet connection to the peer. The throttle represents a probability 17 | that an unreliable packet should not be dropped and thus sent by ENet to the peer. 18 | The lowest mean round trip time from the sending of a reliable packet to the 19 | receipt of its acknowledgement is measured over an amount of time specified by 20 | the interval parameter in milliseconds. If a measured round trip time happens to 21 | be significantly less than the mean round trip time measured over the interval, 22 | then the throttle probability is increased to allow more traffic by an amount 23 | specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE 24 | constant. If a measured round trip time happens to be significantly greater than 25 | the mean round trip time measured over the interval, then the throttle probability 26 | is decreased to limit traffic by an amount specified in the deceleration parameter, which 27 | is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has 28 | a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by 29 | ENet, and so 100% of all unreliable packets will be sent. When the throttle has a 30 | value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable 31 | packets will be sent. Intermediate values for the throttle represent intermediate 32 | probabilities between 0% and 100% of unreliable packets being sent. The bandwidth 33 | limits of the local and foreign hosts are taken into account to determine a 34 | sensible limit for the throttle probability above which it should not raise even in 35 | the best of conditions. 36 | 37 | @param peer peer to configure 38 | @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL. 39 | @param acceleration rate at which to increase the throttle probability as mean RTT declines 40 | @param deceleration rate at which to decrease the throttle probability as mean RTT increases 41 | */ 42 | void 43 | enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration) 44 | { 45 | ENetProtocol command; 46 | 47 | peer -> packetThrottleInterval = interval; 48 | peer -> packetThrottleAcceleration = acceleration; 49 | peer -> packetThrottleDeceleration = deceleration; 50 | 51 | command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; 52 | command.header.channelID = 0xFF; 53 | 54 | command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval); 55 | command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration); 56 | command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (deceleration); 57 | 58 | enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); 59 | } 60 | 61 | int 62 | enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt) 63 | { 64 | if (peer -> lastRoundTripTime <= peer -> lastRoundTripTimeVariance) 65 | { 66 | peer -> packetThrottle = peer -> packetThrottleLimit; 67 | } 68 | else 69 | if (rtt < peer -> lastRoundTripTime) 70 | { 71 | peer -> packetThrottle += peer -> packetThrottleAcceleration; 72 | 73 | if (peer -> packetThrottle > peer -> packetThrottleLimit) 74 | peer -> packetThrottle = peer -> packetThrottleLimit; 75 | 76 | return 1; 77 | } 78 | else 79 | if (rtt > peer -> lastRoundTripTime + 2 * peer -> lastRoundTripTimeVariance) 80 | { 81 | if (peer -> packetThrottle > peer -> packetThrottleDeceleration) 82 | peer -> packetThrottle -= peer -> packetThrottleDeceleration; 83 | else 84 | peer -> packetThrottle = 0; 85 | 86 | return -1; 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | /** Queues a packet to be sent. 93 | @param peer destination for the packet 94 | @param channelID channel on which to send 95 | @param packet packet to send 96 | @retval 0 on success 97 | @retval < 0 on failure 98 | */ 99 | int 100 | enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) 101 | { 102 | ENetChannel * channel = & peer -> channels [channelID]; 103 | ENetProtocol command; 104 | size_t fragmentLength; 105 | 106 | if (peer -> state != ENET_PEER_STATE_CONNECTED || 107 | channelID >= peer -> channelCount || 108 | packet -> dataLength > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE) 109 | return -1; 110 | 111 | fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment); 112 | if (peer -> host -> checksum != NULL) 113 | fragmentLength -= sizeof(enet_uint32); 114 | 115 | if (packet -> dataLength > fragmentLength) 116 | { 117 | enet_uint32 fragmentCount = (packet -> dataLength + fragmentLength - 1) / fragmentLength, 118 | fragmentNumber, 119 | fragmentOffset; 120 | enet_uint8 commandNumber; 121 | enet_uint16 startSequenceNumber; 122 | ENetList fragments; 123 | ENetOutgoingCommand * fragment; 124 | 125 | if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) 126 | return -1; 127 | 128 | if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT && 129 | channel -> outgoingUnreliableSequenceNumber < 0xFFFF) 130 | { 131 | commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT; 132 | startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1); 133 | } 134 | else 135 | { 136 | commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; 137 | startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1); 138 | } 139 | 140 | enet_list_clear (& fragments); 141 | 142 | for (fragmentNumber = 0, 143 | fragmentOffset = 0; 144 | fragmentOffset < packet -> dataLength; 145 | ++ fragmentNumber, 146 | fragmentOffset += fragmentLength) 147 | { 148 | if (packet -> dataLength - fragmentOffset < fragmentLength) 149 | fragmentLength = packet -> dataLength - fragmentOffset; 150 | 151 | fragment = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); 152 | if (fragment == NULL) 153 | { 154 | while (! enet_list_empty (& fragments)) 155 | { 156 | fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); 157 | 158 | enet_free (fragment); 159 | } 160 | 161 | return -1; 162 | } 163 | 164 | fragment -> fragmentOffset = fragmentOffset; 165 | fragment -> fragmentLength = fragmentLength; 166 | fragment -> packet = packet; 167 | fragment -> command.header.command = commandNumber; 168 | fragment -> command.header.channelID = channelID; 169 | fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber; 170 | fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength); 171 | fragment -> command.sendFragment.fragmentCount = ENET_HOST_TO_NET_32 (fragmentCount); 172 | fragment -> command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber); 173 | fragment -> command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength); 174 | fragment -> command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset); 175 | 176 | enet_list_insert (enet_list_end (& fragments), fragment); 177 | } 178 | 179 | packet -> referenceCount += fragmentNumber; 180 | 181 | while (! enet_list_empty (& fragments)) 182 | { 183 | fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments)); 184 | 185 | enet_peer_setup_outgoing_command (peer, fragment); 186 | } 187 | 188 | return 0; 189 | } 190 | 191 | command.header.channelID = channelID; 192 | 193 | if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED) 194 | { 195 | command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; 196 | command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); 197 | } 198 | else 199 | if (packet -> flags & ENET_PACKET_FLAG_RELIABLE || channel -> outgoingUnreliableSequenceNumber >= 0xFFFF) 200 | { 201 | command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; 202 | command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); 203 | } 204 | else 205 | { 206 | command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE; 207 | command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); 208 | } 209 | 210 | if (enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength) == NULL) 211 | return -1; 212 | 213 | return 0; 214 | } 215 | 216 | /** Attempts to dequeue any incoming queued packet. 217 | @param peer peer to dequeue packets from 218 | @param channelID holds the channel ID of the channel the packet was received on success 219 | @returns a pointer to the packet, or NULL if there are no available incoming queued packets 220 | */ 221 | ENetPacket * 222 | enet_peer_receive (ENetPeer * peer, enet_uint8 * channelID) 223 | { 224 | ENetIncomingCommand * incomingCommand; 225 | ENetPacket * packet; 226 | 227 | if (enet_list_empty (& peer -> dispatchedCommands)) 228 | return NULL; 229 | 230 | incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> dispatchedCommands)); 231 | 232 | if (channelID != NULL) 233 | * channelID = incomingCommand -> command.header.channelID; 234 | 235 | packet = incomingCommand -> packet; 236 | 237 | -- packet -> referenceCount; 238 | 239 | if (incomingCommand -> fragments != NULL) 240 | enet_free (incomingCommand -> fragments); 241 | 242 | enet_free (incomingCommand); 243 | 244 | return packet; 245 | } 246 | 247 | static void 248 | enet_peer_reset_outgoing_commands (ENetList * queue) 249 | { 250 | ENetOutgoingCommand * outgoingCommand; 251 | 252 | while (! enet_list_empty (queue)) 253 | { 254 | outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue)); 255 | 256 | if (outgoingCommand -> packet != NULL) 257 | { 258 | -- outgoingCommand -> packet -> referenceCount; 259 | 260 | if (outgoingCommand -> packet -> referenceCount == 0) 261 | enet_packet_destroy (outgoingCommand -> packet); 262 | } 263 | 264 | enet_free (outgoingCommand); 265 | } 266 | } 267 | 268 | static void 269 | enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startCommand, ENetListIterator endCommand) 270 | { 271 | ENetListIterator currentCommand; 272 | 273 | for (currentCommand = startCommand; currentCommand != endCommand; ) 274 | { 275 | ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; 276 | 277 | currentCommand = enet_list_next (currentCommand); 278 | 279 | enet_list_remove (& incomingCommand -> incomingCommandList); 280 | 281 | if (incomingCommand -> packet != NULL) 282 | { 283 | -- incomingCommand -> packet -> referenceCount; 284 | 285 | if (incomingCommand -> packet -> referenceCount == 0) 286 | enet_packet_destroy (incomingCommand -> packet); 287 | } 288 | 289 | if (incomingCommand -> fragments != NULL) 290 | enet_free (incomingCommand -> fragments); 291 | 292 | enet_free (incomingCommand); 293 | } 294 | } 295 | 296 | static void 297 | enet_peer_reset_incoming_commands (ENetList * queue) 298 | { 299 | enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end(queue)); 300 | } 301 | 302 | void 303 | enet_peer_reset_queues (ENetPeer * peer) 304 | { 305 | ENetChannel * channel; 306 | 307 | if (peer -> needsDispatch) 308 | { 309 | enet_list_remove (& peer -> dispatchList); 310 | 311 | peer -> needsDispatch = 0; 312 | } 313 | 314 | while (! enet_list_empty (& peer -> acknowledgements)) 315 | enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements))); 316 | 317 | enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands); 318 | enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands); 319 | enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands); 320 | enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands); 321 | enet_peer_reset_incoming_commands (& peer -> dispatchedCommands); 322 | 323 | if (peer -> channels != NULL && peer -> channelCount > 0) 324 | { 325 | for (channel = peer -> channels; 326 | channel < & peer -> channels [peer -> channelCount]; 327 | ++ channel) 328 | { 329 | enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands); 330 | enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands); 331 | } 332 | 333 | enet_free (peer -> channels); 334 | } 335 | 336 | peer -> channels = NULL; 337 | peer -> channelCount = 0; 338 | } 339 | 340 | /** Forcefully disconnects a peer. 341 | @param peer peer to forcefully disconnect 342 | @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout 343 | on its connection to the local host. 344 | */ 345 | void 346 | enet_peer_reset (ENetPeer * peer) 347 | { 348 | peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; 349 | peer -> connectID = 0; 350 | 351 | peer -> state = ENET_PEER_STATE_DISCONNECTED; 352 | 353 | peer -> incomingBandwidth = 0; 354 | peer -> outgoingBandwidth = 0; 355 | peer -> incomingBandwidthThrottleEpoch = 0; 356 | peer -> outgoingBandwidthThrottleEpoch = 0; 357 | peer -> incomingDataTotal = 0; 358 | peer -> outgoingDataTotal = 0; 359 | peer -> lastSendTime = 0; 360 | peer -> lastReceiveTime = 0; 361 | peer -> nextTimeout = 0; 362 | peer -> earliestTimeout = 0; 363 | peer -> packetLossEpoch = 0; 364 | peer -> packetsSent = 0; 365 | peer -> packetsLost = 0; 366 | peer -> packetLoss = 0; 367 | peer -> packetLossVariance = 0; 368 | peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE; 369 | peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE; 370 | peer -> packetThrottleCounter = 0; 371 | peer -> packetThrottleEpoch = 0; 372 | peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION; 373 | peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION; 374 | peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL; 375 | peer -> pingInterval = ENET_PEER_PING_INTERVAL; 376 | peer -> timeoutLimit = ENET_PEER_TIMEOUT_LIMIT; 377 | peer -> timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM; 378 | peer -> timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM; 379 | peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; 380 | peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; 381 | peer -> lastRoundTripTimeVariance = 0; 382 | peer -> highestRoundTripTimeVariance = 0; 383 | peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; 384 | peer -> roundTripTimeVariance = 0; 385 | peer -> mtu = peer -> host -> mtu; 386 | peer -> reliableDataInTransit = 0; 387 | peer -> outgoingReliableSequenceNumber = 0; 388 | peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; 389 | peer -> incomingUnsequencedGroup = 0; 390 | peer -> outgoingUnsequencedGroup = 0; 391 | peer -> eventData = 0; 392 | 393 | memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); 394 | 395 | enet_peer_reset_queues (peer); 396 | } 397 | 398 | /** Sends a ping request to a peer. 399 | @param peer destination for the ping request 400 | @remarks ping requests factor into the mean round trip time as designated by the 401 | roundTripTime field in the ENetPeer structure. Enet automatically pings all connected 402 | peers at regular intervals, however, this function may be called to ensure more 403 | frequent ping requests. 404 | */ 405 | void 406 | enet_peer_ping (ENetPeer * peer) 407 | { 408 | ENetProtocol command; 409 | 410 | if (peer -> state != ENET_PEER_STATE_CONNECTED) 411 | return; 412 | 413 | command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; 414 | command.header.channelID = 0xFF; 415 | 416 | enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); 417 | } 418 | 419 | /** Sets the interval at which pings will be sent to a peer. 420 | 421 | Pings are used both to monitor the liveness of the connection and also to dynamically 422 | adjust the throttle during periods of low traffic so that the throttle has reasonable 423 | responsiveness during traffic spikes. 424 | 425 | @param peer the peer to adjust 426 | @param pingInterval the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0 427 | */ 428 | void 429 | enet_peer_ping_interval (ENetPeer * peer, enet_uint32 pingInterval) 430 | { 431 | peer -> pingInterval = pingInterval ? pingInterval : ENET_PEER_PING_INTERVAL; 432 | } 433 | 434 | /** Sets the timeout parameters for a peer. 435 | 436 | The timeout parameter control how and when a peer will timeout from a failure to acknowledge 437 | reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable 438 | packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, 439 | the timeout will be doubled until it reaches a set limit. If the timeout is thus at this 440 | limit and reliable packets have been sent but not acknowledged within a certain minimum time 441 | period, the peer will be disconnected. Alternatively, if reliable packets have been sent 442 | but not acknowledged for a certain maximum time period, the peer will be disconnected regardless 443 | of the current timeout limit value. 444 | 445 | @param peer the peer to adjust 446 | @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0 447 | @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0 448 | @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0 449 | */ 450 | 451 | void 452 | enet_peer_timeout (ENetPeer * peer, enet_uint32 timeoutLimit, enet_uint32 timeoutMinimum, enet_uint32 timeoutMaximum) 453 | { 454 | peer -> timeoutLimit = timeoutLimit ? timeoutLimit : ENET_PEER_TIMEOUT_LIMIT; 455 | peer -> timeoutMinimum = timeoutMinimum ? timeoutMinimum : ENET_PEER_TIMEOUT_MINIMUM; 456 | peer -> timeoutMaximum = timeoutMaximum ? timeoutMaximum : ENET_PEER_TIMEOUT_MAXIMUM; 457 | } 458 | 459 | /** Force an immediate disconnection from a peer. 460 | @param peer peer to disconnect 461 | @param data data describing the disconnection 462 | @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not 463 | guarenteed to receive the disconnect notification, and is reset immediately upon 464 | return from this function. 465 | */ 466 | void 467 | enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data) 468 | { 469 | ENetProtocol command; 470 | 471 | if (peer -> state == ENET_PEER_STATE_DISCONNECTED) 472 | return; 473 | 474 | if (peer -> state != ENET_PEER_STATE_ZOMBIE && 475 | peer -> state != ENET_PEER_STATE_DISCONNECTING) 476 | { 477 | enet_peer_reset_queues (peer); 478 | 479 | command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; 480 | command.header.channelID = 0xFF; 481 | command.disconnect.data = ENET_HOST_TO_NET_32 (data); 482 | 483 | enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); 484 | 485 | enet_host_flush (peer -> host); 486 | } 487 | 488 | enet_peer_reset (peer); 489 | } 490 | 491 | /** Request a disconnection from a peer. 492 | @param peer peer to request a disconnection 493 | @param data data describing the disconnection 494 | @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() 495 | once the disconnection is complete. 496 | */ 497 | void 498 | enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) 499 | { 500 | ENetProtocol command; 501 | 502 | if (peer -> state == ENET_PEER_STATE_DISCONNECTING || 503 | peer -> state == ENET_PEER_STATE_DISCONNECTED || 504 | peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT || 505 | peer -> state == ENET_PEER_STATE_ZOMBIE) 506 | return; 507 | 508 | enet_peer_reset_queues (peer); 509 | 510 | command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; 511 | command.header.channelID = 0xFF; 512 | command.disconnect.data = ENET_HOST_TO_NET_32 (data); 513 | 514 | if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) 515 | command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; 516 | else 517 | command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; 518 | 519 | enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); 520 | 521 | if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) 522 | peer -> state = ENET_PEER_STATE_DISCONNECTING; 523 | else 524 | { 525 | enet_host_flush (peer -> host); 526 | enet_peer_reset (peer); 527 | } 528 | } 529 | 530 | /** Request a disconnection from a peer, but only after all queued outgoing packets are sent. 531 | @param peer peer to request a disconnection 532 | @param data data describing the disconnection 533 | @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() 534 | once the disconnection is complete. 535 | */ 536 | void 537 | enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data) 538 | { 539 | if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && 540 | ! (enet_list_empty (& peer -> outgoingReliableCommands) && 541 | enet_list_empty (& peer -> outgoingUnreliableCommands) && 542 | enet_list_empty (& peer -> sentReliableCommands))) 543 | { 544 | peer -> state = ENET_PEER_STATE_DISCONNECT_LATER; 545 | peer -> eventData = data; 546 | } 547 | else 548 | enet_peer_disconnect (peer, data); 549 | } 550 | 551 | ENetAcknowledgement * 552 | enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime) 553 | { 554 | ENetAcknowledgement * acknowledgement; 555 | 556 | if (command -> header.channelID < peer -> channelCount) 557 | { 558 | ENetChannel * channel = & peer -> channels [command -> header.channelID]; 559 | enet_uint16 reliableWindow = command -> header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE, 560 | currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; 561 | 562 | if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber) 563 | reliableWindow += ENET_PEER_RELIABLE_WINDOWS; 564 | 565 | if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS) 566 | return NULL; 567 | } 568 | 569 | acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement)); 570 | if (acknowledgement == NULL) 571 | return NULL; 572 | 573 | peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge); 574 | 575 | acknowledgement -> sentTime = sentTime; 576 | acknowledgement -> command = * command; 577 | 578 | enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement); 579 | 580 | return acknowledgement; 581 | } 582 | 583 | void 584 | enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand) 585 | { 586 | ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID]; 587 | 588 | peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength; 589 | 590 | if (outgoingCommand -> command.header.channelID == 0xFF) 591 | { 592 | ++ peer -> outgoingReliableSequenceNumber; 593 | 594 | outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber; 595 | outgoingCommand -> unreliableSequenceNumber = 0; 596 | } 597 | else 598 | if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) 599 | { 600 | ++ channel -> outgoingReliableSequenceNumber; 601 | channel -> outgoingUnreliableSequenceNumber = 0; 602 | 603 | outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; 604 | outgoingCommand -> unreliableSequenceNumber = 0; 605 | } 606 | else 607 | if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) 608 | { 609 | ++ peer -> outgoingUnsequencedGroup; 610 | 611 | outgoingCommand -> reliableSequenceNumber = 0; 612 | outgoingCommand -> unreliableSequenceNumber = 0; 613 | } 614 | else 615 | { 616 | if (outgoingCommand -> fragmentOffset == 0) 617 | ++ channel -> outgoingUnreliableSequenceNumber; 618 | 619 | outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; 620 | outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber; 621 | } 622 | 623 | outgoingCommand -> sendAttempts = 0; 624 | outgoingCommand -> sentTime = 0; 625 | outgoingCommand -> roundTripTimeout = 0; 626 | outgoingCommand -> roundTripTimeoutLimit = 0; 627 | outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber); 628 | 629 | switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) 630 | { 631 | case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: 632 | outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> unreliableSequenceNumber); 633 | break; 634 | 635 | case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: 636 | outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup); 637 | break; 638 | 639 | default: 640 | break; 641 | } 642 | 643 | if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) 644 | enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand); 645 | else 646 | enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand); 647 | } 648 | 649 | ENetOutgoingCommand * 650 | enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length) 651 | { 652 | ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); 653 | if (outgoingCommand == NULL) 654 | return NULL; 655 | 656 | outgoingCommand -> command = * command; 657 | outgoingCommand -> fragmentOffset = offset; 658 | outgoingCommand -> fragmentLength = length; 659 | outgoingCommand -> packet = packet; 660 | if (packet != NULL) 661 | ++ packet -> referenceCount; 662 | 663 | enet_peer_setup_outgoing_command (peer, outgoingCommand); 664 | 665 | return outgoingCommand; 666 | } 667 | 668 | void 669 | enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel) 670 | { 671 | ENetListIterator droppedCommand, startCommand, currentCommand; 672 | 673 | for (droppedCommand = startCommand = currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands); 674 | currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); 675 | currentCommand = enet_list_next (currentCommand)) 676 | { 677 | ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; 678 | 679 | if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) 680 | continue; 681 | else 682 | if (incomingCommand -> reliableSequenceNumber != channel -> incomingReliableSequenceNumber) 683 | break; 684 | else 685 | if (incomingCommand -> fragmentsRemaining <= 0) 686 | channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber; 687 | else 688 | if (startCommand == currentCommand) 689 | startCommand = enet_list_next (currentCommand); 690 | else 691 | { 692 | enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); 693 | 694 | if (! peer -> needsDispatch) 695 | { 696 | enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); 697 | 698 | peer -> needsDispatch = 1; 699 | } 700 | 701 | droppedCommand = startCommand = enet_list_next (currentCommand); 702 | } 703 | } 704 | 705 | if (startCommand != currentCommand) 706 | { 707 | enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand)); 708 | 709 | if (! peer -> needsDispatch) 710 | { 711 | enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); 712 | 713 | peer -> needsDispatch = 1; 714 | } 715 | 716 | droppedCommand = startCommand = enet_list_next (currentCommand); 717 | } 718 | 719 | enet_peer_remove_incoming_commands (& channel -> incomingUnreliableCommands, enet_list_begin (& channel -> incomingUnreliableCommands), droppedCommand); 720 | } 721 | 722 | void 723 | enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel) 724 | { 725 | ENetListIterator currentCommand; 726 | 727 | for (currentCommand = enet_list_begin (& channel -> incomingReliableCommands); 728 | currentCommand != enet_list_end (& channel -> incomingReliableCommands); 729 | currentCommand = enet_list_next (currentCommand)) 730 | { 731 | ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; 732 | 733 | if (incomingCommand -> fragmentsRemaining > 0 || 734 | incomingCommand -> reliableSequenceNumber != (enet_uint16) (channel -> incomingReliableSequenceNumber + 1)) 735 | break; 736 | 737 | channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber; 738 | 739 | if (incomingCommand -> fragmentCount > 0) 740 | channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1; 741 | } 742 | 743 | if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands)) 744 | return; 745 | 746 | channel -> incomingUnreliableSequenceNumber = 0; 747 | 748 | enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand)); 749 | 750 | if (! peer -> needsDispatch) 751 | { 752 | enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList); 753 | 754 | peer -> needsDispatch = 1; 755 | } 756 | 757 | enet_peer_dispatch_incoming_unreliable_commands (peer, channel); 758 | } 759 | 760 | ENetIncomingCommand * 761 | enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 fragmentCount) 762 | { 763 | static ENetIncomingCommand dummyCommand; 764 | 765 | ENetChannel * channel = & peer -> channels [command -> header.channelID]; 766 | enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber = 0; 767 | enet_uint16 reliableWindow, currentWindow; 768 | ENetIncomingCommand * incomingCommand; 769 | ENetListIterator currentCommand; 770 | 771 | if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) 772 | goto freePacket; 773 | 774 | if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) 775 | { 776 | reliableSequenceNumber = command -> header.reliableSequenceNumber; 777 | reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; 778 | currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; 779 | 780 | if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber) 781 | reliableWindow += ENET_PEER_RELIABLE_WINDOWS; 782 | 783 | if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) 784 | goto freePacket; 785 | } 786 | 787 | switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) 788 | { 789 | case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: 790 | case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: 791 | if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber) 792 | goto freePacket; 793 | 794 | for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); 795 | currentCommand != enet_list_end (& channel -> incomingReliableCommands); 796 | currentCommand = enet_list_previous (currentCommand)) 797 | { 798 | incomingCommand = (ENetIncomingCommand *) currentCommand; 799 | 800 | if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) 801 | { 802 | if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) 803 | continue; 804 | } 805 | else 806 | if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) 807 | break; 808 | 809 | if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber) 810 | { 811 | if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) 812 | break; 813 | 814 | goto freePacket; 815 | } 816 | } 817 | break; 818 | 819 | case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: 820 | case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: 821 | unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber); 822 | 823 | if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber && 824 | unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber) 825 | goto freePacket; 826 | 827 | for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands)); 828 | currentCommand != enet_list_end (& channel -> incomingUnreliableCommands); 829 | currentCommand = enet_list_previous (currentCommand)) 830 | { 831 | incomingCommand = (ENetIncomingCommand *) currentCommand; 832 | 833 | if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) 834 | continue; 835 | 836 | if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) 837 | { 838 | if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) 839 | continue; 840 | } 841 | else 842 | if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) 843 | break; 844 | 845 | if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) 846 | break; 847 | 848 | if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber) 849 | continue; 850 | 851 | if (incomingCommand -> unreliableSequenceNumber <= unreliableSequenceNumber) 852 | { 853 | if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber) 854 | break; 855 | 856 | goto freePacket; 857 | } 858 | } 859 | break; 860 | 861 | case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: 862 | currentCommand = enet_list_end (& channel -> incomingUnreliableCommands); 863 | break; 864 | 865 | default: 866 | goto freePacket; 867 | } 868 | 869 | incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand)); 870 | if (incomingCommand == NULL) 871 | goto notifyError; 872 | 873 | incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber; 874 | incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; 875 | incomingCommand -> command = * command; 876 | incomingCommand -> fragmentCount = fragmentCount; 877 | incomingCommand -> fragmentsRemaining = fragmentCount; 878 | incomingCommand -> packet = packet; 879 | incomingCommand -> fragments = NULL; 880 | 881 | if (fragmentCount > 0) 882 | { 883 | if (fragmentCount <= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) 884 | incomingCommand -> fragments = (enet_uint32 *) enet_malloc ((fragmentCount + 31) / 32 * sizeof (enet_uint32)); 885 | if (incomingCommand -> fragments == NULL) 886 | { 887 | enet_free (incomingCommand); 888 | 889 | goto notifyError; 890 | } 891 | memset (incomingCommand -> fragments, 0, (fragmentCount + 31) / 32 * sizeof (enet_uint32)); 892 | } 893 | 894 | if (packet != NULL) 895 | ++ packet -> referenceCount; 896 | 897 | enet_list_insert (enet_list_next (currentCommand), incomingCommand); 898 | 899 | switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) 900 | { 901 | case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: 902 | case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: 903 | enet_peer_dispatch_incoming_reliable_commands (peer, channel); 904 | break; 905 | 906 | default: 907 | enet_peer_dispatch_incoming_unreliable_commands (peer, channel); 908 | break; 909 | } 910 | 911 | return incomingCommand; 912 | 913 | freePacket: 914 | if (fragmentCount > 0) 915 | goto notifyError; 916 | 917 | if (packet != NULL && packet -> referenceCount == 0) 918 | enet_packet_destroy (packet); 919 | 920 | return & dummyCommand; 921 | 922 | notifyError: 923 | if (packet != NULL && packet -> referenceCount == 0) 924 | enet_packet_destroy (packet); 925 | 926 | return NULL; 927 | } 928 | 929 | /** @} */ 930 | -------------------------------------------------------------------------------- /src/enet/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 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 | #endif 41 | 42 | #ifdef HAS_FCNTL 43 | #include 44 | #endif 45 | 46 | #ifdef HAS_POLL 47 | #include 48 | #endif 49 | 50 | #ifndef HAS_SOCKLEN_T 51 | typedef unsigned int socklen_t; 52 | #endif 53 | 54 | #ifndef MSG_NOSIGNAL 55 | #define MSG_NOSIGNAL 0 56 | #endif 57 | 58 | static enet_uint32 timeBase = 0; 59 | 60 | int 61 | enet_initialize (void) 62 | { 63 | return 0; 64 | } 65 | 66 | void 67 | enet_deinitialize (void) 68 | { 69 | } 70 | 71 | enet_uint32 72 | enet_time_get (void) 73 | { 74 | struct timeval timeVal; 75 | 76 | gettimeofday (& timeVal, NULL); 77 | 78 | return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase; 79 | } 80 | 81 | void 82 | enet_time_set (enet_uint32 newTimeBase) 83 | { 84 | struct timeval timeVal; 85 | 86 | gettimeofday (& timeVal, NULL); 87 | 88 | timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase; 89 | } 90 | 91 | int 92 | enet_address_set_host (ENetAddress * address, const char * name) 93 | { 94 | struct hostent * hostEntry = NULL; 95 | #ifdef HAS_GETHOSTBYNAME_R 96 | struct hostent hostData; 97 | char buffer [2048]; 98 | int errnum; 99 | 100 | #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 101 | gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); 102 | #else 103 | hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum); 104 | #endif 105 | #else 106 | hostEntry = gethostbyname (name); 107 | #endif 108 | 109 | if (hostEntry == NULL || 110 | hostEntry -> h_addrtype != AF_INET) 111 | { 112 | #ifdef HAS_INET_PTON 113 | if (! inet_pton (AF_INET, name, & address -> host)) 114 | #else 115 | if (! inet_aton (name, (struct in_addr *) & address -> host)) 116 | #endif 117 | return -1; 118 | return 0; 119 | } 120 | 121 | address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; 122 | 123 | return 0; 124 | } 125 | 126 | int 127 | enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) 128 | { 129 | #ifdef HAS_INET_NTOP 130 | if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL) 131 | #else 132 | char * addr = inet_ntoa (* (struct in_addr *) & address -> host); 133 | if (addr != NULL) 134 | strncpy (name, addr, nameLength); 135 | else 136 | #endif 137 | return -1; 138 | return 0; 139 | } 140 | 141 | int 142 | enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) 143 | { 144 | struct in_addr in; 145 | struct hostent * hostEntry = NULL; 146 | #ifdef HAS_GETHOSTBYADDR_R 147 | struct hostent hostData; 148 | char buffer [2048]; 149 | int errnum; 150 | 151 | in.s_addr = address -> host; 152 | 153 | #if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 154 | gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); 155 | #else 156 | hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum); 157 | #endif 158 | #else 159 | in.s_addr = address -> host; 160 | 161 | hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); 162 | #endif 163 | 164 | if (hostEntry == NULL) 165 | return enet_address_get_host_ip (address, name, nameLength); 166 | 167 | strncpy (name, hostEntry -> h_name, nameLength); 168 | 169 | return 0; 170 | } 171 | 172 | int 173 | enet_socket_bind (ENetSocket socket, const ENetAddress * address) 174 | { 175 | struct sockaddr_in sin; 176 | 177 | memset (& sin, 0, sizeof (struct sockaddr_in)); 178 | 179 | sin.sin_family = AF_INET; 180 | 181 | if (address != NULL) 182 | { 183 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); 184 | sin.sin_addr.s_addr = address -> host; 185 | } 186 | else 187 | { 188 | sin.sin_port = 0; 189 | sin.sin_addr.s_addr = INADDR_ANY; 190 | } 191 | 192 | return bind (socket, 193 | (struct sockaddr *) & sin, 194 | sizeof (struct sockaddr_in)); 195 | } 196 | 197 | int 198 | enet_socket_listen (ENetSocket socket, int backlog) 199 | { 200 | return listen (socket, backlog < 0 ? SOMAXCONN : backlog); 201 | } 202 | 203 | ENetSocket 204 | enet_socket_create (ENetSocketType type) 205 | { 206 | return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); 207 | } 208 | 209 | int 210 | enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) 211 | { 212 | int result = -1; 213 | switch (option) 214 | { 215 | case ENET_SOCKOPT_NONBLOCK: 216 | #ifdef HAS_FCNTL 217 | // result = fcntl (socket, F_SETFL, O_NONBLOCK | fcntl (socket, F_GETFL)); 218 | #else 219 | // result = ioctl (socket, FIONBIO, & value); 220 | #endif 221 | break; 222 | 223 | case ENET_SOCKOPT_BROADCAST: 224 | result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); 225 | break; 226 | 227 | case ENET_SOCKOPT_REUSEADDR: 228 | result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); 229 | break; 230 | 231 | case ENET_SOCKOPT_RCVBUF: 232 | result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); 233 | break; 234 | 235 | case ENET_SOCKOPT_SNDBUF: 236 | result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); 237 | break; 238 | 239 | case ENET_SOCKOPT_RCVTIMEO: 240 | result = setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO, (char *) & value, sizeof (int)); 241 | break; 242 | 243 | case ENET_SOCKOPT_SNDTIMEO: 244 | result = setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO, (char *) & value, sizeof (int)); 245 | break; 246 | 247 | default: 248 | break; 249 | } 250 | return result == -1 ? -1 : 0; 251 | } 252 | 253 | int 254 | enet_socket_connect (ENetSocket socket, const ENetAddress * address) 255 | { 256 | struct sockaddr_in sin; 257 | int result; 258 | 259 | memset (& sin, 0, sizeof (struct sockaddr_in)); 260 | 261 | sin.sin_family = AF_INET; 262 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); 263 | sin.sin_addr.s_addr = address -> host; 264 | 265 | result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); 266 | if (result == -1 && errno == EINPROGRESS) 267 | return 0; 268 | 269 | return result; 270 | } 271 | 272 | ENetSocket 273 | enet_socket_accept (ENetSocket socket, ENetAddress * address) 274 | { 275 | int result; 276 | struct sockaddr_in sin; 277 | socklen_t sinLength = sizeof (struct sockaddr_in); 278 | 279 | result = accept (socket, 280 | address != NULL ? (struct sockaddr *) & sin : NULL, 281 | address != NULL ? & sinLength : NULL); 282 | 283 | if (result == -1) 284 | return ENET_SOCKET_NULL; 285 | 286 | if (address != NULL) 287 | { 288 | address -> host = (enet_uint32) sin.sin_addr.s_addr; 289 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); 290 | } 291 | 292 | return result; 293 | } 294 | 295 | int 296 | enet_socket_shutdown (ENetSocket socket, ENetSocketShutdown how) 297 | { 298 | return shutdown (socket, (int) how); 299 | } 300 | 301 | void 302 | enet_socket_destroy (ENetSocket socket) 303 | { 304 | if (socket != -1) 305 | close (socket); 306 | } 307 | 308 | int 309 | enet_socket_send (ENetSocket socket, 310 | const ENetAddress * address, 311 | const ENetBuffer * buffers, 312 | size_t bufferCount) 313 | { 314 | struct msghdr msgHdr; 315 | struct sockaddr_in sin; 316 | int sentLength; 317 | 318 | memset (& msgHdr, 0, sizeof (struct msghdr)); 319 | 320 | if (address != NULL) 321 | { 322 | memset (& sin, 0, sizeof (struct sockaddr_in)); 323 | 324 | sin.sin_family = AF_INET; 325 | sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); 326 | sin.sin_addr.s_addr = address -> host; 327 | 328 | msgHdr.msg_name = & sin; 329 | msgHdr.msg_namelen = sizeof (struct sockaddr_in); 330 | } 331 | 332 | msgHdr.msg_iov = (struct iovec *) buffers; 333 | msgHdr.msg_iovlen = bufferCount; 334 | 335 | sentLength = sendmsg (socket, & msgHdr, MSG_NOSIGNAL); 336 | 337 | if (sentLength == -1) 338 | { 339 | if (errno == EWOULDBLOCK) 340 | return 0; 341 | 342 | return -1; 343 | } 344 | 345 | return sentLength; 346 | } 347 | 348 | int 349 | enet_socket_receive (ENetSocket socket, 350 | ENetAddress * address, 351 | ENetBuffer * buffers, 352 | size_t bufferCount) 353 | { 354 | struct msghdr msgHdr; 355 | struct sockaddr_in sin; 356 | int recvLength; 357 | 358 | memset (& msgHdr, 0, sizeof (struct msghdr)); 359 | 360 | if (address != NULL) 361 | { 362 | msgHdr.msg_name = & sin; 363 | msgHdr.msg_namelen = sizeof (struct sockaddr_in); 364 | } 365 | 366 | msgHdr.msg_iov = (struct iovec *) buffers; 367 | msgHdr.msg_iovlen = bufferCount; 368 | 369 | recvLength = recvmsg (socket, & msgHdr, MSG_NOSIGNAL); 370 | 371 | if (recvLength == -1) 372 | { 373 | if (errno == EWOULDBLOCK) 374 | return 0; 375 | 376 | return -1; 377 | } 378 | 379 | #ifdef HAS_MSGHDR_FLAGS 380 | if (msgHdr.msg_flags & MSG_TRUNC) 381 | return -1; 382 | #endif 383 | 384 | if (address != NULL) 385 | { 386 | address -> host = (enet_uint32) sin.sin_addr.s_addr; 387 | address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); 388 | } 389 | 390 | return recvLength; 391 | } 392 | 393 | int 394 | enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) 395 | { 396 | struct timeval timeVal; 397 | 398 | timeVal.tv_sec = timeout / 1000; 399 | timeVal.tv_usec = (timeout % 1000) * 1000; 400 | 401 | return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); 402 | } 403 | 404 | int 405 | enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) 406 | { 407 | #ifdef HAS_POLL 408 | struct pollfd pollSocket; 409 | int pollCount; 410 | 411 | pollSocket.fd = socket; 412 | pollSocket.events = 0; 413 | 414 | if (* condition & ENET_SOCKET_WAIT_SEND) 415 | pollSocket.events |= POLLOUT; 416 | 417 | if (* condition & ENET_SOCKET_WAIT_RECEIVE) 418 | pollSocket.events |= POLLIN; 419 | 420 | pollCount = poll (& pollSocket, 1, timeout); 421 | 422 | if (pollCount < 0) 423 | return -1; 424 | 425 | * condition = ENET_SOCKET_WAIT_NONE; 426 | 427 | if (pollCount == 0) 428 | return 0; 429 | 430 | if (pollSocket.revents & POLLOUT) 431 | * condition |= ENET_SOCKET_WAIT_SEND; 432 | 433 | if (pollSocket.revents & POLLIN) 434 | * condition |= ENET_SOCKET_WAIT_RECEIVE; 435 | 436 | return 0; 437 | #else 438 | fd_set readSet, writeSet; 439 | struct timeval timeVal; 440 | int selectCount; 441 | 442 | timeVal.tv_sec = timeout / 1000; 443 | timeVal.tv_usec = (timeout % 1000) * 1000; 444 | 445 | FD_ZERO (& readSet); 446 | FD_ZERO (& writeSet); 447 | 448 | if (* condition & ENET_SOCKET_WAIT_SEND) 449 | FD_SET (socket, & writeSet); 450 | 451 | if (* condition & ENET_SOCKET_WAIT_RECEIVE) 452 | FD_SET (socket, & readSet); 453 | 454 | selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal); 455 | 456 | if (selectCount < 0) 457 | return -1; 458 | 459 | * condition = ENET_SOCKET_WAIT_NONE; 460 | 461 | if (selectCount == 0) 462 | return 0; 463 | 464 | if (FD_ISSET (socket, & writeSet)) 465 | * condition |= ENET_SOCKET_WAIT_SEND; 466 | 467 | if (FD_ISSET (socket, & readSet)) 468 | * condition |= ENET_SOCKET_WAIT_RECEIVE; 469 | 470 | return 0; 471 | #endif 472 | } 473 | 474 | #endif 475 | 476 | -------------------------------------------------------------------------------- /src/enet_pre.js: -------------------------------------------------------------------------------- 1 | var Module; 2 | this["Module"] = Module = { 3 | "preRun": function () { 4 | Module["jsapi"] = {}; 5 | Module["jsapi"]["init"] = cwrap('jsapi_init', '', ['number']); 6 | Module["jsapi"]["enet_host_create_client"] = cwrap('jsapi_enet_host_create_client', 'number', ['number', 7 | 'number', 8 | 'number', 'number' 9 | ]); 10 | Module["jsapi"]["enet_host_create_server"] = cwrap('jsapi_enet_host_create_server', 'number', ['number', 11 | 'number', 12 | 'number', 'number', 'number', 'number' 13 | ]); 14 | Module["jsapi"]["enet_host_from_socket"] = cwrap('jsapi_enet_host_from_socket', 'number', ['number', 15 | 'number', 'number', 16 | 'number', 'number', 'number', 'number' 17 | ]); 18 | Module["jsapi"]["enet_host_bind"] = cwrap('jsapi_enet_host_bind', '', ['number']); 19 | Module["jsapi"]["host_get_socket"] = cwrap('jsapi_host_get_socket', "number", ['number']); 20 | Module["jsapi"]["host_get_receivedAddress"] = cwrap("jsapi_host_get_receivedAddress", 'number', [ 21 | 'number' 22 | ]); 23 | Module["jsapi"]["enet_host_connect"] = cwrap("jsapi_enet_host_connect", "number", ['number', 'number', 24 | 'number', 25 | 'number', 'number' 26 | ]); 27 | Module["jsapi"]["packet_get_data"] = cwrap("jsapi_packet_get_data", "number", ["number"]); 28 | Module["jsapi"]["packet_set_free_callback"] = cwrap("jsapi_packet_set_free_callback", "", ["number", 29 | "number" 30 | ]); 31 | Module["jsapi"]["packet_get_dataLength"] = cwrap("jsapi_packet_get_dataLength", "number", ["number"]); 32 | Module["jsapi"]["packet_flags"] = cwrap("jsapi_packet_flags", "number", ["number"]); 33 | Module["jsapi"]["event_new"] = cwrap('jsapi_event_new', 'number', []); 34 | Module["jsapi"]["event_free"] = cwrap('jsapi_event_free', '', ['number']); 35 | Module["jsapi"]["event_get_type"] = cwrap('jsapi_event_get_type', 'number', ['number']); 36 | Module["jsapi"]["event_get_peer"] = cwrap('jsapi_event_get_peer', 'number', ['number']); 37 | Module["jsapi"]["event_get_packet"] = cwrap('jsapi_event_get_packet', 'number', ['number']); 38 | Module["jsapi"]["event_get_data"] = cwrap('jsapi_event_get_data', 'number', ['number']); 39 | Module["jsapi"]["event_get_channelID"] = cwrap('jsapi_event_get_channelID', 'number', ['number']); 40 | Module["jsapi"]["address_get_host"] = cwrap('jsapi_address_get_host', 'number', ['number']); 41 | Module["jsapi"]["address_get_port"] = cwrap('jsapi_address_get_port', 'number', ['number']); 42 | Module["jsapi"]["peer_get_address"] = cwrap('jsapi_peer_get_address', 'number', ['number']); 43 | Module["jsapi"]["peer_get_state"] = cwrap('jsapi_peer_get_state', 'number', ['number']); 44 | Module["jsapi"]["peer_get_incomingDataTotal"] = cwrap('jsapi_peer_get_incomingDataTotal', 'number', [ 45 | 'number' 46 | ]); 47 | Module["jsapi"]["peer_get_outgoingDataTotal"] = cwrap('jsapi_peer_get_outgoingDataTotal', 'number', [ 48 | 'number' 49 | ]); 50 | 51 | Module["jsapi"]["peer_get_reliableDataInTransit"] = cwrap('jsapi_peer_get_reliableDataInTransit', 52 | 'number', [ 53 | 'number' 54 | ]); 55 | Module["libenet"] = {}; 56 | Module["libenet"]["host_service"] = cwrap("enet_host_service", 'number', ['number', 'number', 'number']); 57 | Module["libenet"]["host_destroy"] = cwrap("enet_host_destroy", '', ['number']); 58 | Module["libenet"]["host_flush"] = cwrap('enet_host_flush', "", ['number']); 59 | Module["libenet"]["host_bandwidth_throttle"] = cwrap('enet_host_bandwidth_throttle', "", ['number']); 60 | Module["libenet"]["host_broadcast"] = cwrap('enet_host_broadcast', "", ['number', 'number', 'number']); 61 | Module["libenet"]["host_compress_with_range_coder"] = cwrap('enet_host_compress_with_range_coder', 62 | "number", [ 63 | 'number' 64 | ]); 65 | Module["libenet"]["host_compress"] = cwrap('enet_host_compress', "", ['number', 'number']); 66 | Module["libenet"]["packet_create"] = cwrap("enet_packet_create", "number", ['number', 'number', 67 | 'number' 68 | ]); 69 | Module["libenet"]["packet_destroy"] = cwrap("enet_packet_destroy", '', ['number']); 70 | Module["libenet"]["peer_send"] = cwrap('enet_peer_send', 'number', ['number', 'number', 'number']); 71 | Module["libenet"]["peer_reset"] = cwrap('enet_peer_reset', '', ['number']); 72 | Module["libenet"]["peer_ping"] = cwrap('enet_peer_ping', '', ['number']); 73 | Module["libenet"]["peer_disconnect"] = cwrap('enet_peer_disconnect', '', ['number', 'number']); 74 | Module["libenet"]["peer_disconnect_now"] = cwrap('enet_peer_disconnect_now', '', ['number', 'number']); 75 | Module["libenet"]["peer_disconnect_later"] = cwrap('enet_peer_disconnect_later', '', ['number', 76 | 'number' 77 | ]); 78 | 79 | Module["Runtime_addFunction"] = Runtime.addFunction; 80 | Module["Runtime_removeFunction"] = Runtime.removeFunction; 81 | Module["HEAPU8"] = HEAPU8; 82 | Module["HEAPU32"] = HEAPU32; 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /src/jsapi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void jsapi_init(int (ENET_CALLBACK * packet_filter) (ENetHost* host)){ 9 | if(packet_filter){ 10 | ENetCallbacks callbacks = { NULL, NULL, NULL, packet_filter }; 11 | enet_initialize_with_callbacks(ENET_VERSION, &callbacks); 12 | return; 13 | } 14 | enet_initialize(); 15 | } 16 | 17 | ENetHost * 18 | jsapi_enet_host_from_socket (ENetSocket sock, const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) 19 | { 20 | ENetHost * host; 21 | ENetPeer * currentPeer; 22 | 23 | if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) 24 | return NULL; 25 | 26 | host = (ENetHost *) enet_malloc (sizeof (ENetHost)); 27 | if (host == NULL) 28 | return NULL; 29 | memset (host, 0, sizeof (ENetHost)); 30 | 31 | host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer)); 32 | if (host -> peers == NULL) 33 | { 34 | enet_free (host); 35 | 36 | return NULL; 37 | } 38 | memset (host -> peers, 0, peerCount * sizeof (ENetPeer)); 39 | 40 | host -> socket = sock; 41 | if (host -> socket == ENET_SOCKET_NULL) 42 | { 43 | enet_free (host -> peers); 44 | enet_free (host); 45 | 46 | return NULL; 47 | } 48 | 49 | if (address != NULL) 50 | host -> address = * address; 51 | 52 | if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) 53 | channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; 54 | else 55 | if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) 56 | channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; 57 | 58 | host -> randomSeed = (enet_uint32) time(NULL) + (enet_uint32) (size_t) host; 59 | host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16); 60 | host -> channelLimit = channelLimit; 61 | host -> incomingBandwidth = incomingBandwidth; 62 | host -> outgoingBandwidth = outgoingBandwidth; 63 | host -> bandwidthThrottleEpoch = 0; 64 | host -> recalculateBandwidthLimits = 0; 65 | host -> mtu = ENET_HOST_DEFAULT_MTU; 66 | host -> peerCount = peerCount; 67 | host -> commandCount = 0; 68 | host -> bufferCount = 0; 69 | host -> checksum = NULL; 70 | host -> receivedAddress.host = ENET_HOST_ANY; 71 | host -> receivedAddress.port = 0; 72 | host -> receivedData = NULL; 73 | host -> receivedDataLength = 0; 74 | 75 | host -> totalSentData = 0; 76 | host -> totalSentPackets = 0; 77 | host -> totalReceivedData = 0; 78 | host -> totalReceivedPackets = 0; 79 | 80 | host -> compressor.context = NULL; 81 | host -> compressor.compress = NULL; 82 | host -> compressor.decompress = NULL; 83 | host -> compressor.destroy = NULL; 84 | host -> isClient = 0; 85 | 86 | enet_list_clear (& host -> dispatchQueue); 87 | 88 | for (currentPeer = host -> peers; 89 | currentPeer < & host -> peers [host -> peerCount]; 90 | ++ currentPeer) 91 | { 92 | currentPeer -> host = host; 93 | currentPeer -> incomingPeerID = currentPeer - host -> peers; 94 | currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF; 95 | currentPeer -> data = NULL; 96 | 97 | enet_list_clear (& currentPeer -> acknowledgements); 98 | enet_list_clear (& currentPeer -> sentReliableCommands); 99 | enet_list_clear (& currentPeer -> sentUnreliableCommands); 100 | enet_list_clear (& currentPeer -> outgoingReliableCommands); 101 | enet_list_clear (& currentPeer -> outgoingUnreliableCommands); 102 | enet_list_clear (& currentPeer -> dispatchedCommands); 103 | 104 | enet_peer_reset (currentPeer); 105 | } 106 | 107 | return host; 108 | } 109 | 110 | ENetHost* jsapi_enet_host_create_server(unsigned int host, int port,int maxpeers, int maxchannels, int bw_down, int bw_up){ 111 | ENetAddress address; 112 | address.host = host; 113 | address.port = port; 114 | ENetSocket sock = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); 115 | 116 | return jsapi_enet_host_from_socket (sock, 117 | & address /* the address to bind the server host to */, 118 | maxpeers /* allow up to maxpeers clients and/or outgoing connections */, 119 | maxchannels /* allow up to maxchannels channels to be used, 0,1,...maxcahnnels*/, 120 | bw_down /* assume bw_in (Bytes/s) of incoming bandwidth */, 121 | bw_up /* assume bw_out (Bytes/s) of outgoing bandwidth */); 122 | } 123 | 124 | ENetHost* jsapi_enet_host_create_client(int maxconn, int maxchannels, int bw_down, int bw_up){ 125 | ENetSocket sock = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); 126 | ENetHost* host = jsapi_enet_host_from_socket (sock, 127 | NULL /*create a client - doesn't accept incoming connections*/, 128 | maxconn /* allow up to maxconn outgoing connections */, 129 | maxchannels /* allow up to maxchannels channels to be used, 0 and 1 */, 130 | bw_down /* assume bw_down (Bytes/s) incoming bandwidth */, 131 | bw_up /* assume bw_up (Bytes/s) outgoing bandwidth */); 132 | host -> isClient = 1; 133 | return host; 134 | } 135 | 136 | //only call this only for servers/custom socket 137 | void 138 | jsapi_enet_host_bind(ENetHost* host){ 139 | if(host != NULL && host -> socket != ENET_SOCKET_NULL){ 140 | enet_socket_bind (host -> socket, &(host->address)); 141 | } 142 | } 143 | 144 | ENetPeer* jsapi_enet_host_connect(ENetHost* host, unsigned int destinationHost, int port, int channelCount, int data){ 145 | ENetAddress address; 146 | address.host = destinationHost; 147 | address.port = port; 148 | return enet_host_connect(host,&address,channelCount,data); 149 | } 150 | 151 | //ENetEvent - helpers 152 | void * jsapi_event_new(){ 153 | return malloc(sizeof(ENetEvent)); 154 | } 155 | 156 | void jsapi_event_free(ENetEvent *event){ 157 | free(event); 158 | } 159 | 160 | ENetEventType jsapi_event_get_type(ENetEvent* event){ 161 | return event->type; 162 | } 163 | 164 | ENetPeer* jsapi_event_get_peer(ENetEvent* event){ 165 | return event->peer; 166 | } 167 | 168 | int jsapi_event_get_channelID(ENetEvent *event){ 169 | return event->channelID; 170 | } 171 | 172 | ENetPacket* jsapi_event_get_packet(ENetEvent* event){ 173 | return event->packet; 174 | } 175 | 176 | enet_uint32 jsapi_event_get_data(ENetEvent* event){ 177 | return event->data; 178 | } 179 | 180 | //ENetAddress - helpers 181 | enet_uint32* jsapi_address_get_host(ENetAddress* address){ 182 | //emscripten can only return signed int using the ccall so 183 | //we will return a pointer to the unsigned int and grab it 184 | //directly from memory! 185 | return &address->host; 186 | } 187 | 188 | int jsapi_address_get_port(ENetAddress* address){ 189 | return address->port; 190 | } 191 | 192 | //ENetPacket - helpers 193 | enet_uint8* jsapi_packet_get_data(ENetPacket* packet){ 194 | return packet->data; 195 | } 196 | 197 | int jsapi_packet_get_dataLength(ENetPacket* packet){ 198 | return packet->dataLength; 199 | } 200 | 201 | void jsapi_packet_set_free_callback(ENetPacket *packet, ENetPacketFreeCallback callback){ 202 | packet->freeCallback = callback; 203 | } 204 | 205 | ENetPacketFlag jsapi_packet_flags(ENetPacket *packet){ 206 | return packet -> flags; 207 | } 208 | 209 | //ENetHost - helpers 210 | ENetAddress* jsapi_host_get_receivedAddress(ENetHost *host){ 211 | return &host->receivedAddress; 212 | } 213 | 214 | int jsapi_host_get_peerCount(ENetHost* host){ 215 | return host->peerCount; 216 | } 217 | 218 | int jsapi_host_get_channelLimit(ENetHost *host){ 219 | return host->channelLimit; 220 | } 221 | 222 | unsigned char* jsapi_host_get_receivedData(ENetHost *host){ 223 | return host->receivedData; 224 | } 225 | 226 | int jsapi_host_get_receivedDataLength(ENetHost *host){ 227 | return host->receivedDataLength; 228 | } 229 | 230 | ENetSocket jsapi_host_get_socket(ENetHost* host){ 231 | return host->socket; 232 | } 233 | 234 | //ENetPeer - helpers 235 | ENetAddress* jsapi_peer_get_address(ENetPeer* peer){ 236 | return &peer->address; 237 | } 238 | 239 | int jsapi_peer_get_channelCount(ENetPeer* peer){ 240 | return peer->channelCount; 241 | } 242 | 243 | ENetPeerState jsapi_peer_get_state(ENetPeer* peer){ 244 | return peer->state; 245 | } 246 | enet_uint32 jsapi_peer_get_incomingDataTotal(ENetPeer* peer){ 247 | return peer->incomingDataTotal; 248 | } 249 | enet_uint32 jsapi_peer_get_outgoingDataTotal(ENetPeer* peer){ 250 | return peer->outgoingDataTotal; 251 | } 252 | 253 | enet_uint32 jsapi_peer_get_reliableDataInTransit(ENetPeer *peer){ 254 | return peer->reliableDataInTransit; 255 | } 256 | -------------------------------------------------------------------------------- /src/library_inet.js: -------------------------------------------------------------------------------- 1 | mergeInto(LibraryManager.library, { 2 | inet_ntop__deps: ['__setErrNo', '$ERRNO_CODES','inet_ntop4','inet_ntop6'], 3 | inet_ntop: function(af, src, dst, size){ 4 | switch(af){ 5 | case {{{ cDefine('AF_INET') }}}: 6 | return _inet_ntop4(src,dst,size); 7 | case {{{ cDefine('AF_INET6') }}}: 8 | return _inet_ntop6(src,dst,size); 9 | default: 10 | ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); 11 | return 0; 12 | } 13 | }, 14 | inet_pton__deps: ['__setErrNo', '$ERRNO_CODES','inet_pton4','inet_pton6'], 15 | inet_pton: function(af,src,dst){ 16 | switch(af){ 17 | case {{{ cDefine('AF_INET') }}}: 18 | return _inet_pton4(src,dst); 19 | case {{{ cDefine('AF_INET6') }}}: 20 | return _inet_pton6(src,dst); 21 | default: 22 | ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); 23 | return -1; 24 | } 25 | }, 26 | inet_addr: function(ptr) { 27 | var b = Pointer_stringify(ptr).split("."); 28 | if (b.length !== 4) return -1; // we return -1 for error, and otherwise a uint32. this helps inet_pton differentiate 29 | return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; 30 | }, 31 | inet_aton_raw: function(str) { 32 | var b = str.split("."); 33 | return (Number(b[0]) | (Number(b[1]) << 8) | (Number(b[2]) << 16) | (Number(b[3]) << 24)) >>> 0; 34 | }, 35 | inet_ntoa_raw: function(addr) { 36 | return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff) 37 | }, 38 | inet_ntoa__deps: ['inet_ntoa_raw'], 39 | inet_ntoa: function(in_addr) { 40 | if (!_inet_ntoa.buffer) { 41 | _inet_ntoa.buffer = _malloc(1024); 42 | } 43 | var addr = getValue(in_addr, 'i32'); 44 | var str = _inet_ntoa_raw(addr); 45 | writeStringToMemory(str.substr(0, 1024), _inet_ntoa.buffer); 46 | return _inet_ntoa.buffer; 47 | }, 48 | 49 | inet_aton__deps: ['inet_addr'], 50 | inet_aton: function(cp, inp) { 51 | var addr = _inet_addr(cp); 52 | setValue(inp, addr, 'i32'); 53 | if (addr < 0) return 0; 54 | return 1; 55 | }, 56 | 57 | inet_ntop4__deps: ['__setErrNo', '$ERRNO_CODES','inet_ntoa_raw'], 58 | inet_ntop4: function(src,dst,size){ 59 | var str = _inet_ntoa_raw(getValue(src, 'i32')); 60 | if(str.length+1 > size){ 61 | ___setErrNo(ERRNO_CODES.ENOSPC); 62 | return 0; 63 | } 64 | writeStringToMemory(str,dst); 65 | return dst; 66 | }, 67 | 68 | inet_ntop6__deps: ['__setErrNo', '$ERRNO_CODES','inet_ntop6_raw'], 69 | inet_ntop6: function(src, dst, size){ 70 | var str = _inet_ntop6_raw(src); 71 | if(str.length+1 > size){ 72 | ___setErrNo(ERRNO_CODES.ENOSPC); 73 | return 0; 74 | } 75 | writeStringToMemory(str,dst); 76 | return dst; 77 | }, 78 | inet_ntop6_raw__deps: ['htons'], 79 | inet_ntop6_raw: function(src){ 80 | var str = ""; 81 | var word=0; 82 | var longest=0; 83 | var lastzero=0; 84 | var zstart=0; 85 | var len=0; 86 | var i=0; 87 | 88 | var hasipv4 = true; 89 | var v4part = ""; 90 | for(i=0;i<10;i++){ 91 | if(HEAPU8[src+i] !== 0) {hasipv4 = false;break;} 92 | } 93 | 94 | if(hasipv4){ 95 | v4part = HEAPU8[src+12]+"."+HEAPU8[src+13]+"."+HEAPU8[src+14]+"."+HEAPU8[src+15]; 96 | if(HEAPU8[src+10]==255 && HEAPU8[src+11]==255) { 97 | str="::ffff:";//IPv4-mapped IPv6 address 98 | str+=v4part; 99 | return str; 100 | } 101 | if(HEAPU8[src+11]==0 && HEAPU8[src+11]==0){//IPv4-compatible 102 | str="::"; 103 | //loopback or any ? 104 | if(v4part == "0.0.0.0") v4part = ""; 105 | if(v4part == "0.0.0.1") v4part = "1"; 106 | str+=v4part; 107 | return str; 108 | } 109 | } 110 | 111 | //first run to find the longest consecutive zeros 112 | for(word=0;word<8;word++){ 113 | if(HEAPU16[(src+word*2)>>1]==0) { 114 | if(word - lastzero > 1){ 115 | len = 0; 116 | } 117 | lastzero = word; 118 | len++; 119 | } 120 | if(len > longest) { 121 | longest = len; 122 | zstart = word - longest + 1; 123 | } 124 | } 125 | 126 | for(word=0;word<8;word++){ 127 | if(longest>1){ 128 | if(HEAPU16[(src+word*2)>>1]==0 && word >= zstart && word < (zstart+longest) ){ 129 | if(word==zstart) { 130 | str+=":"; 131 | if(zstart==0) str+=":"; 132 | } 133 | continue; 134 | } 135 | } 136 | str+=Number(_htons(HEAPU16[(src+word*2)>>1])).toString(16); 137 | str+= word<7? ":" : ""; 138 | } 139 | return str; 140 | }, 141 | inet_pton4__deps: ['inet_addr'], 142 | inet_pton4: function(src,dst){ 143 | var ret = _inet_addr(src); 144 | if (ret == -1 || isNaN(ret)) return 0; 145 | setValue(dst, ret, 'i32'); 146 | return 1; 147 | }, 148 | inet_pton6__deps: ['inet_pton6_raw'], 149 | inet_pton6:function(src,dst){ 150 | return _inet_pton6_raw(Pointer_stringify(src),dst); 151 | }, 152 | inet_pton6_raw__deps:['htons'], 153 | inet_pton6_raw: function(addr,dst){ 154 | var words; 155 | var w,offset,z,i; 156 | /* http://home.deds.nl/~aeron/regex/ */ 157 | var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i 158 | if(!valid6regx.test(addr)){ 159 | return 0; 160 | } 161 | if(addr == "::"){ 162 | for(i=0;i<16;i++) HEAPU8[dst+i]=0; 163 | return 1; 164 | } 165 | if(addr.indexOf("::")==0){ 166 | addr = addr.replace("::","Z:"); 167 | }else{ 168 | addr = addr.replace("::",":Z:"); 169 | } 170 | 171 | if(addr.indexOf(".")>0){ 172 | addr = addr.replace(new RegExp('[.]', 'g'),":"); 173 | words = addr.split(":"); 174 | words[words.length-4] = parseInt(words[words.length-4]) + parseInt(words[words.length-3])*256; 175 | words[words.length-3] = parseInt(words[words.length-2]) + parseInt(words[words.length-1])*256; 176 | words = words.slice(0,words.length-2); 177 | }else{ 178 | words = addr.split(":"); 179 | } 180 | 181 | offset = 0; z=0; 182 | for(w=0;w>1] = 0; 187 | } 188 | offset = z-1; 189 | }else{ 190 | HEAPU16[(dst+(w+offset)*2)>>1] = _htons(parseInt(words[w],16)); 191 | } 192 | }else HEAPU16[(dst+(w+offset)*2)>>1] = words[w]; 193 | } 194 | return 1; 195 | } 196 | }); 197 | -------------------------------------------------------------------------------- /src/wrap_footer.js: -------------------------------------------------------------------------------- 1 | }).call(moduleScope); 2 | 3 | module.exports = moduleScope.Module; 4 | 5 | }).call(this); 6 | -------------------------------------------------------------------------------- /src/wrap_header.js: -------------------------------------------------------------------------------- 1 | ; 2 | (function () { 3 | //"use strict"; 4 | var moduleScope = {}; 5 | 6 | (function () { 7 | //"use strict"; 8 | // -- code generated by emscripten will follow --- 9 | --------------------------------------------------------------------------------