#include "skynet_malloc.h" #include #include #include #include #include #include #include #include "skynet_socket.h" #include "service_lua.h" #define BACKLOG 32 // 2 ** 12 == 4096 #define LARGE_PAGE_NODE 12 struct buffer_node { char * msg; int sz; struct buffer_node *next; }; struct socket_buffer { int size; int offset; struct buffer_node *head; struct buffer_node *tail; }; static int lfreepool(lua_State *L) { struct buffer_node * pool = lua_touserdata(L, 1); int sz = lua_rawlen(L,1) / sizeof(*pool); int i; for (i=0;imsg) { skynet_free(node->msg); node->msg = NULL; } } return 0; } static int lnewpool(lua_State *L, int sz) { struct buffer_node * pool = lua_newuserdata(L, sizeof(struct buffer_node) * sz); int i; for (i=0;isize = 0; sb->offset = 0; sb->head = NULL; sb->tail = NULL; return 1; } /* userdata send_buffer table pool lightuserdata msg int size return size */ static int lpushbuffer(lua_State *L) { struct socket_buffer *sb = lua_touserdata(L,1); if (sb == NULL) { return luaL_error(L, "need buffer object at param 1"); } char * msg = lua_touserdata(L,3); if (msg == NULL) { return luaL_error(L, "need message block at param 3"); } int pool_index = 2; luaL_checktype(L,pool_index,LUA_TTABLE); int sz = luaL_checkinteger(L,4); lua_rawgeti(L,pool_index,1); struct buffer_node * free_node = lua_touserdata(L,-1); // sb poolt msg size free_node lua_pop(L,1); if (free_node == NULL) { int tsz = lua_rawlen(L,pool_index); if (tsz == 0) tsz++; int size = 8; if (tsz <= LARGE_PAGE_NODE-3) { size <<= tsz; } else { size <<= LARGE_PAGE_NODE-3; } lnewpool(L, size); free_node = lua_touserdata(L,-1); lua_rawseti(L, pool_index, tsz+1); } lua_pushlightuserdata(L, free_node->next); lua_rawseti(L, pool_index, 1); // sb poolt msg size free_node->msg = msg; free_node->sz = sz; free_node->next = NULL; if (sb->head == NULL) { assert(sb->tail == NULL); sb->head = sb->tail = free_node; } else { sb->tail->next = free_node; sb->tail = free_node; } sb->size += sz; lua_pushinteger(L, sb->size); return 1; } static void return_free_node(lua_State *L, int pool, struct socket_buffer *sb) { struct buffer_node *free_node = sb->head; sb->offset = 0; sb->head = free_node->next; if (sb->head == NULL) { sb->tail = NULL; } lua_rawgeti(L,pool,1); free_node->next = lua_touserdata(L,-1); lua_pop(L,1); skynet_free(free_node->msg); free_node->msg = NULL; free_node->sz = 0; lua_pushlightuserdata(L, free_node); lua_rawseti(L, pool, 1); } static void pop_lstring(lua_State *L, struct socket_buffer *sb, int sz, int skip) { struct buffer_node * current = sb->head; if (sz < current->sz - sb->offset) { lua_pushlstring(L, current->msg + sb->offset, sz-skip); sb->offset+=sz; return; } if (sz == current->sz - sb->offset) { lua_pushlstring(L, current->msg + sb->offset, sz-skip); return_free_node(L,2,sb); return; } luaL_Buffer b; luaL_buffinit(L, &b); for (;;) { int bytes = current->sz - sb->offset; if (bytes >= sz) { if (sz > skip) { luaL_addlstring(&b, current->msg + sb->offset, sz - skip); } sb->offset += sz; if (bytes == sz) { return_free_node(L,2,sb); } break; } luaL_addlstring(&b, current->msg + sb->offset, (sz - skip < bytes) ? sz - skip : bytes); return_free_node(L,2,sb); sz-=bytes; if (sz==0) break; current = sb->head; assert(current); } luaL_pushresult(&b); } /* userdata send_buffer table pool integer sz */ static int lpopbuffer(lua_State *L) { struct socket_buffer * sb = lua_touserdata(L, 1); if (sb == NULL) { return luaL_error(L, "Need buffer object at param 1"); } luaL_checktype(L,2,LUA_TTABLE); int sz = luaL_checkinteger(L,3); if (sb->size < sz || sz == 0) { lua_pushnil(L); } else { pop_lstring(L,sb,sz,0); sb->size -= sz; } lua_pushinteger(L, sb->size); return 2; } /* userdata send_buffer table pool */ static int lclearbuffer(lua_State *L) { struct socket_buffer * sb = lua_touserdata(L, 1); if (sb == NULL) { return luaL_error(L, "Need buffer object at param 1"); } luaL_checktype(L,2,LUA_TTABLE); while(sb->head) { return_free_node(L,2,sb); } return 0; } static int lreadall(lua_State *L) { struct socket_buffer * sb = lua_touserdata(L, 1); if (sb == NULL) { return luaL_error(L, "Need buffer object at param 1"); } luaL_checktype(L,2,LUA_TTABLE); luaL_Buffer b; luaL_buffinit(L, &b); while(sb->head) { struct buffer_node *current = sb->head; luaL_addlstring(&b, current->msg + sb->offset, current->sz - sb->offset); return_free_node(L,2,sb); } luaL_pushresult(&b); return 1; } static int ldrop(lua_State *L) { void * msg = lua_touserdata(L,1); luaL_checkinteger(L,2); skynet_free(msg); return 0; } static bool check_sep(struct buffer_node * node, int from, const char *sep, int seplen) { for (;;) { int sz = node->sz - from; if (sz >= seplen) { return memcmp(node->msg+from,sep,seplen) == 0; } if (sz > 0) { if (memcmp(node->msg + from, sep, sz)) { return false; } } node = node->next; sep += sz; seplen -= sz; from = 0; } } /* userdata send_buffer table pool , nil for check string sep */ static int lreadline(lua_State *L) { struct socket_buffer * sb = lua_touserdata(L, 1); if (sb == NULL) { return luaL_error(L, "Need buffer object at param 1"); } // only check bool check = !lua_istable(L, 2); size_t seplen = 0; const char *sep = luaL_checklstring(L,3,&seplen); int i; struct buffer_node *current = sb->head; if (current == NULL) return 0; int from = sb->offset; int bytes = current->sz - from; for (i=0;i<=sb->size - (int)seplen;i++) { if (check_sep(current, from, sep, seplen)) { if (check) { lua_pushboolean(L,true); } else { pop_lstring(L, sb, i+seplen, seplen); sb->size -= i+seplen; } return 1; } ++from; --bytes; if (bytes == 0) { current = current->next; from = 0; if (current == NULL) break; bytes = current->sz; } } return 0; } static int lstr2p(lua_State *L) { size_t sz = 0; const char * str = luaL_checklstring(L,1,&sz); void *ptr = skynet_malloc(sz); memcpy(ptr, str, sz); lua_pushlightuserdata(L, ptr); lua_pushinteger(L, (int)sz); return 2; } // for skynet socket /* lightuserdata msg integer size return type n1 n2 ptr_or_string */ static int lunpack(lua_State *L) { struct skynet_socket_message *message = lua_touserdata(L,1); int size = luaL_checkinteger(L,2); lua_pushinteger(L, message->type); lua_pushinteger(L, message->id); lua_pushinteger(L, message->ud); if (message->buffer == NULL) { lua_pushlstring(L, (char *)(message+1),size - sizeof(*message)); } else { lua_pushlightuserdata(L, message->buffer); } return 4; } static int lconnect(lua_State *L) { size_t sz = 0; const char * addr = luaL_checklstring(L,1,&sz); char tmp[sz]; int port; const char * host; if (lua_isnoneornil(L,2)) { const char * sep = strchr(addr,':'); if (sep == NULL) { return luaL_error(L, "Connect to invalid address %s.",addr); } memcpy(tmp, addr, sep-addr); tmp[sep-addr] = '\0'; host = tmp; port = strtoul(sep+1,NULL,10); } else { host = addr; port = luaL_checkinteger(L,2); } struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); int id = skynet_socket_connect(ctx, host, port); lua_pushinteger(L, id); return 1; } static int lclose(lua_State *L) { int id = luaL_checkinteger(L,1); struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); skynet_socket_close(ctx, id); return 0; } static int llisten(lua_State *L) { const char * host = luaL_checkstring(L,1); int port = luaL_checkinteger(L,2); int backlog = luaL_optinteger(L,3,BACKLOG); struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); int id = skynet_socket_listen(ctx, host,port,backlog); if (id < 0) { return luaL_error(L, "Listen error"); } lua_pushinteger(L,id); return 1; } static void * get_buffer(lua_State *L, int *sz) { void *buffer; if (lua_isuserdata(L,2)) { buffer = lua_touserdata(L,2); *sz = luaL_checkinteger(L,3); } else { size_t len = 0; const char * str = luaL_checklstring(L, 2, &len); buffer = skynet_malloc(len); memcpy(buffer, str, len); *sz = (int)len; } return buffer; } static int lsend(lua_State *L) { struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); int id = luaL_checkinteger(L, 1); int sz = 0; void *buffer = get_buffer(L, &sz); int err = skynet_socket_send(ctx, id, buffer, sz); lua_pushboolean(L, !err); return 1; } static int lsendlow(lua_State *L) { struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); int id = luaL_checkinteger(L, 1); int sz = 0; void *buffer = get_buffer(L, &sz); skynet_socket_send_lowpriority(ctx, id, buffer, sz); return 0; } static int lbind(lua_State *L) { struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); int fd = luaL_checkinteger(L, 1); int id = skynet_socket_bind(ctx,fd); lua_pushinteger(L,id); return 1; } static int lstart(lua_State *L) { struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1)); int id = luaL_checkinteger(L, 1); skynet_socket_start(ctx,id); return 0; } int luaopen_socketdriver(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { { "buffer", lnewbuffer }, { "push", lpushbuffer }, { "pop", lpopbuffer }, { "drop", ldrop }, { "readall", lreadall }, { "clear", lclearbuffer }, { "readline", lreadline }, { "str2p", lstr2p }, { "unpack", lunpack }, { NULL, NULL }, }; luaL_newlib(L,l); luaL_Reg l2[] = { { "connect", lconnect }, { "close", lclose }, { "listen", llisten }, { "send", lsend }, { "lsend", lsendlow }, { "bind", lbind }, { "start", lstart }, { NULL, NULL }, }; lua_getfield(L, LUA_REGISTRYINDEX, "skynet_lua"); struct snlua *lua = lua_touserdata(L,-1); if (lua == NULL || lua->ctx == NULL) { return luaL_error(L, "Init skynet context first"); } // assert(lua->L == L); lua_pop(L,1); lua_pushlightuserdata(L, lua->ctx); luaL_setfuncs(L,l2,1); return 1; }