leaf corcoran 14 年之前
当前提交
b437b472f6
共有 4 个文件被更改,包括 364 次插入0 次删除
  1. 2 0
      .gitignore
  2. 7 0
      Makefile
  3. 3 0
      README.md
  4. 352 0
      enet.c

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+enet.so
+/*.lua

+ 7 - 0
Makefile

@@ -0,0 +1,7 @@
+
+LIBS = -lenet -llua
+GCC = gcc
+
+enet.so: enet.c
+	$(GCC) -o $@ -fpic -shared $< $(LIBS)
+

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+# lua-enet
+
+Provides a binding to [enet](http://enet.bespin.org/) for lua.

+ 352 - 0
enet.c

@@ -0,0 +1,352 @@
+
+#include <stdlib.h>
+
+#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);
+	}
+}
+
+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
+}
+
+/**
+ * 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;
+	const void *data = luaL_checklstring(l, idx, &size);
+
+	enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE;
+	*channel_id = 0;
+
+	int argc = lua_gettop(l);
+	if (argc >= idx+2) { /* flags */ } 
+	if (argc >= idx+1) { 
+		*channel_id = luaL_checkint(l, 3);
+	}
+
+	ENetPacket *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)
+ */
+static int host_create(lua_State *l) {
+	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:
+			out_bandwidth = luaL_checkint(l, 5);
+		case 4:
+			in_bandwidth = luaL_checkint(l, 4);
+		case 3:
+			channel_count = luaL_checkint(l, 3);
+		case 2:
+			peer_count = luaL_checkint(l, 2);
+	}
+
+	ENetHost *host = enet_host_create(have_address ? &address : NULL, peer_count,
+			channel_count, in_bandwidth, out_bandwidth);
+
+	if (host == NULL) {
+		return luaL_error(l, "Failed to create host");
+	}
+
+	*(ENetHost**)lua_newuserdata(l, sizeof(void*)) = host;
+	luaL_getmetatable(l, "enet_host");
+	lua_setmetatable(l, -2);
+
+	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);
+	int timeout = 0;
+
+	if (lua_gettop(l) > 1) 
+		timeout = luaL_checkint(l, 2);
+
+	ENetEvent event;
+	int out = enet_host_service(host, &event, timeout);
+	if (out == 0) return 0;
+	if (out < 0) return luaL_error(l, "Error during service");
+
+	// extract event and return it
+	lua_newtable(l);
+
+	push_peer(l, event.peer);
+	lua_setfield(l, -2, "peer");
+
+	switch (event.type) {
+		case ENET_EVENT_TYPE_CONNECT:
+			lua_pushstring(l, "connect");
+			break;
+		case ENET_EVENT_TYPE_DISCONNECT:
+			lua_pushstring(l, "disconnect");
+			break;
+		case ENET_EVENT_TYPE_RECEIVE:
+			lua_pushlstring(l, event.packet->data, event.packet->dataLength);
+			lua_setfield(l, -2, "data");
+			lua_pushstring(l, "receive");
+			break;
+	}
+	lua_setfield(l, -2, "type");
+	return 1;
+}
+
+/**
+ * Connect a host to an address
+ * Args:
+ * 	the address
+ */
+static int host_connect(lua_State *l) {
+	ENetHost *host = check_host(l, 1);
+	ENetAddress address;
+
+	enet_uint32 data = 0;
+	size_t channel_count = 1;
+	
+	parse_address(l, luaL_checkstring(l, 2), &address);
+
+	switch (lua_gettop(l)) {
+	}
+
+	ENetPeer *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;
+}
+
+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_disconnect(lua_State *l) {
+	ENetPeer *peer = check_peer(l, 1);
+
+	enet_uint32 data = 0;
+	if (lua_gettop(l) > 1) {
+		data = luaL_checkint(l, 2);
+	}
+
+	enet_peer_disconnect(peer, data);
+	return 0;
+}
+
+
+/**
+ * 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);
+
+	enet_peer_send(peer, channel_id, packet);
+	return 0;
+}
+
+static const struct luaL_Reg enet_funcs [] = {
+	{"host_create", host_create},
+	{NULL, NULL}
+};
+
+static const struct luaL_Reg enet_host_funcs [] = {
+	{"service", host_service},
+	{"connect", host_connect},
+	{"broadcast", host_broadcast},
+	{"flush", host_flush},
+	{NULL, NULL}
+};
+
+static const struct luaL_Reg enet_peer_funcs [] = {
+	{"disconnect", peer_disconnect},
+	{"send", peer_send},
+	{NULL, NULL}
+};
+
+static const struct luaL_Reg enet_event_funcs [] = {
+	{NULL, NULL}
+};
+
+LUALIB_API 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);
+	printf("loaded enet\n");
+	return 0;
+}
+