123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- /**
- *
- * Copyright (C) 2011 by Leaf Corcoran
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include <stdlib.h>
- #include <string.h>
- extern "C" {
- #define LUA_COMPAT_ALL
- #include "lua.h"
- #include "lualib.h"
- #include "lauxlib.h"
- #include <enet/enet.h>
- }
- #define check_host(l, idx)\
- *(ENetHost**)luaL_checkudata(l, idx, "enet_host")
- #define check_peer(l, idx)\
- *(ENetPeer**)luaL_checkudata(l, idx, "enet_peer")
- /**
- * Parse address string, eg:
- * *:5959
- * 127.0.0.1:*
- * website.com:8080
- */
- static void parse_address(lua_State *l, const char *addr_str, ENetAddress *address) {
- int host_i = 0, port_i = 0;
- char host_str[128] = {0};
- char port_str[32] = {0};
- int scanning_port = 0;
- char *c = (char *)addr_str;
- while (*c != 0) {
- if (host_i >= 128 || port_i >= 32 ) luaL_error(l, "Hostname too long");
- if (scanning_port) {
- port_str[port_i++] = *c;
- } else {
- if (*c == ':') {
- scanning_port = 1;
- } else {
- host_str[host_i++] = *c;
- }
- }
- c++;
- }
- host_str[host_i] = '\0';
- port_str[port_i] = '\0';
- if (host_i == 0) luaL_error(l, "Failed to parse address");
- if (port_i == 0) luaL_error(l, "Missing port in address");
- if (strcmp("*", host_str) == 0) {
- address->host = ENET_HOST_ANY;
- } else {
- if (enet_address_set_host(address, host_str) != 0) {
- luaL_error(l, "Failed to resolve host name");
- }
- }
- if (strcmp("*", port_str) == 0) {
- address->port = ENET_PORT_ANY;
- } else {
- address->port = atoi(port_str);
- }
- }
- /**
- * Find the index of a given peer for which we only have the pointer.
- */
- static size_t find_peer_index(lua_State *l, ENetHost *enet_host, ENetPeer *peer) {
- size_t peer_index;
- for (peer_index = 0; peer_index < enet_host->peerCount; peer_index++) {
- if (peer == &(enet_host->peers[peer_index]))
- return peer_index;
- }
- luaL_error (l, "enet: could not find peer id!");
- return peer_index;
- }
- static void push_peer(lua_State *l, ENetPeer *peer) {
- // try to find in peer table
- lua_getfield(l, LUA_REGISTRYINDEX, "enet_peers");
- lua_pushlightuserdata(l, peer);
- lua_gettable(l, -2);
- if (lua_isnil(l, -1)) {
- // printf("creating new peer\n");
- lua_pop(l, 1);
- *(ENetPeer**)lua_newuserdata(l, sizeof(void*)) = peer;
- luaL_getmetatable(l, "enet_peer");
- lua_setmetatable(l, -2);
- lua_pushlightuserdata(l, peer);
- lua_pushvalue(l, -2);
- lua_settable(l, -4);
- }
- lua_remove(l, -2); // remove enet_peers
- }
- static void push_event(lua_State *l, ENetEvent *event) {
- lua_newtable(l); // event table
- if (event->peer) {
- push_peer(l, event->peer);
- lua_setfield(l, -2, "peer");
- }
- switch (event->type) {
- case ENET_EVENT_TYPE_CONNECT:
- lua_pushinteger(l, event->data);
- lua_setfield(l, -2, "data");
- lua_pushstring(l, "connect");
- break;
- case ENET_EVENT_TYPE_DISCONNECT:
- lua_pushinteger(l, event->data);
- lua_setfield(l, -2, "data");
- lua_pushstring(l, "disconnect");
- break;
- case ENET_EVENT_TYPE_RECEIVE:
- lua_pushlstring(l, (const char *)event->packet->data, event->packet->dataLength);
- lua_setfield(l, -2, "data");
- lua_pushinteger(l, event->channelID);
- lua_setfield(l, -2, "channel");
- lua_pushstring(l, "receive");
- enet_packet_destroy(event->packet);
- break;
- case ENET_EVENT_TYPE_NONE:
- lua_pushstring(l, "none");
- break;
- }
- lua_setfield(l, -2, "type");
- }
- /**
- * Read a packet off the stack as a string
- * idx is position of string
- */
- static ENetPacket *read_packet(lua_State *l, int idx, enet_uint8 *channel_id) {
- size_t size;
- int argc = lua_gettop(l);
- const void *data = luaL_checklstring(l, idx, &size);
- ENetPacket *packet;
- enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE;
- *channel_id = 0;
- if (argc >= idx+2 && !lua_isnil(l, idx+2)) {
- const char *flag_str = luaL_checkstring(l, idx+2);
- if (strcmp("unsequenced", flag_str) == 0) {
- flags = ENET_PACKET_FLAG_UNSEQUENCED;
- } else if (strcmp("reliable", flag_str) == 0) {
- flags = ENET_PACKET_FLAG_RELIABLE;
- } else if (strcmp("unreliable", flag_str) == 0) {
- flags = 0;
- } else {
- luaL_error(l, "Unknown packet flag: %s", flag_str);
- }
- }
- if (argc >= idx+1 && !lua_isnil(l, idx+1)) {
- *channel_id = luaL_checkint(l, idx+1);
- }
- packet = enet_packet_create(data, size, flags);
- if (packet == NULL) {
- luaL_error(l, "Failed to create packet");
- }
- return packet;
- }
- /**
- * Create a new host
- * Args:
- * address (nil for client)
- * [peer_count = 64]
- * [channel_count = 1]
- * [in_bandwidth = 0]
- * [out_bandwidth = 0]
- */
- static int host_create(lua_State *l) {
- ENetHost *host;
- size_t peer_count = 64, channel_count = 1;
- enet_uint32 in_bandwidth = 0, out_bandwidth = 0;
- int have_address = 1;
- ENetAddress address;
- if (lua_gettop(l) == 0 || lua_isnil(l, 1)) {
- have_address = 0;
- } else {
- parse_address(l, luaL_checkstring(l, 1), &address);
- }
- switch (lua_gettop(l)) {
- case 5:
- if (!lua_isnil(l, 5)) out_bandwidth = luaL_checkint(l, 5);
- case 4:
- if (!lua_isnil(l, 4)) in_bandwidth = luaL_checkint(l, 4);
- case 3:
- if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3);
- case 2:
- if (!lua_isnil(l, 2)) peer_count = luaL_checkint(l, 2);
- }
- // printf("host create, peers=%d, channels=%d, in=%d, out=%d\n",
- // peer_count, channel_count, in_bandwidth, out_bandwidth);
- host = enet_host_create(have_address ? &address : NULL, peer_count,
- channel_count, in_bandwidth, out_bandwidth);
- if (host == NULL) {
- lua_pushnil (l);
- lua_pushstring(l, "enet: failed to create host (already listening?)");
- return 2;
- }
- *(ENetHost**)lua_newuserdata(l, sizeof(void*)) = host;
- luaL_getmetatable(l, "enet_host");
- lua_setmetatable(l, -2);
- return 1;
- }
- static int linked_version(lua_State *l) {
- lua_pushfstring(l, "%d.%d.%d",
- ENET_VERSION_GET_MAJOR(enet_linked_version()),
- ENET_VERSION_GET_MINOR(enet_linked_version()),
- ENET_VERSION_GET_PATCH(enet_linked_version()));
- return 1;
- }
- /**
- * Serice a host
- * Args:
- * timeout
- *
- * Return
- * nil on no event
- * an event table on event
- */
- static int host_service(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- ENetEvent event;
- int timeout = 0, out;
- if (lua_gettop(l) > 1)
- timeout = luaL_checkint(l, 2);
- out = enet_host_service(host, &event, timeout);
- if (out == 0) return 0;
- if (out < 0) return luaL_error(l, "Error during service");
- push_event(l, &event);
- return 1;
- }
- /**
- * Dispatch a single event if available
- */
- static int host_check_events(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- ENetEvent event;
- int out = enet_host_check_events(host, &event);
- if (out == 0) return 0;
- if (out < 0) return luaL_error(l, "Error checking event");
- push_event(l, &event);
- return 1;
- }
- /**
- * Enables an adaptive order-2 PPM range coder for the transmitted data of
- * all peers.
- */
- static int host_compress_with_range_coder(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- int result = enet_host_compress_with_range_coder (host);
- if (result == 0) {
- lua_pushboolean (l, 1);
- } else {
- lua_pushboolean (l, 0);
- }
- return 1;
- }
- /**
- * Connect a host to an address
- * Args:
- * the address
- * [channel_count = 1]
- * [data = 0]
- */
- static int host_connect(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- ENetAddress address;
- ENetPeer *peer;
- enet_uint32 data = 0;
- size_t channel_count = 1;
- parse_address(l, luaL_checkstring(l, 2), &address);
- switch (lua_gettop(l)) {
- case 4:
- if (!lua_isnil(l, 4)) data = luaL_checkint(l, 4);
- case 3:
- if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3);
- }
- // printf("host connect, channels=%d, data=%d\n", channel_count, data);
- peer = enet_host_connect(host, &address, channel_count, data);
- if (peer == NULL) {
- return luaL_error(l, "Failed to create peer");
- }
- push_peer(l, peer);
- return 1;
- }
- static int host_flush(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- enet_host_flush(host);
- return 0;
- }
- static int host_broadcast(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- enet_uint8 channel_id;
- ENetPacket *packet = read_packet(l, 2, &channel_id);
- enet_host_broadcast(host, channel_id, packet);
- return 0;
- }
- // Args: limit:number
- static int host_channel_limit(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- int limit = luaL_checkint(l, 2);
- enet_host_channel_limit(host, limit);
- return 0;
- }
- static int host_bandwidth_limit(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- enet_uint32 in_bandwidth = luaL_checkint(l, 2);
- enet_uint32 out_bandwidth = luaL_checkint(l, 2);
- enet_host_bandwidth_limit(host, in_bandwidth, out_bandwidth);
- return 0;
- }
- static int host_socket_get_address(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- ENetAddress address;
- enet_socket_get_address (host->socket, &address);
- lua_pushfstring(l, "%d.%d.%d.%d:%d",
- ((address.host) & 0xFF),
- ((address.host >> 8) & 0xFF),
- ((address.host >> 16) & 0xFF),
- (address.host >> 24& 0xFF),
- address.port);
- return 1;
- }
- static int host_total_sent_data(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- lua_pushinteger (l, host->totalSentData);
- return 1;
- }
- static int host_total_received_data(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- lua_pushinteger (l, host->totalReceivedData);
- return 1;
- }
- static int host_service_time(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- lua_pushinteger (l, host->serviceTime);
- return 1;
- }
- static int host_peer_count(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- lua_pushinteger (l, host->peerCount);
- return 1;
- }
- static int host_get_peer(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- int peer_index = luaL_checkint(l, 2) - 1;
- if (peer_index < 0 || ((size_t) peer_index) >= host->peerCount) {
- luaL_argerror (l, 2, "Invalid peer index");
- }
- ENetPeer *peer = &(host->peers[peer_index]);
- push_peer (l, peer);
- return 1;
- }
- static int host_gc(lua_State *l) {
- ENetHost *host = check_host(l, 1);
- enet_host_destroy(host);
- return 0;
- }
- static int peer_tostring(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- char host_str[128];
- enet_address_get_host_ip(&peer->address, host_str, 128);
- lua_pushstring(l, host_str);
- lua_pushstring(l, ":");
- lua_pushinteger(l, peer->address.port);
- lua_concat(l, 3);
- return 1;
- }
- static int peer_ping(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_peer_ping(peer);
- return 0;
- }
- static int peer_throttle_configure(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_uint32 interval = luaL_checkint(l, 2);
- enet_uint32 acceleration = luaL_checkint(l, 3);
- enet_uint32 deceleration = luaL_checkint(l, 4);
- enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
- return 0;
- }
- static int peer_round_trip_time(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- if (lua_gettop(l) > 1) {
- enet_uint32 round_trip_time = luaL_checkint(l, 2);
- peer->roundTripTime = round_trip_time;
- }
- lua_pushinteger (l, peer->roundTripTime);
- return 1;
- }
- static int peer_last_round_trip_time(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- if (lua_gettop(l) > 1) {
- enet_uint32 round_trip_time = luaL_checkint(l, 2);
- peer->lastRoundTripTime = round_trip_time;
- }
- lua_pushinteger (l, peer->lastRoundTripTime);
- return 1;
- }
- static int peer_ping_interval(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- if (lua_gettop(l) > 1) {
- enet_uint32 interval = luaL_checkint(l, 2);
- enet_peer_ping_interval (peer, interval);
- }
- lua_pushinteger (l, peer->pingInterval);
- return 1;
- }
- static int peer_timeout(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_uint32 timeout_limit = 0;
- enet_uint32 timeout_minimum = 0;
- enet_uint32 timeout_maximum = 0;
- switch (lua_gettop(l)) {
- case 4:
- if (!lua_isnil(l, 4)) timeout_maximum = luaL_checkint(l, 4);
- case 3:
- if (!lua_isnil(l, 3)) timeout_minimum = luaL_checkint(l, 3);
- case 2:
- if (!lua_isnil(l, 2)) timeout_limit = luaL_checkint(l, 2);
- }
- enet_peer_timeout (peer, timeout_limit, timeout_minimum, timeout_maximum);
- lua_pushinteger (l, peer->timeoutLimit);
- lua_pushinteger (l, peer->timeoutMinimum);
- lua_pushinteger (l, peer->timeoutMaximum);
- return 3;
- }
- static int peer_disconnect(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
- enet_peer_disconnect(peer, data);
- return 0;
- }
- static int peer_disconnect_now(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
- enet_peer_disconnect_now(peer, data);
- return 0;
- }
- static int peer_disconnect_later(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
- enet_peer_disconnect_later(peer, data);
- return 0;
- }
- static int peer_index(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- size_t peer_index = find_peer_index (l, peer->host, peer);
- lua_pushinteger (l, peer_index + 1);
- return 1;
- }
- static int peer_state(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- switch (peer->state) {
- case (ENET_PEER_STATE_DISCONNECTED):
- lua_pushstring (l, "disconnected");
- break;
- case (ENET_PEER_STATE_CONNECTING):
- lua_pushstring (l, "connecting");
- break;
- case (ENET_PEER_STATE_ACKNOWLEDGING_CONNECT):
- lua_pushstring (l, "acknowledging_connect");
- break;
- case (ENET_PEER_STATE_CONNECTION_PENDING):
- lua_pushstring (l, "connection_pending");
- break;
- case (ENET_PEER_STATE_CONNECTION_SUCCEEDED):
- lua_pushstring (l, "connection_succeeded");
- break;
- case (ENET_PEER_STATE_CONNECTED):
- lua_pushstring (l, "connected");
- break;
- case (ENET_PEER_STATE_DISCONNECT_LATER):
- lua_pushstring (l, "disconnect_later");
- break;
- case (ENET_PEER_STATE_DISCONNECTING):
- lua_pushstring (l, "disconnecting");
- break;
- case (ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT):
- lua_pushstring (l, "acknowledging_disconnect");
- break;
- case (ENET_PEER_STATE_ZOMBIE):
- lua_pushstring (l, "zombie");
- break;
- default:
- lua_pushstring (l, "unknown");
- }
- return 1;
- }
- static int peer_connect_id(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- lua_pushinteger (l, peer->connectID);
- return 1;
- }
- static int peer_reset(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_peer_reset(peer);
- return 0;
- }
- static int peer_receive(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- ENetPacket *packet;
- enet_uint8 channel_id = 0;
- if (lua_gettop(l) > 1) {
- channel_id = luaL_checkint(l, 2);
- }
- packet = enet_peer_receive(peer, &channel_id);
- if (packet == NULL) return 0;
- lua_pushlstring(l, (const char *)packet->data, packet->dataLength);
- lua_pushinteger(l, channel_id);
- enet_packet_destroy(packet);
- return 2;
- }
- /**
- * Send a lua string to a peer
- * Args:
- * packet data, string
- * channel id
- * flags ["reliable", nil]
- *
- */
- static int peer_send(lua_State *l) {
- ENetPeer *peer = check_peer(l, 1);
- enet_uint8 channel_id;
- ENetPacket *packet = read_packet(l, 2, &channel_id);
- // printf("sending, channel_id=%d\n", channel_id);
- enet_peer_send(peer, channel_id, packet);
- return 0;
- }
- static const struct luaL_Reg enet_funcs [] = {
- {"host_create", host_create},
- {"linked_version", linked_version},
- {NULL, NULL}
- };
- static const struct luaL_Reg enet_host_funcs [] = {
- {"service", host_service},
- {"check_events", host_check_events},
- {"compress_with_range_coder", host_compress_with_range_coder},
- {"connect", host_connect},
- {"flush", host_flush},
- {"broadcast", host_broadcast},
- {"channel_limit", host_channel_limit},
- {"bandwidth_limit", host_bandwidth_limit},
- {"socket_get_address", host_socket_get_address},
- // additional convenience functions (mostly accessors)
- {"total_sent_data", host_total_sent_data},
- {"total_received_data", host_total_received_data},
- {"service_time", host_service_time},
- {"peer_count", host_peer_count},
- {"get_peer", host_get_peer},
- {NULL, NULL}
- };
- static const struct luaL_Reg enet_peer_funcs [] = {
- {"disconnect", peer_disconnect},
- {"disconnect_now", peer_disconnect_now},
- {"disconnect_later", peer_disconnect_later},
- {"reset", peer_reset},
- {"ping", peer_ping},
- {"receive", peer_receive},
- {"send", peer_send},
- {"throttle_configure", peer_throttle_configure},
- {"ping_interval", peer_ping_interval},
- {"timeout", peer_timeout},
- // additional convenience functions to member variables
- {"index", peer_index},
- {"state", peer_state},
- {"connect_id", peer_connect_id},
- {"round_trip_time", peer_round_trip_time},
- {"last_round_trip_time", peer_last_round_trip_time},
- {NULL, NULL}
- };
- int luaopen_enet(lua_State *l) {
- enet_initialize();
- atexit(enet_deinitialize);
- // create metatables
- luaL_newmetatable(l, "enet_host");
- lua_newtable(l); // index
- luaL_register(l, NULL, enet_host_funcs);
- lua_setfield(l, -2, "__index");
- lua_pushcfunction(l, host_gc);
- lua_setfield(l, -2, "__gc");
- luaL_newmetatable(l, "enet_peer");
- lua_newtable(l);
- luaL_register(l, NULL, enet_peer_funcs);
- lua_setfield(l, -2, "__index");
- lua_pushcfunction(l, peer_tostring);
- lua_setfield(l, -2, "__tostring");
- // set up peer table
- lua_newtable(l);
- lua_newtable(l); // metatable
- lua_pushstring(l, "v");
- lua_setfield(l, -2, "__mode");
- lua_setmetatable(l, -2);
- lua_setfield(l, LUA_REGISTRYINDEX, "enet_peers");
- luaL_register(l, "enet", enet_funcs);
- // return the enet table created with luaL_register
- return 1;
- }
|