Files
skynet/lualib-src/lua-cluster.c
2014-06-18 15:09:15 +08:00

206 lines
4.4 KiB
C

#include <lua.h>
#include <lauxlib.h>
#include <string.h>
#include "skynet.h"
/*
uint32_t/string addr
uint32_t/session session
lightuserdata msg
uint32_t sz
return
string request
uint32_t next_session
*/
#define TEMP_LENGTH 0x10002
static void
fill_uint32(uint8_t * buf, uint32_t n) {
buf[0] = n & 0xff;
buf[1] = (n >> 8) & 0xff;
buf[2] = (n >> 16) & 0xff;
buf[3] = (n >> 24) & 0xff;
}
static void
fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) {
if (sz >= 0x10000) {
skynet_free(msg);
luaL_error(L, "request message is too long %d", sz);
}
buf[0] = (sz >> 8) & 0xff;
buf[1] = sz & 0xff;
}
static void
packreq_number(lua_State *L, int session, void * msg, size_t sz) {
uint32_t addr = lua_tounsigned(L,1);
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+9, msg);
buf[2] = 0;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
memcpy(buf+11,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+11);
}
static void
packreq_string(lua_State *L, int session, void * msg, size_t sz) {
size_t namelen = 0;
const char *name = lua_tolstring(L, 1, &namelen);
if (name == NULL || namelen < 1 || namelen > 255) {
skynet_free(msg);
luaL_error(L, "name is too long %s", name);
}
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+5+namelen, msg);
buf[2] = (uint8_t)namelen;
memcpy(buf+3, name, namelen);
fill_uint32(buf+3+namelen, (uint32_t)session);
memcpy(buf+7+namelen,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+7+namelen);
}
static int
lpackrequest(lua_State *L) {
void *msg = lua_touserdata(L,3);
if (msg == NULL) {
return luaL_error(L, "Invalid request message");
}
size_t sz = luaL_checkunsigned(L,4);
int session = luaL_checkinteger(L,2);
if (session <= 0) {
return luaL_error(L, "Invalid request session %d", session);
}
int addr_type = lua_type(L,1);
if (addr_type == LUA_TNUMBER) {
packreq_number(L, session, msg, sz);
} else {
packreq_string(L, session, msg, sz);
}
if (++session < 0) {
session = 1;
}
skynet_free(msg);
lua_pushinteger(L, session);
return 2;
}
/*
string packed message
return
uint32_t or string addr
int session
string msg
*/
static inline uint32_t
unpack_uint32(const uint8_t * buf) {
return buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24;
}
static int
unpackreq_number(lua_State *L, const uint8_t * buf, size_t sz) {
if (sz < 9) {
return luaL_error(L, "Invalid cluster message");
}
uint32_t address = unpack_uint32(buf+1);
uint32_t session = unpack_uint32(buf+5);
lua_pushunsigned(L, address);
lua_pushunsigned(L, session);
lua_pushlstring(L, (const char *)buf+9, sz-9);
return 3;
}
static int
unpackreq_string(lua_State *L, const uint8_t * buf, size_t sz) {
size_t namesz = buf[0];
if (sz < namesz + 5) {
return luaL_error(L, "Invalid cluster message");
}
lua_pushlstring(L, (const char *)buf+1, namesz);
uint32_t session = unpack_uint32(buf + namesz + 1);
lua_pushunsigned(L, session);
lua_pushlstring(L, (const char *)buf+1+namesz+4, sz - namesz - 5);
return 3;
}
static int
lunpackrequest(lua_State *L) {
size_t sz;
const char *msg = luaL_checklstring(L,1,&sz);
if (msg[0] == 0) {
return unpackreq_number(L, (const uint8_t *)msg, sz);
} else {
return unpackreq_string(L, (const uint8_t *)msg, sz);
}
}
/*
int session
lightuserdata msg
int sz
return string response
*/
static int
lpackresponse(lua_State *L) {
uint32_t session = luaL_checkunsigned(L,1);
// clusterd.lua:command.socket call lpackresponse,
// and the msg/sz is return by skynet.rawcall , so don't free(msg)
void * msg = lua_touserdata(L,2);
size_t sz = luaL_checkunsigned(L, 3);
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+4, msg);
fill_uint32(buf+2, session);
memcpy(buf+6,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+6);
return 1;
}
/*
string packed response
return integer session
boolean ok
string msg
*/
static int
lunpackresponse(lua_State *L) {
size_t sz;
const char * buf = luaL_checklstring(L, 1, &sz);
if (sz < 4) {
return 0;
}
uint32_t session = unpack_uint32((const uint8_t *)buf);
lua_pushunsigned(L, session);
lua_pushboolean(L, 1);
lua_pushlstring(L, buf+4, sz-4);
return 3;
}
int
luaopen_cluster_c(lua_State *L) {
luaL_Reg l[] = {
{ "packrequest", lpackrequest },
{ "unpackrequest", lunpackrequest },
{ "packresponse", lpackresponse },
{ "unpackresponse", lunpackresponse },
{ NULL, NULL },
};
luaL_checkversion(L);
luaL_newlib(L,l);
return 1;
}