1/**
2 *
3 * Copyright (C) 2014 by Leaf Corcoran
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifdef _WIN32
25#define NOMINMAX
26#endif
27
28#include <stdlib.h>
29#include <string.h>
30#include <math.h>
31#include <stdint.h>
32
33#include <cstdio>
34#include <cstddef>
35#include <algorithm>
36
37extern "C" {
38#define LUA_COMPAT_ALL
39#include "lua.h"
40#include "lualib.h"
41#include "lauxlib.h"
42#include <enet/enet.h>
43}
44
45#define check_host(l, idx)\
46 *(ENetHost**)luaL_checkudata(l, idx, "enet_host")
47
48#define check_peer(l, idx)\
49 *(ENetPeer**)luaL_checkudata(l, idx, "enet_peer")
50
51/**
52 * Parse address string, eg:
53 * *:5959
54 * 127.0.0.1:*
55 * website.com:8080
56 */
57static void parse_address(lua_State *l, const char *addr_str, ENetAddress *address) {
58 int host_i = 0, port_i = 0;
59 char host_str[128] = {0};
60 char port_str[32] = {0};
61 int scanning_port = 0;
62
63 char *c = (char *)addr_str;
64
65 while (*c != 0) {
66 if (host_i >= 128 || port_i >= 32 ) luaL_error(l, "Hostname too long");
67 if (scanning_port) {
68 port_str[port_i++] = *c;
69 } else {
70 if (*c == ':') {
71 scanning_port = 1;
72 } else {
73 host_str[host_i++] = *c;
74 }
75 }
76 c++;
77 }
78 host_str[host_i] = '\0';
79 port_str[port_i] = '\0';
80
81 if (host_i == 0) luaL_error(l, "Failed to parse address");
82 if (port_i == 0) luaL_error(l, "Missing port in address");
83
84 if (strcmp("*", host_str) == 0) {
85 address->host = ENET_HOST_ANY;
86 } else {
87 if (enet_address_set_host(address, host_str) != 0) {
88 luaL_error(l, "Failed to resolve host name");
89 }
90 }
91
92 if (strcmp("*", port_str) == 0) {
93 address->port = ENET_PORT_ANY;
94 } else {
95 address->port = atoi(port_str);
96 }
97}
98
99/**
100 * Find the index of a given peer for which we only have the pointer.
101 */
102static size_t find_peer_index(lua_State *l, ENetHost *enet_host, ENetPeer *peer) {
103 size_t peer_index;
104 for (peer_index = 0; peer_index < enet_host->peerCount; peer_index++) {
105 if (peer == &(enet_host->peers[peer_index]))
106 return peer_index;
107 }
108
109 luaL_error (l, "enet: could not find peer id!");
110
111 return peer_index;
112}
113
114// VS2013 doesn't support alignof
115#if defined(_MSC_VER) && _MSC_VER <= 1800
116#define ENET_ALIGNOF(x) __alignof(x)
117#else
118#define ENET_ALIGNOF(x) alignof(x)
119#endif
120
121static bool supports_full_lightuserdata(lua_State *L)
122{
123 static bool checked = false;
124 static bool supported = false;
125
126 if (sizeof(void*) == 4)
127 // 32-bit platforms always supports full-lightuserdata.
128 return true;
129
130 if (!checked)
131 {
132 lua_pushcclosure(L, [](lua_State* L) -> int
133 {
134 // Try to push pointer with all bits set.
135 lua_pushlightuserdata(L, (void*)(~((size_t)0)));
136 return 1;
137 }, 0);
138
139 supported = lua_pcall(L, 0, 1, 0) == 0;
140 checked = true;
141
142 lua_pop(L, 1);
143 }
144
145 return supported;
146}
147
148static uintptr_t compute_peer_key(lua_State *L, ENetPeer *peer)
149{
150 // ENet peers are be allocated on the heap in an array. Lua numbers
151 // (doubles) can store all possible integers up to 2^53. We can store
152 // pointers that use more than 53 bits if their alignment is guaranteed to
153 // be more than 1. For example an alignment requirement of 8 means we can
154 // shift the pointer's bits by 3.
155
156 // Please see these for the reason of this ternary operator:
157 // * https://github.com/love2d/love/issues/1916
158 // * https://github.com/love2d/love/commit/4ab9a1ce8c
159 const size_t minalign = sizeof(void*) == 8 ? std::min(ENET_ALIGNOF(ENetPeer), ENET_ALIGNOF(std::max_align_t)) : 1;
160 uintptr_t key = (uintptr_t) peer;
161
162 if ((key & (minalign - 1)) != 0)
163 {
164 luaL_error(L, "Cannot push enet peer to Lua: unexpected alignment "
165 "(pointer is %p but alignment should be %d)", peer, minalign);
166 }
167
168 static const size_t shift = (size_t) log2((double) minalign);
169
170 return key >> shift;
171}
172
173static void push_peer_key(lua_State *L, uintptr_t key)
174{
175 // If full 64-bit lightuserdata is supported (or it's 32-bit platform),
176 // always use that. Otherwise, if the key is smaller than 2^53 (which is
177 // integer precision for double datatype) on 64-bit platform, then push
178 // number. Otherwise, throw error.
179 if (supports_full_lightuserdata(L))
180 lua_pushlightuserdata(L, (void*) key);
181#if UINTPTR_MAX == 0xffffffffffffffff
182 else if (key > 0x20000000000000ULL) // 2^53
183 luaL_error(L, "Cannot push enet peer to Lua: pointer value %p is too large", key);
184#endif
185 else
186 lua_pushnumber(L, (lua_Number) key);
187}
188
189static void push_peer(lua_State *l, ENetPeer *peer) {
190 uintptr_t key = compute_peer_key(l, peer);
191
192 // try to find in peer table
193 lua_getfield(l, LUA_REGISTRYINDEX, "enet_peers");
194 push_peer_key(l, key);
195 lua_gettable(l, -2);
196
197 if (lua_isnil(l, -1)) {
198 // printf("creating new peer\n");
199 lua_pop(l, 1);
200
201 *(ENetPeer**)lua_newuserdata(l, sizeof(void*)) = peer;
202 luaL_getmetatable(l, "enet_peer");
203 lua_setmetatable(l, -2);
204
205 push_peer_key(l, key);
206 lua_pushvalue(l, -2);
207
208 lua_settable(l, -4);
209 }
210 lua_remove(l, -2); // remove enet_peers
211}
212
213static void push_event(lua_State *l, ENetEvent *event) {
214 lua_newtable(l); // event table
215
216 if (event->peer) {
217 push_peer(l, event->peer);
218 lua_setfield(l, -2, "peer");
219 }
220
221 switch (event->type) {
222 case ENET_EVENT_TYPE_CONNECT:
223 lua_pushinteger(l, event->data);
224 lua_setfield(l, -2, "data");
225
226 lua_pushstring(l, "connect");
227 break;
228 case ENET_EVENT_TYPE_DISCONNECT:
229 lua_pushinteger(l, event->data);
230 lua_setfield(l, -2, "data");
231
232 lua_pushstring(l, "disconnect");
233 break;
234 case ENET_EVENT_TYPE_RECEIVE:
235 lua_pushlstring(l, (const char *)event->packet->data, event->packet->dataLength);
236 lua_setfield(l, -2, "data");
237
238 lua_pushinteger(l, event->channelID);
239 lua_setfield(l, -2, "channel");
240
241 lua_pushstring(l, "receive");
242
243 enet_packet_destroy(event->packet);
244 break;
245 case ENET_EVENT_TYPE_NONE:
246 lua_pushstring(l, "none");
247 break;
248 }
249
250 lua_setfield(l, -2, "type");
251}
252
253/**
254 * Read a packet off the stack as a string
255 * idx is position of string
256 */
257static ENetPacket *read_packet(lua_State *l, int idx, enet_uint8 *channel_id) {
258 size_t size;
259 int argc = lua_gettop(l);
260 const void *data = luaL_checklstring(l, idx, &size);
261 ENetPacket *packet;
262
263 enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE;
264 *channel_id = 0;
265
266 if (argc >= idx+2 && !lua_isnil(l, idx+2)) {
267 const char *flag_str = luaL_checkstring(l, idx+2);
268 if (strcmp("unsequenced", flag_str) == 0) {
269 flags = ENET_PACKET_FLAG_UNSEQUENCED;
270 } else if (strcmp("reliable", flag_str) == 0) {
271 flags = ENET_PACKET_FLAG_RELIABLE;
272 } else if (strcmp("unreliable", flag_str) == 0) {
273 flags = 0;
274 } else {
275 luaL_error(l, "Unknown packet flag: %s", flag_str);
276 }
277 }
278
279 if (argc >= idx+1 && !lua_isnil(l, idx+1)) {
280 *channel_id = (int) luaL_checknumber(l, idx+1);
281 }
282
283 packet = enet_packet_create(data, size, flags);
284 if (packet == NULL) {
285 luaL_error(l, "Failed to create packet");
286 }
287
288 return packet;
289}
290
291/**
292 * Create a new host
293 * Args:
294 * address (nil for client)
295 * [peer_count = 64]
296 * [channel_count = 1]
297 * [in_bandwidth = 0]
298 * [out_bandwidth = 0]
299 */
300static int host_create(lua_State *l) {
301 ENetHost *host;
302 size_t peer_count = 64, channel_count = 1;
303 enet_uint32 in_bandwidth = 0, out_bandwidth = 0;
304
305 int have_address = 1;
306 ENetAddress address;
307
308 if (lua_gettop(l) == 0 || lua_isnil(l, 1)) {
309 have_address = 0;
310 } else {
311 parse_address(l, luaL_checkstring(l, 1), &address);
312 }
313
314 switch (lua_gettop(l)) {
315 case 5:
316 if (!lua_isnil(l, 5)) out_bandwidth = (int) luaL_checknumber(l, 5);
317 case 4:
318 if (!lua_isnil(l, 4)) in_bandwidth = (int) luaL_checknumber(l, 4);
319 case 3:
320 if (!lua_isnil(l, 3)) channel_count = (int) luaL_checknumber(l, 3);
321 case 2:
322 if (!lua_isnil(l, 2)) peer_count = (int) luaL_checknumber(l, 2);
323 }
324
325 // printf("host create, peers=%d, channels=%d, in=%d, out=%d\n",
326 // peer_count, channel_count, in_bandwidth, out_bandwidth);
327 host = enet_host_create(have_address ? &address : NULL, peer_count,
328 channel_count, in_bandwidth, out_bandwidth);
329
330 if (host == NULL) {
331 lua_pushnil (l);
332 lua_pushstring(l, "enet: failed to create host (already listening?)");
333 return 2;
334 }
335
336 *(ENetHost**)lua_newuserdata(l, sizeof(void*)) = host;
337 luaL_getmetatable(l, "enet_host");
338 lua_setmetatable(l, -2);
339
340 return 1;
341}
342
343static int linked_version(lua_State *l) {
344 lua_pushfstring(l, "%d.%d.%d",
345 ENET_VERSION_GET_MAJOR(enet_linked_version()),
346 ENET_VERSION_GET_MINOR(enet_linked_version()),
347 ENET_VERSION_GET_PATCH(enet_linked_version()));
348 return 1;
349}
350
351/**
352 * Serice a host
353 * Args:
354 * timeout
355 *
356 * Return
357 * nil on no event
358 * an event table on event
359 */
360static int host_service(lua_State *l) {
361 ENetHost *host = check_host(l, 1);
362 if (!host) {
363 return luaL_error(l, "Tried to index a nil host!");
364 }
365 ENetEvent event;
366 int timeout = 0, out;
367
368 if (lua_gettop(l) > 1)
369 timeout = (int) luaL_checknumber(l, 2);
370
371 out = enet_host_service(host, &event, timeout);
372 if (out == 0) return 0;
373 if (out < 0) return luaL_error(l, "Error during service");
374
375 push_event(l, &event);
376 return 1;
377}
378
379/**
380 * Dispatch a single event if available
381 */
382static int host_check_events(lua_State *l) {
383 ENetHost *host = check_host(l, 1);
384 if (!host) {
385 return luaL_error(l, "Tried to index a nil host!");
386 }
387 ENetEvent event;
388 int out = enet_host_check_events(host, &event);
389 if (out == 0) return 0;
390 if (out < 0) return luaL_error(l, "Error checking event");
391
392 push_event(l, &event);
393 return 1;
394}
395
396/**
397 * Enables an adaptive order-2 PPM range coder for the transmitted data of
398 * all peers.
399 */
400static int host_compress_with_range_coder(lua_State *l) {
401 ENetHost *host = check_host(l, 1);
402 if (!host) {
403 return luaL_error(l, "Tried to index a nil host!");
404 }
405
406 int result = enet_host_compress_with_range_coder (host);
407 if (result == 0) {
408 lua_pushboolean (l, 1);
409 } else {
410 lua_pushboolean (l, 0);
411 }
412
413 return 1;
414}
415
416/**
417 * Connect a host to an address
418 * Args:
419 * the address
420 * [channel_count = 1]
421 * [data = 0]
422 */
423static int host_connect(lua_State *l) {
424 ENetHost *host = check_host(l, 1);
425 if (!host) {
426 return luaL_error(l, "Tried to index a nil host!");
427 }
428 ENetAddress address;
429 ENetPeer *peer;
430
431 enet_uint32 data = 0;
432 size_t channel_count = 1;
433
434 parse_address(l, luaL_checkstring(l, 2), &address);
435
436 switch (lua_gettop(l)) {
437 case 4:
438 if (!lua_isnil(l, 4)) data = (int) luaL_checknumber(l, 4);
439 case 3:
440 if (!lua_isnil(l, 3)) channel_count = (int) luaL_checknumber(l, 3);
441 }
442
443 // printf("host connect, channels=%d, data=%d\n", channel_count, data);
444 peer = enet_host_connect(host, &address, channel_count, data);
445
446 if (peer == NULL) {
447 return luaL_error(l, "Failed to create peer");
448 }
449
450 push_peer(l, peer);
451
452 return 1;
453}
454
455static int host_flush(lua_State *l) {
456 ENetHost *host = check_host(l, 1);
457 if (!host) {
458 return luaL_error(l, "Tried to index a nil host!");
459 }
460 enet_host_flush(host);
461 return 0;
462}
463
464static int host_broadcast(lua_State *l) {
465 ENetHost *host = check_host(l, 1);
466 if (!host) {
467 return luaL_error(l, "Tried to index a nil host!");
468 }
469
470 enet_uint8 channel_id;
471 ENetPacket *packet = read_packet(l, 2, &channel_id);
472 enet_host_broadcast(host, channel_id, packet);
473 return 0;
474}
475
476// Args: limit:number
477static int host_channel_limit(lua_State *l) {
478 ENetHost *host = check_host(l, 1);
479 if (!host) {
480 return luaL_error(l, "Tried to index a nil host!");
481 }
482 int limit = (int) luaL_checknumber(l, 2);
483 enet_host_channel_limit(host, limit);
484 return 0;
485}
486
487static int host_bandwidth_limit(lua_State *l) {
488 ENetHost *host = check_host(l, 1);
489 if (!host) {
490 return luaL_error(l, "Tried to index a nil host!");
491 }
492 enet_uint32 in_bandwidth = (int) luaL_checknumber(l, 2);
493 enet_uint32 out_bandwidth = (int) luaL_checknumber(l, 2);
494 enet_host_bandwidth_limit(host, in_bandwidth, out_bandwidth);
495 return 0;
496}
497
498static int host_get_socket_address(lua_State *l) {
499 ENetHost *host = check_host(l, 1);
500 if (!host) {
501 return luaL_error(l, "Tried to index a nil host!");
502 }
503 ENetAddress address;
504 enet_socket_get_address (host->socket, &address);
505
506 lua_pushfstring(l, "%d.%d.%d.%d:%d",
507 ((address.host) & 0xFF),
508 ((address.host >> 8) & 0xFF),
509 ((address.host >> 16) & 0xFF),
510 (address.host >> 24& 0xFF),
511 address.port);
512 return 1;
513}
514static int host_total_sent_data(lua_State *l) {
515 ENetHost *host = check_host(l, 1);
516 if (!host) {
517 return luaL_error(l, "Tried to index a nil host!");
518 }
519
520 lua_pushinteger (l, host->totalSentData);
521
522 return 1;
523}
524
525static int host_total_received_data(lua_State *l) {
526 ENetHost *host = check_host(l, 1);
527 if (!host) {
528 return luaL_error(l, "Tried to index a nil host!");
529 }
530
531 lua_pushinteger (l, host->totalReceivedData);
532
533 return 1;
534}
535static int host_service_time(lua_State *l) {
536 ENetHost *host = check_host(l, 1);
537 if (!host) {
538 return luaL_error(l, "Tried to index a nil host!");
539 }
540
541 lua_pushinteger (l, host->serviceTime);
542
543 return 1;
544}
545
546static int host_peer_count(lua_State *l) {
547 ENetHost *host = check_host(l, 1);
548 if (!host) {
549 return luaL_error(l, "Tried to index a nil host!");
550 }
551
552 lua_pushinteger (l, host->peerCount);
553
554 return 1;
555}
556
557static int host_get_peer(lua_State *l) {
558 ENetHost *host = check_host(l, 1);
559 if (!host) {
560 return luaL_error(l, "Tried to index a nil host!");
561 }
562
563 int peer_index = (int) luaL_checknumber(l, 2) - 1;
564
565 if (peer_index < 0 || ((size_t) peer_index) >= host->peerCount) {
566 luaL_argerror (l, 2, "Invalid peer index");
567 }
568
569 ENetPeer *peer = &(host->peers[peer_index]);
570
571 push_peer (l, peer);
572 return 1;
573}
574
575static int host_gc(lua_State *l) {
576 // We have to manually grab the userdata so that we can set it to NULL.
577 ENetHost** host = (ENetHost**)luaL_checkudata(l, 1, "enet_host");
578 // We don't want to crash by destroying a non-existant host.
579 if (*host) {
580 enet_host_destroy(*host);
581 }
582 *host = NULL;
583 return 0;
584}
585
586static int peer_tostring(lua_State *l) {
587 ENetPeer *peer = check_peer(l, 1);
588 char host_str[128];
589 enet_address_get_host_ip(&peer->address, host_str, 128);
590
591 lua_pushstring(l, host_str);
592 lua_pushstring(l, ":");
593 lua_pushinteger(l, peer->address.port);
594 lua_concat(l, 3);
595 return 1;
596}
597
598static int peer_ping(lua_State *l) {
599 ENetPeer *peer = check_peer(l, 1);
600 enet_peer_ping(peer);
601 return 0;
602}
603
604static int peer_throttle_configure(lua_State *l) {
605 ENetPeer *peer = check_peer(l, 1);
606
607 enet_uint32 interval = (int) luaL_checknumber(l, 2);
608 enet_uint32 acceleration = (int) luaL_checknumber(l, 3);
609 enet_uint32 deceleration = (int) luaL_checknumber(l, 4);
610
611 enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
612 return 0;
613}
614
615static int peer_round_trip_time(lua_State *l) {
616 ENetPeer *peer = check_peer(l, 1);
617
618 if (lua_gettop(l) > 1) {
619 enet_uint32 round_trip_time = (int) luaL_checknumber(l, 2);
620 peer->roundTripTime = round_trip_time;
621 }
622
623 lua_pushinteger (l, peer->roundTripTime);
624
625 return 1;
626}
627
628static int peer_last_round_trip_time(lua_State *l) {
629 ENetPeer *peer = check_peer(l, 1);
630
631 if (lua_gettop(l) > 1) {
632 enet_uint32 round_trip_time = (int) luaL_checknumber(l, 2);
633 peer->lastRoundTripTime = round_trip_time;
634 }
635 lua_pushinteger (l, peer->lastRoundTripTime);
636
637 return 1;
638}
639
640static int peer_ping_interval(lua_State *l) {
641 ENetPeer *peer = check_peer(l, 1);
642
643 if (lua_gettop(l) > 1) {
644 enet_uint32 interval = (int) luaL_checknumber(l, 2);
645 enet_peer_ping_interval (peer, interval);
646 }
647
648 lua_pushinteger (l, peer->pingInterval);
649
650 return 1;
651}
652
653static int peer_timeout(lua_State *l) {
654 ENetPeer *peer = check_peer(l, 1);
655
656 enet_uint32 timeout_limit = 0;
657 enet_uint32 timeout_minimum = 0;
658 enet_uint32 timeout_maximum = 0;
659
660 switch (lua_gettop(l)) {
661 case 4:
662 if (!lua_isnil(l, 4)) timeout_maximum = (int) luaL_checknumber(l, 4);
663 case 3:
664 if (!lua_isnil(l, 3)) timeout_minimum = (int) luaL_checknumber(l, 3);
665 case 2:
666 if (!lua_isnil(l, 2)) timeout_limit = (int) luaL_checknumber(l, 2);
667 }
668
669 enet_peer_timeout (peer, timeout_limit, timeout_minimum, timeout_maximum);
670
671 lua_pushinteger (l, peer->timeoutLimit);
672 lua_pushinteger (l, peer->timeoutMinimum);
673 lua_pushinteger (l, peer->timeoutMaximum);
674
675 return 3;
676}
677
678static int peer_disconnect(lua_State *l) {
679 ENetPeer *peer = check_peer(l, 1);
680
681 enet_uint32 data = lua_gettop(l) > 1 ? (int) luaL_checknumber(l, 2) : 0;
682 enet_peer_disconnect(peer, data);
683 return 0;
684}
685
686static int peer_disconnect_now(lua_State *l) {
687 ENetPeer *peer = check_peer(l, 1);
688
689 enet_uint32 data = lua_gettop(l) > 1 ? (int) luaL_checknumber(l, 2) : 0;
690 enet_peer_disconnect_now(peer, data);
691 return 0;
692}
693
694static int peer_disconnect_later(lua_State *l) {
695 ENetPeer *peer = check_peer(l, 1);
696
697 enet_uint32 data = lua_gettop(l) > 1 ? (int) luaL_checknumber(l, 2) : 0;
698 enet_peer_disconnect_later(peer, data);
699 return 0;
700}
701
702static int peer_index(lua_State *l) {
703 ENetPeer *peer = check_peer(l, 1);
704
705 size_t peer_index = find_peer_index (l, peer->host, peer);
706 lua_pushinteger (l, peer_index + 1);
707
708 return 1;
709}
710
711static int peer_state(lua_State *l) {
712 ENetPeer *peer = check_peer(l, 1);
713
714 switch (peer->state) {
715 case (ENET_PEER_STATE_DISCONNECTED):
716 lua_pushstring (l, "disconnected");
717 break;
718 case (ENET_PEER_STATE_CONNECTING):
719 lua_pushstring (l, "connecting");
720 break;
721 case (ENET_PEER_STATE_ACKNOWLEDGING_CONNECT):
722 lua_pushstring (l, "acknowledging_connect");
723 break;
724 case (ENET_PEER_STATE_CONNECTION_PENDING):
725 lua_pushstring (l, "connection_pending");
726 break;
727 case (ENET_PEER_STATE_CONNECTION_SUCCEEDED):
728 lua_pushstring (l, "connection_succeeded");
729 break;
730 case (ENET_PEER_STATE_CONNECTED):
731 lua_pushstring (l, "connected");
732 break;
733 case (ENET_PEER_STATE_DISCONNECT_LATER):
734 lua_pushstring (l, "disconnect_later");
735 break;
736 case (ENET_PEER_STATE_DISCONNECTING):
737 lua_pushstring (l, "disconnecting");
738 break;
739 case (ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT):
740 lua_pushstring (l, "acknowledging_disconnect");
741 break;
742 case (ENET_PEER_STATE_ZOMBIE):
743 lua_pushstring (l, "zombie");
744 break;
745 default:
746 lua_pushstring (l, "unknown");
747 }
748
749 return 1;
750}
751
752static int peer_connect_id(lua_State *l) {
753 ENetPeer *peer = check_peer(l, 1);
754
755 lua_pushinteger (l, peer->connectID);
756
757 return 1;
758}
759
760
761static int peer_reset(lua_State *l) {
762 ENetPeer *peer = check_peer(l, 1);
763 enet_peer_reset(peer);
764 return 0;
765}
766
767static int peer_receive(lua_State *l) {
768 ENetPeer *peer = check_peer(l, 1);
769 ENetPacket *packet;
770 enet_uint8 channel_id = 0;
771
772 if (lua_gettop(l) > 1) {
773 channel_id = (int) luaL_checknumber(l, 2);
774 }
775
776 packet = enet_peer_receive(peer, &channel_id);
777 if (packet == NULL) return 0;
778
779 lua_pushlstring(l, (const char *)packet->data, packet->dataLength);
780 lua_pushinteger(l, channel_id);
781
782 enet_packet_destroy(packet);
783 return 2;
784}
785
786
787/**
788 * Send a lua string to a peer
789 * Args:
790 * packet data, string
791 * channel id
792 * flags ["reliable", nil]
793 *
794 */
795static int peer_send(lua_State *l) {
796 ENetPeer *peer = check_peer(l, 1);
797
798 enet_uint8 channel_id;
799 ENetPacket *packet = read_packet(l, 2, &channel_id);
800
801 // printf("sending, channel_id=%d\n", channel_id);
802 int ret = enet_peer_send(peer, channel_id, packet);
803 if (ret < 0) {
804 enet_packet_destroy(packet);
805 }
806
807 lua_pushinteger(l, ret);
808
809 return 1;
810}
811
812static const struct luaL_Reg enet_funcs [] = {
813 {"host_create", host_create},
814 {"linked_version", linked_version},
815 {NULL, NULL}
816};
817
818static const struct luaL_Reg enet_host_funcs [] = {
819 {"service", host_service},
820 {"check_events", host_check_events},
821 {"compress_with_range_coder", host_compress_with_range_coder},
822 {"connect", host_connect},
823 {"flush", host_flush},
824 {"broadcast", host_broadcast},
825 {"channel_limit", host_channel_limit},
826 {"bandwidth_limit", host_bandwidth_limit},
827 // Since ENetSocket isn't part of enet-lua, we should try to keep
828 // naming conventions the same as the rest of the lib.
829 {"get_socket_address", host_get_socket_address},
830 // We need this function to free up our ports when needed!
831 {"destroy", host_gc},
832
833 // additional convenience functions (mostly accessors)
834 {"total_sent_data", host_total_sent_data},
835 {"total_received_data", host_total_received_data},
836 {"service_time", host_service_time},
837 {"peer_count", host_peer_count},
838 {"get_peer", host_get_peer},
839 {NULL, NULL}
840};
841
842static const struct luaL_Reg enet_peer_funcs [] = {
843 {"disconnect", peer_disconnect},
844 {"disconnect_now", peer_disconnect_now},
845 {"disconnect_later", peer_disconnect_later},
846 {"reset", peer_reset},
847 {"ping", peer_ping},
848 {"receive", peer_receive},
849 {"send", peer_send},
850 {"throttle_configure", peer_throttle_configure},
851 {"ping_interval", peer_ping_interval},
852 {"timeout", peer_timeout},
853
854 // additional convenience functions to member variables
855 {"index", peer_index},
856 {"state", peer_state},
857 {"connect_id", peer_connect_id},
858 {"round_trip_time", peer_round_trip_time},
859 {"last_round_trip_time", peer_last_round_trip_time},
860 {NULL, NULL}
861};
862
863extern "C" {
864 void luax_register(lua_State *L, const char *name, const luaL_Reg *l);
865}
866
867int luaopen_enet(lua_State *l) {
868 enet_initialize();
869 atexit(enet_deinitialize);
870
871 // create metatables
872 luaL_newmetatable(l, "enet_host");
873 lua_newtable(l); // index
874 luax_register(l, NULL, enet_host_funcs);
875 lua_setfield(l, -2, "__index");
876 lua_pushcfunction(l, host_gc);
877 lua_setfield(l, -2, "__gc");
878
879 luaL_newmetatable(l, "enet_peer");
880 lua_newtable(l);
881 luax_register(l, NULL, enet_peer_funcs);
882 lua_setfield(l, -2, "__index");
883 lua_pushcfunction(l, peer_tostring);
884 lua_setfield(l, -2, "__tostring");
885
886 // set up peer table
887 lua_newtable(l);
888
889 lua_newtable(l); // metatable
890 lua_pushstring(l, "v");
891 lua_setfield(l, -2, "__mode");
892 lua_setmetatable(l, -2);
893
894 lua_setfield(l, LUA_REGISTRYINDEX, "enet_peers");
895
896 luax_register(l, nullptr, enet_funcs);
897
898 // return the enet table created with luaL_register
899 return 1;
900}
901