1 /**
2  @file host.c
3  @brief ENet host management functions
4 */
5 #define ENET_BUILDING_LIB 1
6 #include <string.h>
7 #include "enet/enet.h"
8 
9 /** @defgroup host ENet host functions
10     @{
11 */
12 
13 /** Creates a host for communicating to peers.
14 
15     @param address   the address at which other peers may connect to this host.  If NULL, then no peers may connect to the host.
16     @param peerCount the maximum number of peers that should be allocated for the host.
17     @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
18     @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
19     @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
20 
21     @returns the host on success and NULL on failure
22 
23     @remarks ENet will strategically drop packets on specific sides of a connection between hosts
24     to ensure the host's bandwidth is not overwhelmed.  The bandwidth parameters also determine
25     the window size of a connection which limits the amount of reliable packets that may be in transit
26     at any given time.
27 */
28 ENetHost *
enet_host_create(const ENetAddress * address,size_t peerCount,size_t channelLimit,enet_uint32 incomingBandwidth,enet_uint32 outgoingBandwidth)29 enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
30 {
31     ENetHost * host;
32     ENetPeer * currentPeer;
33     int i;
34 
35     if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
36       return NULL;
37 
38     host = (ENetHost *) enet_malloc (sizeof (ENetHost));
39     if (host == NULL)
40       return NULL;
41     memset (host, 0, sizeof (ENetHost));
42 
43     host -> peer_list = (ENetPeer **) enet_malloc (ENET_PROTOCOL_MAXIMUM_PEER_ID * sizeof (ENetPeer*));
44     if (host -> peer_list == NULL)
45     {
46        enet_free (host);
47 
48        return NULL;
49     }
50     for (i=0; i < peerCount; i++) {
51 	host -> peer_list[i] = enet_malloc (sizeof (ENetPeer));
52 	memset (host -> peer_list[i], 0, sizeof (ENetPeer));
53     }
54 
55     host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
56     if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0))
57     {
58        if (host -> socket != ENET_SOCKET_NULL)
59          enet_socket_destroy (host -> socket);
60 
61        for (i=0; i < peerCount; i++) {
62 	   enet_free (host -> peer_list[i]);
63        }
64        enet_free (host -> peer_list);
65        enet_free (host);
66 
67        return NULL;
68     }
69 
70     enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1);
71     enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1);
72     enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
73     enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
74 
75     if (address != NULL && enet_socket_get_address (host -> socket, & host -> address) < 0)
76       host -> address = * address;
77 
78     if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
79       channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
80     else
81     if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
82       channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
83 
84     host -> randomSeed = (enet_uint32) (size_t) host;
85     host -> randomSeed += enet_host_random_seed ();
86     host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16);
87     host -> channelLimit = channelLimit;
88     host -> incomingBandwidth = incomingBandwidth;
89     host -> outgoingBandwidth = outgoingBandwidth;
90     host -> bandwidthThrottleEpoch = 0;
91     host -> recalculateBandwidthLimits = 0;
92     host -> mtu = ENET_HOST_DEFAULT_MTU;
93     host -> peerCount = peerCount;
94     host -> commandCount = 0;
95     host -> bufferCount = 0;
96     host -> checksum = NULL;
97     host -> receivedAddress.host = ENET_HOST_ANY;
98     host -> receivedAddress.port = 0;
99     host -> receivedData = NULL;
100     host -> receivedDataLength = 0;
101 
102     host -> totalSentData = 0;
103     host -> totalSentPackets = 0;
104     host -> totalReceivedData = 0;
105     host -> totalReceivedPackets = 0;
106 
107     host -> connectedPeers = 0;
108     host -> bandwidthLimitedPeers = 0;
109     host -> duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID;
110     host -> maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE;
111     host -> maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA;
112 
113     host -> compressor.context = NULL;
114     host -> compressor.compress = NULL;
115     host -> compressor.decompress = NULL;
116     host -> compressor.destroy = NULL;
117 
118     host -> intercept = NULL;
119 
120     enet_list_clear (& host -> dispatchQueue);
121 
122     for (i = 0; i < host -> peerCount; i++ )
123     {
124        currentPeer = host -> peer_list[i];
125        currentPeer -> host = host;
126        currentPeer -> incomingPeerID = i;
127        currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF;
128        currentPeer -> data = NULL;
129 
130        enet_list_clear (& currentPeer -> acknowledgements);
131        enet_list_clear (& currentPeer -> sentReliableCommands);
132        enet_list_clear (& currentPeer -> sentUnreliableCommands);
133        enet_list_clear (& currentPeer -> outgoingReliableCommands);
134        enet_list_clear (& currentPeer -> outgoingUnreliableCommands);
135        enet_list_clear (& currentPeer -> dispatchedCommands);
136 
137        enet_peer_reset (currentPeer);
138     }
139 
140     return host;
141 }
142 
143 /** Destroys the host and all resources associated with it.
144     @param host pointer to the host to destroy
145 */
146 void
enet_host_destroy(ENetHost * host)147 enet_host_destroy (ENetHost * host)
148 {
149     ENetPeer * currentPeer;
150     int i;
151 
152     if (host == NULL)
153       return;
154 
155     enet_socket_destroy (host -> socket);
156 
157     for (i = 0; i < host -> peerCount; i++ )
158     {
159        currentPeer = host -> peer_list[i];
160        enet_peer_reset (currentPeer);
161        enet_free (currentPeer);
162        host -> peer_list[i] = NULL;
163     }
164 
165     if (host -> compressor.context != NULL && host -> compressor.destroy)
166       (* host -> compressor.destroy) (host -> compressor.context);
167 
168     enet_free (host -> peer_list);
169     enet_free (host);
170 }
171 
172 /** Initiates a connection to a foreign host.
173     @param host host seeking the connection
174     @param address destination for the connection
175     @param channelCount number of channels to allocate
176     @param data user data supplied to the receiving host
177     @returns a peer representing the foreign host on success, NULL on failure
178     @remarks The peer returned will have not completed the connection until enet_host_service()
179     notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
180 */
181 ENetPeer *
enet_host_connect(ENetHost * host,const ENetAddress * address,size_t channelCount,enet_uint32 data)182 enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data)
183 {
184     ENetPeer * currentPeer;
185     ENetChannel * channel;
186     ENetProtocol command;
187     int i;
188 
189     if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
190       channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
191     else
192     if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
193       channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
194 
195     for (i = 0; i < host -> peerCount; i++ )
196     {
197        currentPeer = host -> peer_list[i];
198 
199        if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
200          break;
201     }
202 
203     if (i >= host -> peerCount)
204     {
205 	if (i >= ENET_PROTOCOL_MAXIMUM_PEER_ID)
206 	    return NULL;
207 	host -> peerCount++;
208 	host -> peer_list[i] = enet_malloc (sizeof (ENetPeer));
209 	memset (host -> peer_list[i], 0, sizeof (ENetPeer));
210 	currentPeer = host->peer_list[i];
211 	currentPeer -> host = host;
212 	currentPeer -> incomingPeerID = i;
213 	currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF;
214 	currentPeer -> data = NULL;
215 
216 	enet_list_clear (& currentPeer -> acknowledgements);
217 	enet_list_clear (& currentPeer -> sentReliableCommands);
218 	enet_list_clear (& currentPeer -> sentUnreliableCommands);
219 	enet_list_clear (& currentPeer -> outgoingReliableCommands);
220 	enet_list_clear (& currentPeer -> outgoingUnreliableCommands);
221 	enet_list_clear (& currentPeer -> dispatchedCommands);
222 
223 	enet_peer_reset (currentPeer);
224     }
225 
226     currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
227     if (currentPeer -> channels == NULL)
228       return NULL;
229     currentPeer -> channelCount = channelCount;
230     currentPeer -> state = ENET_PEER_STATE_CONNECTING;
231     currentPeer -> address = * address;
232     currentPeer -> connectID = ++ host -> randomSeed;
233 
234     if (host -> outgoingBandwidth == 0)
235       currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
236     else
237       currentPeer -> windowSize = (host -> outgoingBandwidth /
238                                     ENET_PEER_WINDOW_SIZE_SCALE) *
239                                       ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
240 
241     if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
242       currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
243     else
244     if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
245       currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
246 
247     for (channel = currentPeer -> channels;
248          channel < & currentPeer -> channels [channelCount];
249          ++ channel)
250     {
251         channel -> outgoingReliableSequenceNumber = 0;
252         channel -> outgoingUnreliableSequenceNumber = 0;
253         channel -> incomingReliableSequenceNumber = 0;
254         channel -> incomingUnreliableSequenceNumber = 0;
255 
256         enet_list_clear (& channel -> incomingReliableCommands);
257         enet_list_clear (& channel -> incomingUnreliableCommands);
258 
259         channel -> usedReliableWindows = 0;
260         memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows));
261     }
262 
263     command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
264     command.header.channelID = 0xFF;
265     command.connect.outgoingPeerID = ENET_HOST_TO_NET_32 (currentPeer -> incomingPeerID);
266     command.connect.incomingSessionID = currentPeer -> incomingSessionID;
267     command.connect.outgoingSessionID = currentPeer -> outgoingSessionID;
268     command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu);
269     command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize);
270     command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount);
271     command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth);
272     command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
273     command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval);
274     command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration);
275     command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration);
276     command.connect.connectID = currentPeer -> connectID;
277     command.connect.data = ENET_HOST_TO_NET_32 (data);
278 
279     enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0);
280 
281     return currentPeer;
282 }
283 
284 /** Queues a packet to be sent to all peers associated with the host.
285     @param host host on which to broadcast the packet
286     @param channelID channel on which to broadcast
287     @param packet packet to broadcast
288 */
289 void
enet_host_broadcast(ENetHost * host,enet_uint8 channelID,ENetPacket * packet)290 enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet)
291 {
292     ENetPeer * currentPeer;
293     int i;
294 
295     for (i = 0; i < host -> peerCount; i++ )
296     {
297        currentPeer = host -> peer_list[i];
298 
299        if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
300          continue;
301 
302        enet_peer_send (currentPeer, channelID, packet);
303     }
304 
305     if (packet -> referenceCount == 0)
306       enet_packet_destroy (packet);
307 }
308 
309 /** Sets the packet compressor the host should use to compress and decompress packets.
310     @param host host to enable or disable compression for
311     @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled
312 */
313 void
enet_host_compress(ENetHost * host,const ENetCompressor * compressor)314 enet_host_compress (ENetHost * host, const ENetCompressor * compressor)
315 {
316     if (host -> compressor.context != NULL && host -> compressor.destroy)
317       (* host -> compressor.destroy) (host -> compressor.context);
318 
319     if (compressor)
320       host -> compressor = * compressor;
321     else
322       host -> compressor.context = NULL;
323 }
324 
325 /** Limits the maximum allowed channels of future incoming connections.
326     @param host host to limit
327     @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
328 */
329 void
enet_host_channel_limit(ENetHost * host,size_t channelLimit)330 enet_host_channel_limit (ENetHost * host, size_t channelLimit)
331 {
332     if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
333       channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
334     else
335     if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
336       channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
337 
338     host -> channelLimit = channelLimit;
339 }
340 
341 
342 /** Adjusts the bandwidth limits of a host.
343     @param host host to adjust
344     @param incomingBandwidth new incoming bandwidth
345     @param outgoingBandwidth new outgoing bandwidth
346     @remarks the incoming and outgoing bandwidth parameters are identical in function to those
347     specified in enet_host_create().
348 */
349 void
enet_host_bandwidth_limit(ENetHost * host,enet_uint32 incomingBandwidth,enet_uint32 outgoingBandwidth)350 enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
351 {
352     host -> incomingBandwidth = incomingBandwidth;
353     host -> outgoingBandwidth = outgoingBandwidth;
354     host -> recalculateBandwidthLimits = 1;
355 }
356 
357 void
enet_host_bandwidth_throttle(ENetHost * host)358 enet_host_bandwidth_throttle (ENetHost * host)
359 {
360     enet_uint32 timeCurrent = enet_time_get (),
361            elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch,
362            peersRemaining = (enet_uint32) host -> connectedPeers,
363            dataTotal = ~0,
364            bandwidth = ~0,
365            throttle = 0,
366            bandwidthLimit = 0;
367     int needsAdjustment = host -> bandwidthLimitedPeers > 0 ? 1 : 0;
368     ENetPeer * peer;
369     ENetProtocol command;
370     int i;
371 
372     if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
373       return;
374 
375     host -> bandwidthThrottleEpoch = timeCurrent;
376 
377     if (peersRemaining == 0)
378       return;
379 
380     if (host -> outgoingBandwidth != 0)
381     {
382         dataTotal = 0;
383         bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000;
384 
385 	for (i = 0; i < host -> peerCount; i++ )
386         {
387 	    peer = host -> peer_list[i];
388 
389             if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
390               continue;
391 
392             dataTotal += peer -> outgoingDataTotal;
393         }
394     }
395 
396     while (peersRemaining > 0 && needsAdjustment != 0)
397     {
398         needsAdjustment = 0;
399 
400         if (dataTotal <= bandwidth)
401           throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
402         else
403           throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
404 
405 	for (i = 0; i < host -> peerCount; i++ )
406 	{
407             enet_uint32 peerBandwidth;
408 	    peer = host -> peer_list[i];
409 
410             if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
411                 peer -> incomingBandwidth == 0 ||
412                 peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
413               continue;
414 
415             peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000;
416             if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth)
417               continue;
418 
419             peer -> packetThrottleLimit = (peerBandwidth *
420                                             ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal;
421 
422             if (peer -> packetThrottleLimit == 0)
423               peer -> packetThrottleLimit = 1;
424 
425             if (peer -> packetThrottle > peer -> packetThrottleLimit)
426               peer -> packetThrottle = peer -> packetThrottleLimit;
427 
428             peer -> outgoingBandwidthThrottleEpoch = timeCurrent;
429 
430             peer -> incomingDataTotal = 0;
431             peer -> outgoingDataTotal = 0;
432 
433             needsAdjustment = 1;
434             -- peersRemaining;
435             bandwidth -= peerBandwidth;
436             dataTotal -= peerBandwidth;
437         }
438     }
439 
440     if (peersRemaining > 0)
441     {
442         if (dataTotal <= bandwidth)
443           throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
444         else
445           throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
446 
447 	for (i = 0; i < host -> peerCount; i++ )
448 	{
449 	    peer = host -> peer_list[i];
450 
451             if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
452 		peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
453 	      continue;
454 
455 	    peer -> packetThrottleLimit = throttle;
456 
457 	    if (peer -> packetThrottle > peer -> packetThrottleLimit)
458 		peer -> packetThrottle = peer -> packetThrottleLimit;
459 
460             peer -> incomingDataTotal = 0;
461             peer -> outgoingDataTotal = 0;
462 	}
463     }
464 
465     if (host -> recalculateBandwidthLimits)
466     {
467        host -> recalculateBandwidthLimits = 0;
468 
469        peersRemaining = (enet_uint32) host -> connectedPeers;
470        bandwidth = host -> incomingBandwidth;
471        needsAdjustment = 1;
472 
473        if (bandwidth == 0)
474          bandwidthLimit = 0;
475        else
476        while (peersRemaining > 0 && needsAdjustment != 0)
477        {
478            needsAdjustment = 0;
479            bandwidthLimit = bandwidth / peersRemaining;
480 
481 	   for (i = 0; i < host -> peerCount; i++ )
482 	   {
483 	       peer = host -> peer_list[i];
484                if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
485                    peer -> incomingBandwidthThrottleEpoch == timeCurrent)
486                  continue;
487 
488                if (peer -> outgoingBandwidth > 0 &&
489                    peer -> outgoingBandwidth >= bandwidthLimit)
490                  continue;
491 
492                peer -> incomingBandwidthThrottleEpoch = timeCurrent;
493 
494                needsAdjustment = 1;
495                -- peersRemaining;
496                bandwidth -= peer -> outgoingBandwidth;
497            }
498        }
499 
500        for (i = 0; i < host -> peerCount; i++ )
501        {
502 	   peer = host -> peer_list[i];
503 
504            if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
505              continue;
506 
507            command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
508            command.header.channelID = 0xFF;
509            command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
510 
511            if (peer -> incomingBandwidthThrottleEpoch == timeCurrent)
512              command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth);
513            else
514              command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit);
515 
516            enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
517        }
518     }
519 }
520 
521 /** @} */
522