Compare commits

..

102 Commits

Author SHA1 Message Date
云风
a8a683b48e Merge pull request #135 from cloudwu/dev
release v0.4.2
2014-07-14 14:16:17 +08:00
Cloud Wu
4cdf034f15 release 0.4.2 2014-07-14 14:14:42 +08:00
Cloud Wu
68ddeab8fa bugfix: skynet.localname return nil not 0 2014-07-13 19:44:59 +08:00
Cloud Wu
3bc7304609 skynet.localname return nil when the name not exist 2014-07-13 19:37:08 +08:00
Cloud Wu
2e35f405e7 update history 2014-07-13 11:56:28 +08:00
Cloud Wu
6813fd9ef7 bugfix: skynet.exit redirect error, and add datacenter.wait 2014-07-13 11:55:25 +08:00
Cloud Wu
7b5e62b896 fix typo 2014-07-12 23:24:29 +08:00
Cloud Wu
a090899bce improve cluster 2014-07-12 23:14:05 +08:00
Cloud Wu
3a5de32ad0 add socket.limit for defence 2014-07-12 20:30:02 +08:00
Cloud Wu
54e6d03d36 update readme 2014-07-10 16:57:41 +08:00
Cloud Wu
83289b7612 bugfix: Issue #133 2014-07-09 21:07:26 +08:00
Cloud Wu
b7c12846a0 bugfix: socket channel 2014-07-09 15:59:06 +08:00
Cloud Wu
b5e10b8f9f add skynet.queue 2014-07-09 15:26:34 +08:00
Cloud Wu
0855bf30d9 update history 2014-07-09 14:33:53 +08:00
Cloud Wu
d05859b766 gate support TCP_NODELAY 2014-07-09 12:03:44 +08:00
Cloud Wu
fe5c73b1e8 socket id can't be less then 0 2014-07-09 11:25:28 +08:00
Cloud Wu
35775685c3 add worker dispatch weight 2014-07-08 19:56:30 +08:00
Cloud Wu
e60fb1d722 bugfix: remote send handle destination 2014-07-08 11:01:26 +08:00
云风
4e4dacbb4d Merge pull request #130 from cloudwu/dev
Dev
2014-07-07 20:53:38 +08:00
Cloud Wu
8f8b844bde ready for release 2014-07-07 20:52:34 +08:00
Cloud Wu
54f4d94ba2 bugfix: create queue first 2014-07-07 19:50:31 +08:00
Cloud Wu
4967dc2fce skynet.task return session:traceback 2014-07-07 19:00:22 +08:00
Cloud Wu
ece89a1b49 add new api skynet.task() 2014-07-07 18:29:27 +08:00
Cloud Wu
f874fdc618 throw error when skynet.exit 2014-07-03 17:40:07 +08:00
Cloud Wu
711c04e6a9 bugfix: redirect should pass session (0) 2014-07-03 17:13:47 +08:00
Cloud Wu
1e0189962b bugfix: dead lock when service_harbor exit 2014-06-30 11:31:24 +08:00
Cloud Wu
f4d865a882 release v0.4.0 2014-06-30 10:07:55 +08:00
云风
60b0976253 Merge pull request #129 from cloudwu/dev
pre release v0.4.0
2014-06-30 10:05:30 +08:00
Cloud Wu
2b9efcec3f revert 2014-06-26 15:12:16 +08:00
Cloud Wu
d343f3b374 use atomic operation 2014-06-26 15:06:47 +08:00
Cloud Wu
ceeb9912bf typo 2014-06-26 14:04:57 +08:00
Cloud Wu
be1db23ea3 get now before starttime would be better 2014-06-25 11:59:54 +08:00
Cloud Wu
36cab8e060 add skynet.time() 2014-06-25 11:15:28 +08:00
云风
b1d6f7fd88 Merge pull request #127 from xjdrew/real_bugfix_time
Real bugfix time
2014-06-25 11:00:01 +08:00
xjdrew
e0d8b00226 bugfix: ntp校验时把时间往后调整 2014-06-25 10:53:56 +08:00
xjdrew
1cbe639186 bugfix: time rewind 2014-06-25 00:50:42 +08:00
Cloud Wu
f849c522bb bugfix: silly bug 2014-06-24 21:06:40 +08:00
Cloud Wu
3cadd29796 don't throw error when destination address is invalid 2014-06-24 19:32:15 +08:00
Cloud Wu
db952dc658 report too long message error, instead of assert 2014-06-24 19:22:18 +08:00
Cloud Wu
813e6c764d add assert 2014-06-24 18:30:20 +08:00
Cloud Wu
79b6b80676 bugfix: harbor socket package split 2014-06-24 18:19:04 +08:00
Cloud Wu
d30a206a15 bugfix: typo 2014-06-24 11:51:52 +08:00
Cloud Wu
cc2cffacb7 bugfix: master, don't report offline slave 2014-06-24 11:33:29 +08:00
Cloud Wu
d8b0e977f3 merge history 2014-06-23 11:06:20 +08:00
Cloud Wu
2128a82571 update history, and release v0.3.2 2014-06-23 11:01:20 +08:00
Cloud Wu
4e2dc64f8f Merge branch 'master' into dev 2014-06-21 18:03:24 +08:00
Cloud Wu
d910686cb8 cluster bugfix : add socket.header to decode bigendian header 2014-06-21 18:03:08 +08:00
Cloud Wu
9937081854 Redesign harbor/master/dummy service 2014-06-21 17:01:59 +08:00
Cloud Wu
7137850eb2 restore config_log 2014-06-20 03:02:51 +08:00
Cloud Wu
c3eb5cd202 After connecting, socket can send before connected. remove block connect api 2014-06-20 02:49:48 +08:00
Cloud Wu
1a44bfb09a launch logger in C 2014-06-19 22:12:29 +08:00
Cloud Wu
e4197daa54 minor optimize 2014-06-19 16:29:54 +08:00
Cloud Wu
d0468a39f4 cluster.open support cluster name 2014-06-19 16:25:50 +08:00
Cloud Wu
ad9898a209 add module skynet.harbor 2014-06-19 15:43:41 +08:00
云风
33e51a4de9 Merge pull request #124 from xjdrew/bugfix_redis
optimize redis compose_message, see redistest for changes
2014-06-18 20:30:10 +08:00
xjdrew
4ccb677e84 optimize redis compose_message, see redistest for changes
test case: start redistest
2014-06-18 20:20:45 +08:00
Cloud Wu
942c2d3a67 freebsd can use malloc hook now 2014-06-18 15:10:21 +08:00
Cloud Wu
44bef99f64 use skynet.error instead of print 2014-06-18 15:10:21 +08:00
Cloud Wu
078ac2bcd2 bugfix: double free 2014-06-18 15:09:15 +08:00
云风
c7887cceb7 Merge pull request #119 from cloudwu/dev
release v0.3.1
2014-06-16 10:11:18 +08:00
Cloud Wu
4fbd433199 release v0.3.1 2014-06-16 10:10:18 +08:00
Cloud Wu
87d276caf6 typo fix 2014-06-12 17:28:54 +08:00
Cloud Wu
0f64e909fa big-endian encoding bson objectid 2014-06-11 15:11:18 +08:00
Cloud Wu
4bc2e800fd bugfix: lua mongo result 2014-06-09 18:08:23 +08:00
Cloud Wu
bf6501f2ee check mongo reply data stream 2014-06-09 17:43:40 +08:00
Cloud Wu
f92fc153e4 bugfix: in freebsd, libthr may call calloc before globalinit 2014-06-04 02:51:29 +00:00
Cloud Wu
c10e5412c0 invalid length may nagtive 2014-06-04 10:23:49 +08:00
Cloud Wu
9477cc8171 turn off memory hook in freeBSD 2014-06-03 12:35:00 +00:00
Cloud Wu
7f3ba76a41 update history 2014-06-02 21:10:58 +08:00
云风
4545ef149b Merge pull request #116 from cloudwu/dev
merge dev version
2014-06-02 21:05:15 +08:00
Cloud Wu
c130a93a91 bson : check string length 2014-06-02 11:53:55 +08:00
Cloud Wu
cd0a1a495e optimize timer 2014-05-28 11:30:39 +08:00
Cloud Wu
3597bb6d75 use jemalloc release 3.6.0 2014-05-27 21:04:22 +08:00
Cloud Wu
39c5e13d1a Merge branch 'dev' of github.com:cloudwu/skynet into dev 2014-05-26 13:42:07 +08:00
Cloud Wu
e1a72bd820 optimize message dispatch 2014-05-26 13:40:49 +08:00
Cloud Wu
f77482024e Merge branch 'master' into dev 2014-05-26 13:23:59 +08:00
Cloud Wu
866e59811e remove unused mq api 2014-05-26 13:23:57 +08:00
Cloud Wu
f3b1f5be51 bugfix: check globalmq push is complete 2014-05-26 13:18:09 +08:00
Cloud
0fcab96431 daemon is deprecarted in macosx 2014-05-23 16:52:24 +08:00
Cloud Wu
e765d3c305 don't unlock pidfile after write pid 2014-05-23 14:06:41 +08:00
Cloud Wu
8005b55ef5 add pidfile for daemon 2014-05-23 13:24:02 +08:00
Cloud Wu
1ce90b7d17 daemon mode 2014-05-23 10:54:54 +08:00
Cloud Wu
37ea7a025c single node mode 2014-05-22 22:44:20 +08:00
Cloud Wu
88700c2c90 cluster support 2014-05-22 21:04:32 +08:00
Cloud Wu
90cd967333 concurrence bugfix 2014-05-22 11:24:36 +08:00
Cloud Wu
1fbee1ac0b update lua-bson to fix the 32bit signed int bug 2014-05-21 11:21:01 +08:00
云风
d6a4c5cc59 Merge pull request #114 from tangyi/minor-fix
fix the missing of 'Welcome to skynet' in example
2014-05-20 10:39:33 +08:00
tangyi
66a0a6e1db fix the missing of 'Welcome to skynet' in example 2014-05-19 18:13:34 +08:00
云风
57f37a55ba Merge pull request #113 from cloudwu/dev
bugfix
2014-05-19 10:53:08 +08:00
Cloud Wu
84e8abc09c update history 2014-05-19 10:51:20 +08:00
云风
dbfa17be09 Merge pull request #112 from zhoukk/master
remove services when launch error.
2014-05-19 10:50:12 +08:00
zhoukk
19729576f6 lua service launch错误时,移除services中记录
lua service launch错误后,没有移除 launcher.lua里services中的服务记录,导致debug_console中的list mem等命令返回数据不正确
2014-05-18 12:36:38 +08:00
Cloud Wu
a5df196e92 use skynet_error for memory dump 2014-05-16 17:36:49 +08:00
Cloud Wu
a2ad158dbc update PTYPE_* macro 2014-05-16 15:01:25 +08:00
Cloud Wu
ff155c623e bugfix: stdin is 0 2014-05-16 14:31:27 +08:00
Cloud Wu
9fe6a0a954 Merge branch 'master' into dev 2014-05-15 19:33:30 +08:00
Cloud Wu
c2ed2f8603 bugfix. the harbor and master service need to rewrite in future 2014-05-15 19:32:54 +08:00
Cloud Wu
a67e561a64 Merge branch 'master' into dev 2014-05-14 11:55:53 +08:00
Cloud Wu
ef2da264f1 bugfix: watchdog socket data 2014-05-14 11:55:40 +08:00
Cloud Wu
b397c70c34 remove unused pingqueue 2014-05-13 17:00:43 +08:00
Cloud Wu
02f2f88b6d Fix issue #109 2014-05-13 13:35:37 +08:00
Cloud Wu
29917efad7 add MAX_SLOT_SIZE limit 2014-05-13 11:09:15 +08:00
78 changed files with 2297 additions and 931 deletions

7
.gitignore vendored
View File

@@ -1,9 +1,10 @@
*.o
*.a
skynet
/skynet
/skynet.pid
3rd/lua/lua
3rd/lua/luac
cservice
luaclib
/cservice
/luaclib
*.so
*.dSYM

View File

@@ -1,3 +1,61 @@
v0.4.2 (2014-7-14)
-----------
* Bugfix : invalid negative socket id
* Add optional TCP_NODELAY support
* Add worker thread weight
* Add skynet.queue
* Bugfix: socketchannel
* cluster can throw error
* Add readline and writeline to clientsocket lib
* Add cluster.reload to reload config file
* Add datacenter.wait
v0.4.1 (2014-7-7)
-----------
* Add SERVICE_NAME in loader
* Throw error back when skynet.error
* Add skynet.task
* Bugfix for last version (harbor service bugs)
v0.4.0 (2014-6-30)
-----------
* Optimize redis driver `compose_message`.
* Add module skynet.harbor for monitor harbor connect/disconnect, see test/testharborlink.lua .
* cluster.open support cluster name.
* Add new api skynet.packstring , and skynet.unpack support lua string
* socket.listen support put port into address. (address:port)
* Redesign harbor/master/dummy, remove lots of C code and rewite in lua.
* Remove block connect api, queue sending message during connecting now.
* Add skynet.time()
v0.3.2 (2014-6-23)
----------
* Bugfix : cluster (double free).
* Add socket.header() to decode big-endian package header (and fix the bug in cluster).
v0.3.1 (2014-6-16)
-----------
* Bugfix: lua mongo driver . Hold reply string before decode bson data.
* More check in bson decoding.
* Use big-endian for encoding bson objectid.
v0.3.0 (2014-6-2)
-----------
* Add cluster support
* Add single node mode
* Add daemon mode
* Bugfix: update lua-bson (signed 32bit int bug / check string length)
* Optimize timer
* Simplify message queue and optimize message dispatch
* Use jemalloc release 3.6.0
v0.2.1 (2014-5-19)
-----------
* Bugfix: check all the events already read after socket close
* Bugfix: socket data in gate service
* Bugfix: boundary problem in harbor service
* Bugfix: stdin handle is 0
v0.2.0 (2014-5-12)
-----------

View File

@@ -40,13 +40,15 @@ jemalloc : $(MALLOC_STATICLIB)
# skynet
CSERVICE = snlua logger gate master harbor
LUA_CLIB = skynet socketdriver int64 bson mongo md5 netpack cjson clientsocket memory profile multicast
CSERVICE = snlua logger gate harbor
LUA_CLIB = skynet socketdriver int64 bson mongo md5 netpack \
cjson clientsocket memory profile multicast \
cluster
SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \
skynet_server.c skynet_start.c skynet_timer.c skynet_error.c \
skynet_harbor.c skynet_env.c skynet_monitor.c skynet_socket.c socket_server.c \
malloc_hook.c
malloc_hook.c skynet_daemon.c
all : \
$(SKYNET_BUILD_PATH)/skynet \
@@ -64,7 +66,7 @@ $(CSERVICE_PATH) :
define CSERVICE_TEMP
$$(CSERVICE_PATH)/$(1).so : service-src/service_$(1).c | $$(CSERVICE_PATH)
$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
$$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
endef
$(foreach v, $(CSERVICE), $(eval $(call CSERVICE_TEMP,$(v))))
@@ -105,6 +107,9 @@ $(LUA_CLIB_PATH)/profile.so : lualib-src/lua-profile.c | $(LUA_CLIB_PATH)
$(LUA_CLIB_PATH)/multicast.so : lualib-src/lua-multicast.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/cluster.so : lualib-src/lua-cluster.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
clean :
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so

View File

@@ -1,9 +1,9 @@
## Build
Install autoconf first for jemalloc
For linux, install autoconf first for jemalloc
```
git clone git@github.com:cloudwu/skynet.git
git clone https://github.com/cloudwu/skynet.git
cd skynet
make 'PLATFORM' # PLATFORM can be linux, macosx, freebsd now
```
@@ -15,6 +15,8 @@ export PLAT=linux
make
```
For freeBSD , use gmake instead of make .
## Test
Run these in different console
@@ -36,5 +38,4 @@ You can also use the offical lua version , edit the makefile by yourself .
* http://blog.codingnow.com/2012/09/the_design_of_skynet.html
* http://blog.codingnow.com/2012/08/skynet.html
* http://blog.codingnow.com/2012/08/skynet_harbor_rpc.html
* http://blog.codingnow.com/eo/skynet/

View File

@@ -8,7 +8,7 @@ local CMD = {}
local client_fd
local function send_client(v)
socket.write(client_fd, netpack.pack(jsonpack.pack(0,v)))
socket.write(client_fd, netpack.pack(jsonpack.pack(0, {true, v})))
end
local function response_client(session,v)

View File

@@ -39,7 +39,7 @@ end
while true do
dispatch()
local cmd = socket.readline()
local cmd = socket.readstdin()
if cmd then
local args = {}
string.gsub(cmd, '[^ ]+', function(v) table.insert(args, v) end )

9
examples/cluster1.lua Normal file
View File

@@ -0,0 +1,9 @@
local skynet = require "skynet"
local cluster = require "cluster"
skynet.start(function()
skynet.newservice("simpledb")
print(skynet.call("SIMPLEDB", "lua", "SET", "a", "foobar"))
print(skynet.call("SIMPLEDB", "lua", "GET", "a"))
cluster.open "db"
end)

6
examples/cluster2.lua Normal file
View File

@@ -0,0 +1,6 @@
local skynet = require "skynet"
local cluster = require "cluster"
skynet.start(function()
print(cluster.call("db", "SIMPLEDB", "GET", "a"))
end)

1
examples/clustername.lua Normal file
View File

@@ -0,0 +1 @@
db = "127.0.0.1:2528"

View File

@@ -12,3 +12,4 @@ lualoader = "lualib/loader.lua"
-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run
snax = root.."examples/?.lua;"..root.."test/?.lua"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

9
examples/config.c1 Normal file
View File

@@ -0,0 +1,9 @@
thread = 8
logger = nil
harbor = 0
start = "cluster1"
bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = "./service/?.lua;./test/?.lua;./examples/?.lua"
lualoader = "lualib/loader.lua"
cpath = "./cservice/?.so"
cluster = "./examples/clustername.lua"

9
examples/config.c2 Normal file
View File

@@ -0,0 +1,9 @@
thread = 8
logger = nil
harbor = 0
start = "cluster2"
bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = "./service/?.lua;./test/?.lua;./examples/?.lua"
lualoader = "lualib/loader.lua"
cpath = "./cservice/?.so"
cluster = "./examples/clustername.lua"

View File

@@ -1,8 +1,8 @@
local skynet = require "skynet"
skynet.start(function()
skynet.dispatch("text", function(session, address, text)
print("[GLOBALLOG]", skynet.address(address),text)
skynet.dispatch("lua", function(session, address, ...)
print("[GLOBALLOG]", skynet.address(address), ...)
end)
skynet.register "LOG"
end)

View File

@@ -12,6 +12,7 @@ skynet.start(function()
port = 8888,
maxclient = max_client,
})
print("Watchdog listen on ", 8888)
skynet.exit()
end)

View File

@@ -2,7 +2,6 @@ local skynet = require "skynet"
skynet.start(function()
print("Log server start")
local service = skynet.newservice("service_mgr")
skynet.monitor "simplemonitor"
local log = skynet.newservice("globallog")
skynet.exit()

View File

@@ -12,7 +12,7 @@ skynet.register_protocol {
local w = service_map[address]
if w then
for watcher in pairs(w) do
skynet.redirect(watcher, address, "error", "")
skynet.redirect(watcher, address, "error", 0, "")
end
service_map[address] = false
end

View File

@@ -33,6 +33,7 @@ function SOCKET.data(fd, msg)
end
function CMD.start(conf)
skynet.call(gate, "lua", "nodelay", true)
skynet.call(gate, "lua", "open" , conf)
end

View File

@@ -1,5 +1,3 @@
#include "skynet_malloc.h"
#include <lua.h>
#include <lauxlib.h>
@@ -70,10 +68,17 @@ struct bson_reader {
int size;
};
static inline int32_t
get_length(const uint8_t * data) {
const uint8_t * b = (const uint8_t *)data;
int32_t len = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
return len;
}
static inline void
bson_destroy(struct bson *b) {
if (b->ptr != b->buffer) {
skynet_free(b->ptr);
free(b->ptr);
}
}
@@ -93,10 +98,10 @@ bson_reserve(struct bson *b, int sz) {
} while (b->cap <= b->size + sz);
if (b->ptr == b->buffer) {
b->ptr = skynet_malloc(b->cap);
b->ptr = malloc(b->cap);
memcpy(b->ptr, b->buffer, b->size);
} else {
b->ptr = skynet_realloc(b->ptr, b->cap);
b->ptr = realloc(b->ptr, b->cap);
}
}
@@ -258,13 +263,13 @@ append_key(struct bson *bs, int type, const char *key, size_t sz) {
static void
append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
lua_Integer i = lua_tointeger(L, -1);
int64_t i = lua_tointeger(L, -1);
lua_Number d = lua_tonumber(L,-1);
if (i != d) {
append_key(bs, BSON_REAL, key, sz);
write_double(bs, d);
} else {
int si = (int64_t)i >> 32;
int si = i >> 31;
if (si == 0 || si == -1) {
append_key(bs, BSON_INT32, key, sz);
write_int32(bs, i);
@@ -459,7 +464,7 @@ pack_dict(lua_State *L, struct bson *b, bool isarray) {
}
static void
pack_sorted_dict(lua_State *L, struct bson *b, int n) {
pack_ordered_dict(lua_State *L, struct bson *b, int n) {
int length = reserve_length(b);
int i;
for (i=0;i<n;i+=2) {
@@ -534,6 +539,9 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
break;
case BSON_STRING: {
int sz = read_int32(L, &t);
if (sz <= 0) {
luaL_error(L, "Invalid bson string , length = %d", sz);
}
lua_pushlstring(L, read_bytes(L, &t, sz), sz-1);
break;
}
@@ -643,7 +651,7 @@ static int
lmakeindex(lua_State *L) {
int32_t *bson = luaL_checkudata(L,1,"bson");
const uint8_t * start = (const uint8_t *)bson;
struct bson_reader br = { start+4, *bson - 5 };
struct bson_reader br = { start+4, get_length(start) - 5 };
lua_newtable(L);
for (;;) {
@@ -806,6 +814,9 @@ lreplace(lua_State *L) {
write_int64(&b, i);
break;
}
default:
luaL_error(L, "Can't replace type %d", type);
break;
}
return 0;
}
@@ -816,7 +827,9 @@ ldecode(lua_State *L) {
if (data == NULL) {
return 0;
}
struct bson_reader br = { (const uint8_t *)data , *data };
const uint8_t * b = (const uint8_t *)data;
int32_t len = get_length(b);
struct bson_reader br = { b , len };
unpack_dict(L, &br, false);
@@ -865,7 +878,7 @@ lencode_order(lua_State *L) {
if (n%2 != 0) {
return luaL_error(L, "Invalid ordered dict");
}
pack_sorted_dict(L, &b, n);
pack_ordered_dict(L, &b, n);
lua_settop(L,1);
void * ud = lua_newuserdata(L, b.size);
memcpy(ud, b.ptr, b.size);
@@ -1136,14 +1149,14 @@ lobjectid(lua_State *L) {
}
} else {
time_t ti = time(NULL);
oid[2] = ti & 0xff;
oid[3] = (ti>>8) & 0xff;
oid[4] = (ti>>16) & 0xff;
oid[5] = (ti>>24) & 0xff;
oid[2] = (ti>>24) & 0xff;
oid[3] = (ti>>16) & 0xff;
oid[4] = (ti>>8) & 0xff;
oid[5] = ti & 0xff;
memcpy(oid+6 , oid_header, 5);
oid[11] = oid_counter & 0xff;
oid[11] = (oid_counter>>16) & 0xff;
oid[12] = (oid_counter>>8) & 0xff;
oid[13] = (oid_counter>>16) & 0xff;
oid[13] = oid_counter & 0xff;
++oid_counter;
}
lua_pushlstring( L, (const char *)oid, 14);
@@ -1190,3 +1203,4 @@ luaopen_bson(lua_State *L) {
return 1;
}

View File

@@ -125,14 +125,19 @@ _block:
boolean (true: data, false: block, nil: close)
string last
*/
struct socket_buffer {
void * buffer;
int sz;
};
static int
lrecv(lua_State *L) {
recv_socket(lua_State *L, char *tmp, struct socket_buffer *result) {
int fd = luaL_checkinteger(L,1);
size_t sz = 0;
const char * last = lua_tolstring(L,2,&sz);
luaL_checktype(L, 3, LUA_TTABLE);
char tmp[CACHE_SIZE];
char * buffer;
int r = recv(fd, tmp, CACHE_SIZE, 0);
if (r == 0) {
@@ -163,10 +168,64 @@ lrecv(lua_State *L) {
lua_pushnil(L);
lua_rawseti(L, 3, i);
}
return unpack(L, (uint8_t *)buffer, r+sz, 0);
result->buffer = buffer;
result->sz = r + sz;
return -1;
}
static int
lrecv(lua_State *L) {
struct socket_buffer sb;
char tmp[CACHE_SIZE];
int ret = recv_socket(L, tmp, &sb);
if (ret < 0) {
return unpack(L, sb.buffer, sb.sz, 0);
} else {
return ret;
}
}
static int
unpack_line(lua_State *L, uint8_t *buffer, int sz, int n) {
if (sz == 0)
goto _block;
if (buffer[0] == '\n') {
return unpack_line(L, buffer+1, sz-1, n);
}
int i;
for (i=1;i<sz;i++) {
if (buffer[i] == '\n') {
++n;
lua_pushlstring(L, (const char *)buffer, i);
lua_rawseti(L, 3, n);
buffer += i + 1;
sz -= i + 1;
return unpack_line(L, buffer, sz, n);
}
}
_block:
lua_pushboolean(L, n==0 ? 0:1);
if (sz == 0) {
lua_pushnil(L);
} else {
lua_pushlstring(L, (const char *)buffer, sz);
}
return 2;
}
static int
lreadline(lua_State *L) {
struct socket_buffer sb;
char tmp[CACHE_SIZE];
int ret = recv_socket(L, tmp, &sb);
if (ret < 0) {
return unpack_line(L, sb.buffer, sb.sz, 0);
} else {
return ret;
}
}
static int
lusleep(lua_State *L) {
int n = luaL_checknumber(L, 1);
@@ -219,7 +278,7 @@ readline_stdin(void * arg) {
}
static int
lreadline(lua_State *L) {
lreadstdin(lua_State *L) {
struct queue *q = lua_touserdata(L, lua_upvalueindex(1));
LOCK(q);
if (q->head == q->tail) {
@@ -236,6 +295,18 @@ lreadline(lua_State *L) {
return 1;
}
static int
lwriteline(lua_State *L) {
size_t sz = 0;
int fd = luaL_checkinteger(L,1);
const char * msg = luaL_checklstring(L, 2, &sz);
block_send(L, fd, msg, sz);
char nl[1] = { '\n' };
block_send(L, fd, nl, 1);
return 0;
}
int
luaopen_clientsocket(lua_State *L) {
luaL_checkversion(L);
@@ -245,14 +316,16 @@ luaopen_clientsocket(lua_State *L) {
{ "send", lsend },
{ "close", lclose },
{ "usleep", lusleep },
{ "readline", lreadline },
{ "writeline", lwriteline },
{ NULL, NULL },
};
luaL_newlib(L, l);
struct queue * q = lua_newuserdata(L, sizeof(*q));
memset(q, 0, sizeof(*q));
lua_pushcclosure(L, lreadline, 1);
lua_setfield(L, -2, "readline");
lua_pushcclosure(L, lreadstdin, 1);
lua_setfield(L, -2, "readstdin");
pthread_t pid ;
pthread_create(&pid, NULL, readline_stdin, q);

218
lualib-src/lua-cluster.c Normal file
View File

@@ -0,0 +1,218 @@
#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 0x10007
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
boolean ok
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)
int ok = lua_toboolean(L,2);
void * msg;
size_t sz;
if (lua_type(L,3) == LUA_TSTRING) {
msg = (void *)lua_tolstring(L, 3, &sz);
if (sz > 0x1000) {
sz = 0x1000;
}
} else {
msg = lua_touserdata(L,3);
sz = luaL_checkunsigned(L, 4);
}
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+5, msg);
fill_uint32(buf+2, session);
buf[6] = ok;
memcpy(buf+7,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+7);
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 < 5) {
return 0;
}
uint32_t session = unpack_uint32((const uint8_t *)buf);
lua_pushunsigned(L, session);
lua_pushboolean(L, buf[4]);
lua_pushlstring(L, buf+5, sz-5);
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;
}

View File

@@ -260,6 +260,13 @@ op_reply(lua_State *L) {
lua_pushnil(L);
lua_rawseti(L, 2, i);
}
} else {
if (sz >= 4) {
sz -= get_length((document)doc);
}
}
if (sz != 0) {
return luaL_error(L, "Invalid result bson document");
}
lua_pushboolean(L,1);
lua_pushinteger(L, id);
@@ -499,7 +506,7 @@ op_insert(lua_State *L) {
int i;
for (i=1;i<=s;i++) {
lua_rawgeti(L,3,i);
document doc = lua_touserdata(L,3);
document doc = lua_touserdata(L,-1);
luaL_addlstring(&b, (const char *)doc, get_length(doc));
lua_pop(L,1);
}

View File

@@ -581,8 +581,16 @@ _luaseri_unpack(lua_State *L) {
if (lua_isnoneornil(L,1)) {
return 0;
}
void * buffer = lua_touserdata(L,1);
int len = luaL_checkinteger(L,2);
void * buffer;
int len;
if (lua_type(L,1) == LUA_TSTRING) {
size_t sz;
buffer = (void *)lua_tolstring(L,1,&sz);
len = (int)sz;
} else {
buffer = lua_touserdata(L,1);
len = luaL_checkinteger(L,2);
}
if (len == 0) {
return 0;
}

View File

@@ -149,7 +149,7 @@ _sendname(lua_State *L, struct skynet_context * context, const char * dest) {
luaL_error(L, "skynet.send invalid param %s", lua_typename(L,lua_type(L,4)));
}
if (session < 0) {
luaL_error(L, "skynet.send session (%d) < 0", session);
return 0;
}
lua_pushinteger(L,session);
return 1;
@@ -221,7 +221,7 @@ _send(lua_State *L) {
}
if (session < 0) {
// send to invalid address
// todo: maybe throw error is better
// todo: maybe throw error whould be better
return 0;
}
lua_pushinteger(L,session);
@@ -289,6 +289,16 @@ _harbor(lua_State *L) {
return 2;
}
static int
lpackstring(lua_State *L) {
_luaseri_pack(L);
char * str = (char *)lua_touserdata(L, -2);
int sz = lua_tointeger(L, -1);
lua_pushlstring(L, str, sz);
skynet_free(str);
return 1;
}
int
luaopen_skynet_c(lua_State *L) {
luaL_checkversion(L);
@@ -303,6 +313,7 @@ luaopen_skynet_c(lua_State *L) {
{ "harbor", _harbor },
{ "pack", _luaseri_pack },
{ "unpack", _luaseri_unpack },
{ "packstring", lpackstring },
{ "callback", _callback },
{ NULL, NULL },
};

View File

@@ -14,6 +14,7 @@
#define BACKLOG 32
// 2 ** 12 == 4096
#define LARGE_PAGE_NODE 12
#define BUFFER_LIMIT (256 * 1024)
struct buffer_node {
char * msg;
@@ -22,6 +23,7 @@ struct buffer_node {
};
struct socket_buffer {
int limit;
int size;
int offset;
struct buffer_node *head;
@@ -64,6 +66,7 @@ lnewpool(lua_State *L, int sz) {
static int
lnewbuffer(lua_State *L) {
struct socket_buffer * sb = lua_newuserdata(L, sizeof(*sb));
sb->limit = luaL_optint(L,1,BUFFER_LIMIT);
sb->size = 0;
sb->offset = 0;
sb->head = NULL;
@@ -126,6 +129,9 @@ lpushbuffer(lua_State *L) {
sb->size += sz;
lua_pushinteger(L, sb->size);
if (sb->limit > 0 && sb->size > sb->limit) {
return luaL_error(L, "buffer overflow (limit = %d, size = %d)", sb->limit, sb->size);
}
return 1;
}
@@ -188,10 +194,29 @@ pop_lstring(lua_State *L, struct socket_buffer *sb, int sz, int skip) {
luaL_pushresult(&b);
}
static int
lheader(lua_State *L) {
size_t len;
const uint8_t * s = (const uint8_t *)luaL_checklstring(L, 1, &len);
if (len > 4 || len < 1) {
return luaL_error(L, "Invalid read %s", s);
}
int i;
size_t sz = 0;
for (i=0;i<(int)len;i++) {
sz <<= 8;
sz |= s[i];
}
lua_pushunsigned(L, sz);
return 1;
}
/*
userdata send_buffer
table pool
integer sz
integer sz
*/
static int
lpopbuffer(lua_State *L) {
@@ -457,6 +482,14 @@ lstart(lua_State *L) {
return 0;
}
static int
lnodelay(lua_State *L) {
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
int id = luaL_checkinteger(L, 1);
skynet_socket_nodelay(ctx,id);
return 0;
}
int
luaopen_socketdriver(lua_State *L) {
luaL_checkversion(L);
@@ -469,6 +502,7 @@ luaopen_socketdriver(lua_State *L) {
{ "clear", lclearbuffer },
{ "readline", lreadline },
{ "str2p", lstr2p },
{ "header", lheader },
{ "unpack", lunpack },
{ NULL, NULL },
@@ -482,6 +516,7 @@ luaopen_socketdriver(lua_State *L) {
{ "lsend", lsendlow },
{ "bind", lbind },
{ "start", lstart },
{ "nodelay", lnodelay },
{ NULL, NULL },
};
lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context");

27
lualib/cluster.lua Normal file
View File

@@ -0,0 +1,27 @@
local skynet = require "skynet"
local clusterd
local cluster = {}
function cluster.call(node, address, ...)
-- skynet.pack(...) will free by cluster.c.packrequest
return skynet.call(clusterd, "lua", "req", node, address, skynet.pack(...))
end
function cluster.open(port)
if type(port) == "string" then
skynet.call(clusterd, "lua", "listen", port)
else
skynet.call(clusterd, "lua", "listen", "0.0.0.0", port)
end
end
function cluster.reload()
skynet.call(clusterd, "lua", "reload")
end
skynet.init(function()
clusterd = skynet.uniqueservice("clusterd")
end)
return cluster

View File

@@ -10,5 +10,9 @@ function datacenter.set(...)
return skynet.call("DATACENTER", "lua", "UPDATE", ...)
end
function datacenter.wait(...)
return skynet.call("DATACENTER", "lua", "WAIT", ...)
end
return datacenter

View File

@@ -3,11 +3,13 @@ for word in string.gmatch(..., "%S+") do
table.insert(args, word)
end
SERVICE_NAME = args[1]
local main, pattern
local err = {}
for pat in string.gmatch(LUA_SERVICE, "([^;]+);*") do
local filename = string.gsub(pat, "?", args[1])
local filename = string.gsub(pat, "?", SERVICE_NAME)
local f, msg = loadfile(filename)
if not f then
table.insert(err, msg)

View File

@@ -98,7 +98,7 @@ function mongo.client( conf )
host = obj.host,
port = obj.port,
response = dispatch_reply,
auth = mongo_auth(conf),
auth = mongo_auth(obj),
}
setmetatable(obj, client_meta)
obj.__sock:connect(true) -- try connect only once
@@ -167,7 +167,9 @@ function mongo_db:runCommand(cmd,cmd_v,...)
bson_cmd = bson_encode_order(cmd,cmd_v,...)
end
local pack = driver.query(request_id, 0, self.__cmd, 0, 1, bson_cmd)
local doc = sock:request(pack, request_id).document
-- we must hold req (req.data), because req.document is a lightuserdata, it's a pointer to the string (req.data)
local req = sock:request(pack, request_id)
local doc = req.document
return bson_decode(doc)
end
@@ -224,7 +226,9 @@ function mongo_collection:findOne(query, selector)
local request_id = conn:genId()
local sock = conn.__sock
local pack = driver.query(request_id, 0, self.full_name, 0, 1, query and bson_encode(query) or empty_bson, selector and bson_encode(selector))
local doc = sock:request(pack, request_id).document
-- we must hold req (req.data), because req.document is a lightuserdata, it's a pointer to the string (req.data)
local req = sock:request(pack, request_id)
local doc = req.document
return bson_decode(doc)
end

View File

@@ -1,3 +1,5 @@
-- This is a deprecated module, use skynet.queue instead.
local skynet = require "skynet"
local c = require "skynet.c"

View File

@@ -1,6 +1,7 @@
local skynet = require "skynet"
local socket = require "socket"
local socketchannel = require "socketchannel"
local int64 = require "int64"
local table = table
local string = string
@@ -94,31 +95,56 @@ function command:disconnect()
setmetatable(self, nil)
end
local function compose_message(msg)
if #msg == 1 then
return msg[1] .. "\r\n"
-- msg could be any type of value
local function pack_value(lines, v)
if v == nil then
return
end
local lines = { "*" .. #msg }
for _,v in ipairs(msg) do
local t = type(v)
if t == "number" then
v = tostring(v)
elseif t == "userdata" then
v = int64.tostring(int64.new(v),10)
end
table.insert(lines,"$"..#v)
table.insert(lines,v)
end
table.insert(lines,"")
local cmd = table.concat(lines,"\r\n")
return cmd
local t = type(v)
if t == "number" then
v = tostring(v)
elseif t == "userdata" then
v = int64.tostring(int64.new(v),10)
end
table.insert(lines,"$"..#v)
table.insert(lines,v)
end
local function compose_message(cmd, msg)
local len = 1
local t = type(msg)
if t == "table" then
len = len + #msg
elseif t ~= nil then
len = len + 1
end
local lines = {"*" .. len}
pack_value(lines, cmd)
if t == "table" then
for _,v in ipairs(msg) do
pack_value(lines, v)
end
else
pack_value(lines, msg)
end
table.insert(lines, "")
local chunk = table.concat(lines,"\r\n")
return chunk
end
setmetatable(command, { __index = function(t,k)
local cmd = string.upper(k)
local f = function (self, ...)
return self[1]:request(compose_message { cmd, ... }, read_response)
local f = function (self, v, ...)
if type(v) == "table" then
return self[1]:request(compose_message(cmd, v), read_response)
else
return self[1]:request(compose_message(cmd, {v, ...}), read_response)
end
end
t[k] = f
return f
@@ -131,12 +157,12 @@ end
function command:exists(key)
local fd = self[1]
return fd:request(compose_message { "EXISTS", key }, read_boolean)
return fd:request(compose_message ("EXISTS", key), read_boolean)
end
function command:sismember(key, value)
local fd = self[1]
return fd:request(compose_message { "SISMEMBER", key, value }, read_boolean)
return fd:request(compose_message ("SISMEMBER", {key, value}), read_boolean)
end
--- watch mode
@@ -156,10 +182,10 @@ local function watch_login(obj, auth)
so:request("AUTH "..auth.."\r\n", read_response)
end
for k in pairs(obj.__psubscribe) do
so:request(compose_message { "PSUBSCRIBE", k })
so:request(compose_message ("PSUBSCRIBE", k))
end
for k in pairs(obj.__subscribe) do
so:request(compose_message { "SUBSCRIBE", k })
so:request(compose_message("SUBSCRIBE", k))
end
end
end
@@ -192,7 +218,7 @@ local function watch_func( name )
local so = self.__sock
for i = 1, select("#", ...) do
local v = select(i, ...)
so:request(compose_message { NAME, v })
so:request(compose_message(NAME, v))
end
end
end

View File

@@ -22,7 +22,7 @@ local skynet = {
PTYPE_HARBOR = 5,
PTYPE_SOCKET = 6,
PTYPE_ERROR = 7,
PTYPE_QUEUE = 8,
PTYPE_QUEUE = 8, -- use in deprecated mqueue, use skynet.queue instead
PTYPE_DEBUG = 9,
PTYPE_LUA = 10,
PTYPE_SNAX = 11,
@@ -190,12 +190,33 @@ function skynet.wait()
session_id_coroutine[session] = nil
end
local function globalname(name, handle)
local c = string.sub(name,1,1)
assert(c ~= ':')
if c == '.' then
return false
end
assert(#name <= 16) -- GLOBALNAME_LENGTH is 16, defined in skynet_harbor.h
assert(tonumber(name) == nil) -- global name can't be number
local harbor = require "skynet.harbor"
harbor.globalname(name, handle)
return true
end
function skynet.register(name)
c.command("REG", name)
if not globalname(name) then
c.command("REG", name)
end
end
function skynet.name(name, handle)
c.command("NAME", name .. " " .. skynet.address(handle))
if not globalname(name, handle) then
c.command("NAME", name .. " " .. skynet.address(handle))
end
end
local self_handle
@@ -208,7 +229,10 @@ function skynet.self()
end
function skynet.localname(name)
return string_to_handle(c.command("QUERY", name))
local addr = c.command("QUERY", name)
if addr then
return string_to_handle(addr)
end
end
function skynet.launch(...)
@@ -226,8 +250,19 @@ function skynet.starttime()
return tonumber(c.command("STARTTIME"))
end
function skynet.time()
return skynet.now()/100 + skynet.starttime() -- get now first would be better
end
function skynet.exit()
skynet.send(".launcher","lua","REMOVE",skynet.self())
for co, session in pairs(session_coroutine_id) do
local address = session_coroutine_address[co]
local self = skynet.self()
if session~=0 and address then
skynet.redirect(address, self, "error", session, "")
end
end
c.command("EXIT")
end
@@ -267,6 +302,7 @@ skynet.redirect = function(dest,source,typename,...)
end
skynet.pack = assert(c.pack)
skynet.packstring = assert(c.packstring)
skynet.unpack = assert(c.unpack)
skynet.tostring = assert(c.tostring)
@@ -292,6 +328,9 @@ end
function skynet.rawcall(addr, typename, msg, sz)
local p = proto[typename]
if watching_service[addr] == false then
error("Service is dead")
end
local session = assert(c.send(addr, p.id , nil , msg, sz), "call to invalid address")
return yield_call(addr, session)
end
@@ -318,8 +357,8 @@ function skynet.dispatch(typename, func)
p.dispatch = func
end
local function unknown_request(session, address, msg, sz)
print("Unknown request :" , c.tostring(msg,sz))
local function unknown_request(session, address, msg, sz, prototype)
skynet.error(string.format("Unknown request (%s): %s", prototype, c.tostring(msg,sz)))
error(string.format("Unknown session : %d from %x", session, address))
end
@@ -373,7 +412,7 @@ local function raw_dispatch_message(prototype, msg, sz, session, source, ...)
session_coroutine_address[co] = source
suspend(co, coroutine.resume(co, session,source, p.unpack(msg,sz, ...)))
else
unknown_request(session, source, msg, sz)
unknown_request(session, source, msg, sz, proto[prototype])
end
end
end
@@ -502,7 +541,7 @@ end
local function init_service(start)
local ok, err = xpcall(init_template, debug.traceback, start)
if not ok then
print("init service failed:", err)
skynet.error("init service failed: " .. tostring(err))
skynet.send(".launcher","lua", "ERROR")
skynet.exit()
else
@@ -543,12 +582,24 @@ function skynet.monitor(service, query)
end
assert(monitor, "Monitor launch failed")
c.command("MONITOR", string.format(":%08x", monitor))
return monitor
end
function skynet.mqlen()
return tonumber(c.command "MQLEN")
end
function skynet.task(ret)
local t = 0
for session,co in pairs(session_id_coroutine) do
if ret then
ret[session] = debug.traceback(co)
end
t = t + 1
end
return t
end
-- Inject internal debug framework
local debug = require "skynet.debug"
debug(skynet)

View File

@@ -21,9 +21,16 @@ end
function dbgcmd.STAT()
local stat = {}
stat.mqlen = skynet.mqlen()
stat.task = skynet.task()
skynet.ret(skynet.pack(stat))
end
function dbgcmd.TASK()
local task = {}
skynet.task(task)
skynet.ret(skynet.pack(task))
end
function dbgcmd.INFO()
if internal_info_func then
skynet.ret(skynet.pack(internal_info_func()))

18
lualib/skynet/harbor.lua Normal file
View File

@@ -0,0 +1,18 @@
local skynet = require "skynet"
local harbor = {}
function harbor.globalname(name, handle)
handle = handle or skynet.self()
skynet.send(".slave", "lua", "REGISTER", name, handle)
end
function harbor.link(id)
skynet.call(".slave", "lua", "LINK", id)
end
function harbor.connect(id)
skynet.call(".slave", "lua", "CONNECT", id)
end
return harbor

33
lualib/skynet/queue.lua Normal file
View File

@@ -0,0 +1,33 @@
local skynet = require "skynet"
local coroutine = coroutine
local pcall = pcall
local table = table
function skynet.queue()
local current_thread
local ref = 0
local thread_queue = {}
return function(f, ...)
local thread = coroutine.running()
if ref == 0 then
current_thread = thread
elseif current_thread ~= thread then
table.insert(thread_queue, thread)
skynet.wait()
assert(ref == 0)
end
ref = ref + 1
local ok, err = pcall(f, ...)
ref = ref - 1
if ref == 0 then
current_thread = nil
local co = table.remove(thread_queue,1)
if co then
skynet.wakeup(co)
end
end
assert(ok,err)
end
end
return skynet.queue

View File

@@ -2,6 +2,7 @@ local driver = require "socketdriver"
local skynet = require "skynet"
local assert = assert
local buffer_limit = -1
local socket = {} -- api
local buffer_pool = {} -- store all message buffer object
local socket_pool = setmetatable( -- store all socket object
@@ -47,7 +48,13 @@ socket_message[1] = function(id, size, data)
return
end
local sz = driver.push(s.buffer, buffer_pool, data, size)
local ok , sz = pcall(driver.push, s.buffer, buffer_pool, data, size)
if not ok then
skynet.error("socket: error on ", id , sz)
driver.clear(s.buffer,buffer_pool)
driver.close(id)
return
end
local rr = s.read_required
local rrt = type(rr)
if rrt == "number" then
@@ -123,7 +130,7 @@ skynet.register_protocol {
local function connect(id, func)
local newbuffer
if func == nil then
newbuffer = driver.buffer()
newbuffer = driver.buffer(buffer_limit)
end
local s = {
id = id,
@@ -151,7 +158,7 @@ function socket.bind(os_fd)
end
function socket.stdin()
return socket.bind(1)
return socket.bind(0)
end
function socket.start(id, func)
@@ -266,12 +273,19 @@ end
socket.write = assert(driver.send)
socket.lwrite = assert(driver.lsend)
socket.header = assert(driver.header)
function socket.invalid(id)
return socket_pool[id] == nil
end
socket.listen = assert(driver.listen)
function socket.listen(host, port, backlog)
if port == nil then
host, port = string.match(host, "([^:]+):(.+)$")
port = tonumber(port)
end
return driver.listen(host, port, backlog)
end
function socket.lock(id)
local s = socket_pool[id]
@@ -311,4 +325,8 @@ function socket.abandon(id)
socket_pool[id] = nil
end
function socket.limit(limit)
buffer_limit = limit
end
return socket

View File

@@ -135,6 +135,9 @@ local function dispatch_by_order(self)
if result ~= socket_error then
errmsg = result_ok
end
self.__result[co] = socket_error
self.__result_data[co] = errmsg
skynet.wakeup(co)
wakeup_all(self, errmsg)
end
end

View File

@@ -2,6 +2,16 @@
#include "skynet_harbor.h"
#include "skynet_socket.h"
/*
harbor listen the PTYPE_HARBOR (in text)
N name : update the global name
S fd id: connect to new harbor , we should send self_id to fd first , and then recv a id (check it), and at last send queue.
A fd id: accept new harbor , we should send self_id to fd , and then send queue.
If the fd is disconnected, send message to slave in PTYPE_TEXT. D id
If we don't known a globalname, send message to slave in PTYPE_TEXT. Q name
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@@ -13,8 +23,22 @@
#define HASH_SIZE 4096
#define DEFAULT_QUEUE_SIZE 1024
// 12 is sizeof(struct remote_message_header)
#define HEADER_COOKIE_LENGTH 12
/*
message type (8bits) is in destination high 8bits
harbor id (8bits) is also in that place , but remote message doesn't need harbor id.
*/
struct remote_message_header {
uint32_t source;
uint32_t destination;
uint32_t session;
};
struct msg {
uint8_t * buffer;
struct remote_message_header header;
void * buffer;
size_t size;
};
@@ -37,32 +61,34 @@ struct hashmap {
struct keyvalue *node[HASH_SIZE];
};
/*
message type (8bits) is in destination high 8bits
harbor id (8bits) is also in that place , but remote message doesn't need harbor id.
*/
struct remote_message_header {
uint32_t source;
uint32_t destination;
uint32_t session;
#define STATUS_WAIT 0
#define STATUS_HANDSHAKE 1
#define STATUS_HEADER 2
#define STATUS_CONTENT 3
#define STATUS_DOWN 4
struct slave {
int fd;
struct msg_queue *queue;
int status;
int length;
int read;
uint8_t size[4];
char * recv_buffer;
};
struct harbor {
struct skynet_context *ctx;
char * local_addr;
int id;
uint32_t slave;
struct hashmap * map;
int master_fd;
char * master_addr;
int remote_fd[REMOTE_MAX];
bool connected[REMOTE_MAX];
char * remote_addr[REMOTE_MAX];
struct slave s[REMOTE_MAX];
};
// hash table
static void
_push_queue(struct msg_queue * queue, const void * buffer, size_t sz, struct remote_message_header * header) {
push_queue_msg(struct msg_queue * queue, struct msg * m) {
// If there is only 1 free slot which is reserved to distinguish full/empty
// of circular buffer, expand it.
if (((queue->tail + 1) % queue->size) == queue->head) {
@@ -78,16 +104,21 @@ _push_queue(struct msg_queue * queue, const void * buffer, size_t sz, struct rem
queue->size *= 2;
}
struct msg * slot = &queue->data[queue->tail];
*slot = *m;
queue->tail = (queue->tail + 1) % queue->size;
}
slot->buffer = skynet_malloc(sz + sizeof(*header));
memcpy(slot->buffer, buffer, sz);
memcpy(slot->buffer + sz, header, sizeof(*header));
slot->size = sz + sizeof(*header);
static void
push_queue(struct msg_queue * queue, void * buffer, size_t sz, struct remote_message_header * header) {
struct msg m;
m.header = *header;
m.buffer = buffer;
m.size = sz;
push_queue_msg(queue, &m);
}
static struct msg *
_pop_queue(struct msg_queue * queue) {
pop_queue(struct msg_queue * queue) {
if (queue->head == queue->tail) {
return NULL;
}
@@ -97,7 +128,7 @@ _pop_queue(struct msg_queue * queue) {
}
static struct msg_queue *
_new_queue() {
new_queue() {
struct msg_queue * queue = skynet_malloc(sizeof(*queue));
queue->size = DEFAULT_QUEUE_SIZE;
queue->head = 0;
@@ -108,20 +139,19 @@ _new_queue() {
}
static void
_release_queue(struct msg_queue *queue) {
release_queue(struct msg_queue *queue) {
if (queue == NULL)
return;
struct msg * m = _pop_queue(queue);
while (m) {
struct msg * m;
while ((m=pop_queue(queue)) != NULL) {
skynet_free(m->buffer);
m = _pop_queue(queue);
}
skynet_free(queue->data);
skynet_free(queue);
}
static struct keyvalue *
_hash_search(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
hash_search(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
uint32_t *ptr = (uint32_t*) name;
uint32_t h = ptr[0] ^ ptr[1] ^ ptr[2] ^ ptr[3];
struct keyvalue * node = hash->node[h % HASH_SIZE];
@@ -139,7 +169,7 @@ _hash_search(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
// Don't support erase name yet
static struct void
_hash_erase(struct hashmap * hash, char name[GLOBALNAME_LENGTH) {
hash_erase(struct hashmap * hash, char name[GLOBALNAME_LENGTH) {
uint32_t *ptr = name;
uint32_t h = ptr[0] ^ ptr[1] ^ ptr[2] ^ ptr[3];
struct keyvalue ** ptr = &hash->node[h % HASH_SIZE];
@@ -157,7 +187,7 @@ _hash_erase(struct hashmap * hash, char name[GLOBALNAME_LENGTH) {
*/
static struct keyvalue *
_hash_insert(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
hash_insert(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
uint32_t *ptr = (uint32_t *)name;
uint32_t h = ptr[0] ^ ptr[1] ^ ptr[2] ^ ptr[3];
struct keyvalue ** pkv = &hash->node[h % HASH_SIZE];
@@ -173,20 +203,20 @@ _hash_insert(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
}
static struct hashmap *
_hash_new() {
hash_new() {
struct hashmap * h = skynet_malloc(sizeof(struct hashmap));
memset(h,0,sizeof(*h));
return h;
}
static void
_hash_delete(struct hashmap *hash) {
hash_delete(struct hashmap *hash) {
int i;
for (i=0;i<HASH_SIZE;i++) {
struct keyvalue * node = hash->node[i];
while (node) {
struct keyvalue * next = node->next;
_release_queue(node->queue);
release_queue(node->queue);
skynet_free(node);
node = next;
}
@@ -196,64 +226,50 @@ _hash_delete(struct hashmap *hash) {
///////////////
static void
close_harbor(struct harbor *h, int id) {
struct slave *s = &h->s[id];
s->status = STATUS_DOWN;
if (s->fd) {
skynet_socket_close(h->ctx, s->fd);
}
if (s->queue) {
release_queue(s->queue);
s->queue = NULL;
}
}
static void
report_harbor_down(struct harbor *h, int id) {
char down[64];
int n = sprintf(down, "D %d",id);
skynet_send(h->ctx, 0, h->slave, PTYPE_TEXT, 0, down, n);
}
struct harbor *
harbor_create(void) {
struct harbor * h = skynet_malloc(sizeof(*h));
h->ctx = NULL;
h->id = 0;
h->master_fd = -1;
h->master_addr = NULL;
int i;
for (i=0;i<REMOTE_MAX;i++) {
h->remote_fd[i] = -1;
h->connected[i] = false;
h->remote_addr[i] = NULL;
}
h->map = _hash_new();
memset(h,0,sizeof(*h));
h->map = hash_new();
return h;
}
void
harbor_release(struct harbor *h) {
struct skynet_context *ctx = h->ctx;
if (h->master_fd >= 0) {
skynet_socket_close(ctx, h->master_fd);
}
skynet_free(h->master_addr);
skynet_free(h->local_addr);
int i;
for (i=0;i<REMOTE_MAX;i++) {
if (h->remote_fd[i] >= 0) {
skynet_socket_close(ctx, h->remote_fd[i]);
skynet_free(h->remote_addr[i]);
for (i=1;i<REMOTE_MAX;i++) {
struct slave *s = &h->s[i];
if (s->fd && s->status != STATUS_DOWN) {
close_harbor(h,i);
// don't call report_harbor_down.
// never call skynet_send during module exit, because of dead lock
}
}
_hash_delete(h->map);
hash_delete(h->map);
skynet_free(h);
}
static int
_connect_to(struct harbor *h, const char *ipaddress, bool blocking) {
char * port = strchr(ipaddress,':');
if (port==NULL) {
return -1;
}
int sz = port - ipaddress;
char tmp[sz + 1];
memcpy(tmp,ipaddress,sz);
tmp[sz] = '\0';
int portid = strtol(port+1, NULL,10);
skynet_error(h->ctx, "Harbor(%d) connect to %s:%d", h->id, tmp, portid);
if (blocking) {
return skynet_socket_block_connect(h->ctx, tmp, portid);
} else {
return skynet_socket_connect(h->ctx, tmp, portid);
}
}
static inline void
to_bigendian(uint8_t *buffer, uint32_t n) {
buffer[0] = (n >> 24) & 0xff;
@@ -263,7 +279,7 @@ to_bigendian(uint8_t *buffer, uint32_t n) {
}
static inline void
_header_to_message(const struct remote_message_header * header, uint8_t * message) {
header_to_message(const struct remote_message_header * header, uint8_t * message) {
to_bigendian(message , header->source);
to_bigendian(message+4 , header->destination);
to_bigendian(message+8 , header->session);
@@ -280,112 +296,207 @@ from_bigendian(uint32_t n) {
}
static inline void
_message_to_header(const uint32_t *message, struct remote_message_header *header) {
message_to_header(const uint32_t *message, struct remote_message_header *header) {
header->source = from_bigendian(message[0]);
header->destination = from_bigendian(message[1]);
header->session = from_bigendian(message[2]);
}
static void
_send_package(struct skynet_context *ctx, int fd, const void * buffer, size_t sz) {
uint8_t * sendbuf = skynet_malloc(sz+4);
to_bigendian(sendbuf, sz);
memcpy(sendbuf+4, buffer, sz);
// socket package
if (skynet_socket_send(ctx, fd, sendbuf, sz+4)) {
skynet_error(ctx, "Send to %d error", fd);
static void
forward_local_messsage(struct harbor *h, void *msg, int sz) {
const char * cookie = msg;
cookie += sz - HEADER_COOKIE_LENGTH;
struct remote_message_header header;
message_to_header((const uint32_t *)cookie, &header);
uint32_t destination = header.destination;
int type = (destination >> HANDLE_REMOTE_SHIFT) | PTYPE_TAG_DONTCOPY;
destination = (destination & HANDLE_MASK) | ((uint32_t)h->id << HANDLE_REMOTE_SHIFT);
if (skynet_send(h->ctx, header.source, destination, type, (int)header.session, (void *)msg, sz-HEADER_COOKIE_LENGTH) < 0) {
skynet_error(h->ctx, "Unknown destination :%x from :%x", destination, header.source);
}
}
static void
_send_remote(struct skynet_context * ctx, int fd, const char * buffer, size_t sz, struct remote_message_header * cookie) {
send_remote(struct skynet_context * ctx, int fd, const char * buffer, size_t sz, struct remote_message_header * cookie) {
uint32_t sz_header = sz+sizeof(*cookie);
uint8_t * sendbuf = skynet_malloc(sz_header+4);
to_bigendian(sendbuf, sz_header);
memcpy(sendbuf+4, buffer, sz);
_header_to_message(cookie, sendbuf+4+sz);
header_to_message(cookie, sendbuf+4+sz);
if (skynet_socket_send(ctx, fd, sendbuf, sz_header+4)) {
skynet_error(ctx, "Remote send to %d error", fd);
}
// ignore send error, because if the connection is broken, the mainloop will recv a message.
skynet_socket_send(ctx, fd, sendbuf, sz_header+4);
}
static void
_update_remote_address(struct harbor *h, int harbor_id, const char * ipaddr) {
if (harbor_id == h->id) {
return;
}
assert(harbor_id > 0 && harbor_id< REMOTE_MAX);
struct skynet_context * context = h->ctx;
if (h->remote_fd[harbor_id] >=0) {
skynet_socket_close(context, h->remote_fd[harbor_id]);
skynet_free(h->remote_addr[harbor_id]);
h->remote_addr[harbor_id] = NULL;
}
h->remote_fd[harbor_id] = _connect_to(h, ipaddr, false);
h->connected[harbor_id] = false;
}
static void
_dispatch_queue(struct harbor *h, struct msg_queue * queue, uint32_t handle, const char name[GLOBALNAME_LENGTH] ) {
dispatch_name_queue(struct harbor *h, struct keyvalue * node) {
struct msg_queue * queue = node->queue;
uint32_t handle = node->value;
int harbor_id = handle >> HANDLE_REMOTE_SHIFT;
assert(harbor_id != 0);
struct skynet_context * context = h->ctx;
int fd = h->remote_fd[harbor_id];
if (fd < 0) {
char tmp [GLOBALNAME_LENGTH+1];
memcpy(tmp, name , GLOBALNAME_LENGTH);
tmp[GLOBALNAME_LENGTH] = '\0';
skynet_error(context, "Drop message to %s (in harbor %d)",tmp,harbor_id);
struct slave *s = &h->s[harbor_id];
int fd = s->fd;
if (fd == 0) {
if (s->status == STATUS_DOWN) {
char tmp [GLOBALNAME_LENGTH+1];
memcpy(tmp, node->key, GLOBALNAME_LENGTH);
tmp[GLOBALNAME_LENGTH] = '\0';
skynet_error(context, "Drop message to %s (in harbor %d)",tmp,harbor_id);
} else {
if (s->queue == NULL) {
s->queue = node->queue;
node->queue = NULL;
} else {
struct msg * m;
while ((m = pop_queue(queue))!=NULL) {
push_queue_msg(s->queue, m);
}
}
}
return;
}
struct msg * m = _pop_queue(queue);
while (m) {
struct remote_message_header cookie;
uint8_t *ptr = m->buffer + m->size - sizeof(cookie);
memcpy(&cookie, ptr, sizeof(cookie));
cookie.destination |= (handle & HANDLE_MASK);
_header_to_message(&cookie, ptr);
_send_package(context, fd, m->buffer, m->size);
m = _pop_queue(queue);
struct msg * m;
while ((m = pop_queue(queue)) != NULL) {
m->header.destination |= (handle & HANDLE_MASK);
send_remote(context, fd, m->buffer, m->size, &m->header);
}
}
static void
_update_remote_name(struct harbor *h, const char name[GLOBALNAME_LENGTH], uint32_t handle) {
struct keyvalue * node = _hash_search(h->map, name);
dispatch_queue(struct harbor *h, int id) {
struct slave *s = &h->s[id];
int fd = s->fd;
assert(fd != 0);
struct msg_queue *queue = s->queue;
if (queue == NULL)
return;
struct msg * m;
while ((m = pop_queue(queue)) != NULL) {
send_remote(h->ctx, fd, m->buffer, m->size, &m->header);
}
release_queue(queue);
s->queue = NULL;
}
static void
push_socket_data(struct harbor *h, const struct skynet_socket_message * message) {
assert(message->type == SKYNET_SOCKET_TYPE_DATA);
int fd = message->id;
int i;
int id = 0;
struct slave * s = NULL;
for (i=1;i<REMOTE_MAX;i++) {
if (h->s[i].fd == fd) {
s = &h->s[i];
id = i;
break;
}
}
if (s == NULL) {
skynet_free(message->buffer);
skynet_error(h->ctx, "Invalid socket fd (%d) data", fd);
return;
}
uint8_t * buffer = (uint8_t *)message->buffer;
int size = message->ud;
for (;;) {
switch(s->status) {
case STATUS_HANDSHAKE: {
// check id
uint8_t remote_id = buffer[0];
if (remote_id != id) {
skynet_error(h->ctx, "Invalid shakehand id (%d) from fd = %d , harbor = %d", id, fd, remote_id);
close_harbor(h,id);
return;
}
++buffer;
--size;
s->status = STATUS_HEADER;
dispatch_queue(h, id);
if (size == 0) {
break;
}
// go though
}
case STATUS_HEADER: {
// big endian 4 bytes length, the first one must be 0.
int need = 4 - s->read;
if (size < need) {
memcpy(s->size + s->read, buffer, size);
s->read += size;
return;
} else {
memcpy(s->size + s->read, buffer, need);
buffer += need;
size -= need;
if (s->size[0] != 0) {
skynet_error(h->ctx, "Message is too long from harbor %d", id);
close_harbor(h,id);
return;
}
s->length = s->size[1] << 16 | s->size[2] << 8 | s->size[3];
s->read = 0;
s->recv_buffer = skynet_malloc(s->length);
s->status = STATUS_CONTENT;
if (size == 0) {
return;
}
}
}
// go though
case STATUS_CONTENT: {
int need = s->length - s->read;
if (size < need) {
memcpy(s->recv_buffer + s->read, buffer, size);
s->read += size;
return;
}
memcpy(s->recv_buffer + s->read, buffer, need);
forward_local_messsage(h, s->recv_buffer, s->length);
s->length = 0;
s->read = 0;
s->recv_buffer = NULL;
size -= need;
buffer += need;
s->status = STATUS_HEADER;
if (size == 0)
return;
break;
}
default:
return;
}
}
}
static void
update_name(struct harbor *h, const char name[GLOBALNAME_LENGTH], uint32_t handle) {
struct keyvalue * node = hash_search(h->map, name);
if (node == NULL) {
node = _hash_insert(h->map, name);
node = hash_insert(h->map, name);
}
node->value = handle;
if (node->queue) {
_dispatch_queue(h, node->queue, handle, name);
_release_queue(node->queue);
dispatch_name_queue(h, node);
release_queue(node->queue);
node->queue = NULL;
}
}
static void
_request_master(struct harbor *h, const char name[GLOBALNAME_LENGTH], size_t i, uint32_t handle) {
uint8_t buffer[4+i];
to_bigendian(buffer, handle);
memcpy(buffer+4,name,i);
_send_package(h->ctx, h->master_fd, buffer, 4+i);
}
/*
update global name to master
2 bytes (size)
4 bytes (handle) (handle == 0 for request)
n bytes string (name)
*/
static int
_remote_send_handle(struct harbor *h, uint32_t source, uint32_t destination, int type, int session, const char * msg, size_t sz) {
remote_send_handle(struct harbor *h, uint32_t source, uint32_t destination, int type, int session, const char * msg, size_t sz) {
int harbor_id = destination >> HANDLE_REMOTE_SHIFT;
assert(harbor_id != 0);
struct skynet_context * context = h->ctx;
if (harbor_id == h->id) {
// local message
@@ -393,55 +504,117 @@ _remote_send_handle(struct harbor *h, uint32_t source, uint32_t destination, int
return 1;
}
int fd = h->remote_fd[harbor_id];
if (fd >= 0 && h->connected[harbor_id]) {
struct slave * s = &h->s[harbor_id];
if (s->fd == 0 || s->status == STATUS_HANDSHAKE) {
if (s->status == STATUS_DOWN) {
// throw an error return to source
// report the destination is dead
skynet_send(context, destination, source, PTYPE_ERROR, 0 , NULL, 0);
skynet_error(context, "Drop message to harbor %d from %x to %x (session = %d, msgsz = %d)",harbor_id, source, destination,session,(int)sz);
} else {
if (s->queue == NULL) {
s->queue = new_queue();
}
struct remote_message_header header;
header.source = source;
header.destination = (type << HANDLE_REMOTE_SHIFT) | (destination & HANDLE_MASK);
header.session = (uint32_t)session;
push_queue(s->queue, (void *)msg, sz, &header);
return 1;
}
} else {
struct remote_message_header cookie;
cookie.source = source;
cookie.destination = (destination & HANDLE_MASK) | ((uint32_t)type << HANDLE_REMOTE_SHIFT);
cookie.session = (uint32_t)session;
_send_remote(context, fd, msg,sz,&cookie);
} else {
// throw an error return to source
// report the destination is dead
skynet_send(context, destination, source, PTYPE_ERROR, 0 , NULL, 0);
skynet_error(context, "Drop message to harbor %d from %x to %x (session = %d, msgsz = %d)",harbor_id, source, destination,session,(int)sz);
send_remote(context, s->fd, msg,sz,&cookie);
}
return 0;
}
static void
_remote_register_name(struct harbor *h, const char name[GLOBALNAME_LENGTH], uint32_t handle) {
int i;
for (i=0;i<GLOBALNAME_LENGTH;i++) {
if (name[i] == '\0')
break;
}
if (handle != 0) {
_update_remote_name(h, name, handle);
}
_request_master(h, name,i,handle);
}
static int
_remote_send_name(struct harbor *h, uint32_t source, const char name[GLOBALNAME_LENGTH], int type, int session, const char * msg, size_t sz) {
struct keyvalue * node = _hash_search(h->map, name);
remote_send_name(struct harbor *h, uint32_t source, const char name[GLOBALNAME_LENGTH], int type, int session, const char * msg, size_t sz) {
struct keyvalue * node = hash_search(h->map, name);
if (node == NULL) {
node = _hash_insert(h->map, name);
node = hash_insert(h->map, name);
}
if (node->value == 0) {
if (node->queue == NULL) {
node->queue = _new_queue();
node->queue = new_queue();
}
struct remote_message_header header;
header.source = source;
header.destination = type << HANDLE_REMOTE_SHIFT;
header.session = (uint32_t)session;
_push_queue(node->queue, msg, sz, &header);
// 0 for request
_remote_register_name(h, name, 0);
push_queue(node->queue, (void *)msg, sz, &header);
char query[2+GLOBALNAME_LENGTH+1] = "Q ";
query[2+GLOBALNAME_LENGTH] = 0;
memcpy(query+2, name, GLOBALNAME_LENGTH);
skynet_send(h->ctx, 0, h->slave, PTYPE_TEXT, 0, query, strlen(query));
return 1;
} else {
return _remote_send_handle(h, source, node->value, type, session, msg, sz);
return remote_send_handle(h, source, node->value, type, session, msg, sz);
}
}
static void
handshake(struct harbor *h, int id) {
struct slave *s = &h->s[id];
uint8_t * handshake = skynet_malloc(1);
handshake[0] = (uint8_t)h->id;
skynet_socket_send(h->ctx, s->fd, handshake, 1);
}
static void
harbor_command(struct harbor * h, const char * msg, size_t sz, int session, uint32_t source) {
const char * name = msg + 2;
int s = (int)sz;
s -= 2;
switch(msg[0]) {
case 'N' : {
if (s <=0 || s>= GLOBALNAME_LENGTH) {
skynet_error(h->ctx, "Invalid global name %s", name);
return;
}
struct remote_name rn;
memset(&rn, 0, sizeof(rn));
memcpy(rn.name, name, s);
rn.handle = source;
update_name(h, rn.name, rn.handle);
break;
}
case 'S' :
case 'A' : {
char buffer[s+1];
memcpy(buffer, name, s);
buffer[s] = 0;
int fd=0, id=0;
sscanf(buffer, "%d %d",&fd,&id);
if (fd == 0 || id <= 0 || id>=REMOTE_MAX) {
skynet_error(h->ctx, "Invalid command %c %s", msg[0], buffer);
return;
}
struct slave * slave = &h->s[id];
if (slave->fd != 0) {
skynet_error(h->ctx, "Harbor %d alreay exist", id);
return;
}
slave->fd = fd;
skynet_socket_start(h->ctx, fd);
handshake(h, id);
if (msg[0] == 'S') {
slave->status = STATUS_HANDSHAKE;
} else {
slave->status = STATUS_HEADER;
dispatch_queue(h,id);
}
break;
}
default:
skynet_error(h->ctx, "Unknown command %s", msg);
return;
}
}
@@ -449,105 +622,57 @@ static int
harbor_id(struct harbor *h, int fd) {
int i;
for (i=1;i<REMOTE_MAX;i++) {
if (h->remote_fd[i] == fd)
struct slave *s = &h->s[i];
if (s->fd == fd) {
return i;
}
}
return 0;
}
static void
close_harbor(struct harbor *h, int fd) {
int id = harbor_id(h,fd);
if (id == 0)
return;
skynet_error(h->ctx, "Harbor %d closed",id);
skynet_socket_close(h->ctx, fd);
h->remote_fd[id] = -1;
h->connected[id] = false;
}
static void
open_harbor(struct harbor *h, int fd) {
int id = harbor_id(h,fd);
if (id == 0)
return;
assert(h->connected[id] == false);
h->connected[id] = true;
}
static int
_mainloop(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
mainloop(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
struct harbor * h = ud;
switch (type) {
case PTYPE_SOCKET: {
const struct skynet_socket_message * message = msg;
switch(message->type) {
case SKYNET_SOCKET_TYPE_DATA:
push_socket_data(h, message);
skynet_free(message->buffer);
skynet_error(context, "recv invalid socket message (size=%d)", message->ud);
break;
case SKYNET_SOCKET_TYPE_ACCEPT:
skynet_error(context, "recv invalid socket accept message");
break;
case SKYNET_SOCKET_TYPE_ERROR:
case SKYNET_SOCKET_TYPE_CLOSE:
close_harbor(h, message->id);
case SKYNET_SOCKET_TYPE_CLOSE: {
int id = harbor_id(h, message->id);
if (id) {
report_harbor_down(h,id);
} else {
skynet_error(context, "Unkown fd (%d) closed", message->id);
}
break;
}
case SKYNET_SOCKET_TYPE_CONNECT:
open_harbor(h, message->id);
// fd forward to this service
break;
default:
skynet_error(context, "recv invalid socket message type %d", type);
break;
}
return 0;
}
case PTYPE_HARBOR: {
// remote message in
const char * cookie = msg;
cookie += sz - 12;
struct remote_message_header header;
_message_to_header((const uint32_t *)cookie, &header);
if (header.source == 0) {
if (header.destination < REMOTE_MAX) {
// 1 byte harbor id (0~255)
// update remote harbor address
char ip [sz - 11];
memcpy(ip, msg, sz-12);
ip[sz-11] = '\0';
_update_remote_address(h, header.destination, ip);
} else {
// update global name
if (sz - 12 > GLOBALNAME_LENGTH) {
char name[sz-11];
memcpy(name, msg, sz-12);
name[sz-11] = '\0';
skynet_error(context, "Global name is too long %s", name);
}
_update_remote_name(h, msg, header.destination);
}
} else {
uint32_t destination = header.destination;
int type = (destination >> HANDLE_REMOTE_SHIFT) | PTYPE_TAG_DONTCOPY;
destination = (destination & HANDLE_MASK) | ((uint32_t)h->id << HANDLE_REMOTE_SHIFT);
skynet_send(context, header.source, destination, type, (int)header.session, (void *)msg, sz-12);
return 1;
}
return 0;
}
case PTYPE_SYSTEM: {
// register name message
const struct remote_message *rmsg = msg;
assert (sz == sizeof(rmsg->destination));
_remote_register_name(h, rmsg->destination.name, rmsg->destination.handle);
harbor_command(h, msg,sz,session,source);
return 0;
}
default: {
// remote message out
const struct remote_message *rmsg = msg;
if (rmsg->destination.handle == 0) {
if (_remote_send_name(h, source , rmsg->destination.name, type, session, rmsg->message, rmsg->sz)) {
if (remote_send_name(h, source , rmsg->destination.name, type, session, rmsg->message, rmsg->sz)) {
return 0;
}
} else {
if (_remote_send_handle(h, source , rmsg->destination.handle, type, session, rmsg->message, rmsg->sz)) {
if (remote_send_handle(h, source , rmsg->destination.handle, type, session, rmsg->message, rmsg->sz)) {
return 0;
}
}
@@ -557,48 +682,19 @@ _mainloop(struct skynet_context * context, void * ud, int type, int session, uin
}
}
static void
_launch_gate(struct skynet_context * ctx, const char * local_addr) {
char tmp[128];
sprintf(tmp,"gate L ! %s %d %d 0",local_addr, PTYPE_HARBOR, REMOTE_MAX);
const char * gate_addr = skynet_command(ctx, "LAUNCH", tmp);
if (gate_addr == NULL) {
fprintf(stderr, "Harbor : launch gate failed\n");
exit(1);
}
uint32_t gate = strtoul(gate_addr+1 , NULL, 16);
if (gate == 0) {
fprintf(stderr, "Harbor : launch gate invalid %s", gate_addr);
exit(1);
}
const char * self_addr = skynet_command(ctx, "REG", NULL);
int n = sprintf(tmp,"broker %s",self_addr);
skynet_send(ctx, 0, gate, PTYPE_TEXT, 0, tmp, n);
skynet_send(ctx, 0, gate, PTYPE_TEXT, 0, "start", 5);
}
int
harbor_init(struct harbor *h, struct skynet_context *ctx, const char * args) {
h->ctx = ctx;
int sz = strlen(args)+1;
char master_addr[sz];
char local_addr[sz];
int harbor_id = 0;
sscanf(args,"%s %s %d",master_addr, local_addr, &harbor_id);
h->master_addr = skynet_strdup(master_addr);
h->id = harbor_id;
h->master_fd = _connect_to(h, master_addr, true);
if (h->master_fd == -1) {
fprintf(stderr, "Harbor: Connect to master failed\n");
exit(1);
uint32_t slave = 0;
sscanf(args,"%d %u", &harbor_id, &slave);
if (slave == 0) {
return 1;
}
h->id = harbor_id;
h->slave = slave;
skynet_callback(ctx, h, mainloop);
skynet_harbor_start(ctx);
h->local_addr = skynet_strdup(local_addr);
_launch_gate(ctx, local_addr);
skynet_callback(ctx, h, _mainloop);
_request_master(h, local_addr, strlen(local_addr), harbor_id);
return 0;
}

View File

@@ -28,7 +28,7 @@ logger_release(struct logger * inst) {
static int
_logger(struct skynet_context * context, void *ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
struct logger * inst = ud;
fprintf(inst->handle, "[:%x] ",source);
fprintf(inst->handle, "[:%08x] ",source);
fwrite(msg, sz , 1, inst->handle);
fprintf(inst->handle, "\n");
fflush(inst->handle);

View File

@@ -1,313 +0,0 @@
#include "skynet.h"
#include "skynet_harbor.h"
#include "skynet_socket.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#define HASH_SIZE 4096
struct name {
struct name * next;
char key[GLOBALNAME_LENGTH];
uint32_t hash;
uint32_t value;
};
struct namemap {
struct name *node[HASH_SIZE];
};
struct master {
struct skynet_context *ctx;
int remote_fd[REMOTE_MAX];
bool connected[REMOTE_MAX];
char * remote_addr[REMOTE_MAX];
struct namemap map;
};
struct master *
master_create() {
struct master *m = skynet_malloc(sizeof(*m));
int i;
for (i=0;i<REMOTE_MAX;i++) {
m->remote_fd[i] = -1;
m->remote_addr[i] = NULL;
m->connected[i] = false;
}
memset(&m->map, 0, sizeof(m->map));
return m;
}
void
master_release(struct master * m) {
int i;
struct skynet_context *ctx = m->ctx;
for (i=0;i<REMOTE_MAX;i++) {
int fd = m->remote_fd[i];
if (fd >= 0) {
assert(ctx);
skynet_socket_close(ctx, fd);
}
skynet_free(m->remote_addr[i]);
}
for (i=0;i<HASH_SIZE;i++) {
struct name * node = m->map.node[i];
while (node) {
struct name * next = node->next;
skynet_free(node);
node = next;
}
}
skynet_free(m);
}
static struct name *
_search_name(struct master *m, char name[GLOBALNAME_LENGTH]) {
uint32_t *ptr = (uint32_t *) name;
uint32_t h = ptr[0] ^ ptr[1] ^ ptr[2] ^ ptr[3];
struct name * node = m->map.node[h % HASH_SIZE];
while (node) {
if (node->hash == h && strncmp(node->key, name, GLOBALNAME_LENGTH) == 0) {
return node;
}
node = node->next;
}
return NULL;
}
static struct name *
_insert_name(struct master *m, char name[GLOBALNAME_LENGTH]) {
uint32_t *ptr = (uint32_t *)name;
uint32_t h = ptr[0] ^ ptr[1] ^ ptr[2] ^ ptr[3];
struct name **pname = &m->map.node[h % HASH_SIZE];
struct name * node = skynet_malloc(sizeof(*node));
memcpy(node->key, name, GLOBALNAME_LENGTH);
node->next = *pname;
node->hash = h;
node->value = 0;
*pname = node;
return node;
}
static void
_copy_name(char *name, const char * buffer, size_t sz) {
if (sz < GLOBALNAME_LENGTH) {
memcpy(name, buffer, sz);
memset(name+sz, 0 , GLOBALNAME_LENGTH - sz);
} else {
memcpy(name, buffer, GLOBALNAME_LENGTH);
}
}
static void
_connect_to(struct master *m, int id) {
assert(m->connected[id] == false);
struct skynet_context * ctx = m->ctx;
const char *ipaddress = m->remote_addr[id];
char * portstr = strchr(ipaddress,':');
if (portstr==NULL) {
skynet_error(ctx, "Harbor %d : address invalid (%s)",id, ipaddress);
return;
}
int sz = portstr - ipaddress;
char tmp[sz + 1];
memcpy(tmp,ipaddress,sz);
tmp[sz] = '\0';
int port = strtol(portstr+1,NULL,10);
skynet_error(ctx, "Master connect to harbor(%d) %s:%d", id, tmp, port);
m->remote_fd[id] = skynet_socket_connect(ctx, tmp, port);
}
static inline void
to_bigendian(uint8_t *buffer, uint32_t n) {
buffer[0] = (n >> 24) & 0xff;
buffer[1] = (n >> 16) & 0xff;
buffer[2] = (n >> 8) & 0xff;
buffer[3] = n & 0xff;
}
static void
_send_to(struct master *m, int id, const void * buf, int sz, uint32_t handle) {
uint8_t * buffer= (uint8_t *)skynet_malloc(4 + sz + 12);
to_bigendian(buffer, sz+12);
memcpy(buffer+4, buf, sz);
to_bigendian(buffer+4+sz, 0);
to_bigendian(buffer+4+sz+4, handle);
to_bigendian(buffer+4+sz+8, 0);
sz += 4 + 12;
if (skynet_socket_send(m->ctx, m->remote_fd[id], buffer, sz)) {
skynet_error(m->ctx, "Harbor %d : send error", id);
}
}
static void
_broadcast(struct master *m, const char *name, size_t sz, uint32_t handle) {
int i;
for (i=1;i<REMOTE_MAX;i++) {
int fd = m->remote_fd[i];
if (fd < 0 || m->connected[i]==false)
continue;
_send_to(m, i , name, sz, handle);
}
}
static void
_request_name(struct master *m, const char * buffer, size_t sz) {
char name[GLOBALNAME_LENGTH];
_copy_name(name, buffer, sz);
struct name * n = _search_name(m, name);
if (n == NULL) {
return;
}
_broadcast(m, name, GLOBALNAME_LENGTH, n->value);
}
static void
_update_name(struct master *m, uint32_t handle, const char * buffer, size_t sz) {
char name[GLOBALNAME_LENGTH];
_copy_name(name, buffer, sz);
struct name * n = _search_name(m, name);
if (n==NULL) {
n = _insert_name(m,name);
}
n->value = handle;
_broadcast(m,name,GLOBALNAME_LENGTH, handle);
}
static void
close_harbor(struct master *m, int harbor_id) {
if (m->connected[harbor_id]) {
struct skynet_context * context = m->ctx;
skynet_socket_close(context, m->remote_fd[harbor_id]);
m->remote_fd[harbor_id] = -1;
m->connected[harbor_id] = false;
}
}
static void
_update_address(struct master *m, int harbor_id, const char * buffer, size_t sz) {
if (m->remote_fd[harbor_id] >= 0) {
close_harbor(m, harbor_id);
}
skynet_free(m->remote_addr[harbor_id]);
char * addr = skynet_malloc(sz+1);
memcpy(addr, buffer, sz);
addr[sz] = '\0';
m->remote_addr[harbor_id] = addr;
_connect_to(m, harbor_id);
}
static int
socket_id(struct master *m, int id) {
int i;
for (i=1;i<REMOTE_MAX;i++) {
if (m->remote_fd[i] == id)
return i;
}
return 0;
}
static void
on_connected(struct master *m, int id) {
_broadcast(m, m->remote_addr[id], strlen(m->remote_addr[id]), id);
m->connected[id] = true;
int i;
for (i=1;i<REMOTE_MAX;i++) {
if (i == id)
continue;
const char * addr = m->remote_addr[i];
if (addr == NULL || m->connected[i] == false) {
continue;
}
_send_to(m, id , addr, strlen(addr), i);
}
}
static void
dispatch_socket(struct master *m, const struct skynet_socket_message *msg, int sz) {
int id = socket_id(m, msg->id);
switch(msg->type) {
case SKYNET_SOCKET_TYPE_CONNECT:
assert(id);
on_connected(m, id);
break;
case SKYNET_SOCKET_TYPE_ERROR:
skynet_error(m->ctx, "socket error on harbor %d", id);
// go though, close socket
case SKYNET_SOCKET_TYPE_CLOSE:
close_harbor(m, id);
break;
default:
skynet_error(m->ctx, "Invalid socket message type %d", msg->type);
break;
}
}
/*
update global name to master
4 bytes (handle) (handle == 0 for request)
n bytes string (name)
*/
static int
_mainloop(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
if (type == PTYPE_SOCKET) {
dispatch_socket(ud, msg, (int)sz);
return 0;
}
if (type != PTYPE_HARBOR) {
skynet_error(context, "None harbor message recv from %x (type = %d)", source, type);
return 0;
}
assert(sz >= 4);
struct master *m = ud;
const uint8_t *handlen = msg;
uint32_t handle = handlen[0]<<24 | handlen[1]<<16 | handlen[2]<<8 | handlen[3];
sz -= 4;
const char * name = msg;
name += 4;
if (handle == 0) {
_request_name(m , name, sz);
} else if (handle < REMOTE_MAX) {
_update_address(m , handle, name, sz);
} else {
_update_name(m , handle, name, sz);
}
return 0;
}
int
master_init(struct master *m, struct skynet_context *ctx, const char * args) {
char tmp[strlen(args) + 32];
sprintf(tmp,"gate L ! %s %d %d 0",args,PTYPE_HARBOR,REMOTE_MAX);
const char * gate_addr = skynet_command(ctx, "LAUNCH", tmp);
if (gate_addr == NULL) {
skynet_error(ctx, "Master : launch gate failed");
return 1;
}
uint32_t gate = strtoul(gate_addr+1, NULL, 16);
if (gate == 0) {
skynet_error(ctx, "Master : launch gate invalid %s", gate_addr);
return 1;
}
const char * self_addr = skynet_command(ctx, "REG", NULL);
int n = sprintf(tmp,"broker %s",self_addr);
skynet_send(ctx, 0, gate, PTYPE_TEXT, 0, tmp, n);
skynet_send(ctx, 0, gate, PTYPE_TEXT, 0, "start", 5);
skynet_callback(ctx, m, _mainloop);
m->ctx = ctx;
return 0;
}

View File

@@ -1,23 +1,38 @@
local skynet = require "skynet"
local harbor = require "skynet.harbor"
skynet.start(function()
assert(skynet.launch("logger", skynet.getenv "logger"))
local standalone = skynet.getenv "standalone"
local master_addr = skynet.getenv "master"
if standalone then
assert(skynet.launch("master", master_addr))
end
local local_addr = skynet.getenv "address"
local harbor_id = skynet.getenv "harbor"
assert(skynet.launch("harbor",master_addr, local_addr, harbor_id))
local launcher = assert(skynet.launch("snlua","launcher"))
skynet.name(".launcher", launcher)
local harbor_id = tonumber(skynet.getenv "harbor")
if harbor_id == 0 then
assert(standalone == nil)
standalone = true
skynet.setenv("standalone", "true")
local slave = skynet.newservice "cdummy"
if slave == nil then
skynet.abort()
end
skynet.name(".slave", slave)
else
if standalone then
if not skynet.newservice "cmaster" then
skynet.abort()
end
end
local slave = skynet.newservice "cslave"
if slave == nil then
skynet.abort()
end
skynet.name(".slave", slave)
end
if standalone then
local datacenter = assert(skynet.newservice "datacenterd")
skynet.name("DATACENTER", datacenter)

47
service/cdummy.lua Normal file
View File

@@ -0,0 +1,47 @@
local skynet = require "skynet"
local globalname = {}
local harbor = {}
skynet.register_protocol {
name = "harbor",
id = skynet.PTYPE_HARBOR,
pack = function(...) return ... end,
unpack = skynet.tostring,
}
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
pack = function(...) return ... end,
unpack = skynet.tostring,
}
function harbor.REGISTER(name, handle)
assert(globalname[name] == nil)
globalname[name] = handle
skynet.redirect(harbor_service, handle, "harbor", 0, "N " .. name)
end
function harbor.LINK(id)
skynet.ret()
end
function harbor.CONNECT(id)
skynet.error("Can't connect to other harbor in single node mode")
end
skynet.start(function()
local harbor_id = tonumber(skynet.getenv "harbor")
assert(harbor_id == 0)
skynet.dispatch("lua", function (session,source,command,...)
local f = assert(harbor[command])
f(...)
end)
skynet.dispatch("text", function(session,source,command)
-- ignore all the command
end)
harbor_service = assert(skynet.launch("harbor", harbor_id, skynet.self()))
end)

90
service/clusterd.lua Normal file
View File

@@ -0,0 +1,90 @@
local skynet = require "skynet"
local sc = require "socketchannel"
local socket = require "socket"
local cluster = require "cluster.c"
local config_name = skynet.getenv "cluster"
local node_address = {}
local function loadconfig()
local f = assert(io.open(config_name))
local source = f:read "*a"
f:close()
assert(load(source, "@"..config_name, "t", node_address))()
end
local node_session = {}
local command = {}
local function read_response(sock)
local sz = socket.header(sock:read(2))
local msg = sock:read(sz)
return cluster.unpackresponse(msg) -- session, ok, data
end
local function open_channel(t, key)
local host, port = string.match(node_address[key], "([^:]+):(.*)$")
local c = sc.channel {
host = host,
port = tonumber(port),
response = read_response,
}
assert(c:connect(true))
t[key] = c
node_session[key] = 1
return c
end
local node_channel = setmetatable({}, { __index = open_channel })
function command.reload()
loadconfig()
skynet.ret(skynet.pack(nil))
end
function command.listen(source, addr, port)
local gate = skynet.newservice("gate")
if port == nil then
addr, port = string.match(node_address[addr], "([^:]+):(.*)$")
end
skynet.call(gate, "lua", "open", { address = addr, port = port })
skynet.ret(skynet.pack(nil))
end
function command.req(source, node, addr, msg, sz)
local request
local c = node_channel[node]
local session = node_session[node]
-- msg is a local pointer, cluster.packrequest will free it
request, node_session[node] = cluster.packrequest(addr, session , msg, sz)
skynet.ret(c:request(request, session))
end
local request_fd = {}
function command.socket(source, subcmd, fd, msg)
if subcmd == "data" then
local addr, session, msg = cluster.unpackrequest(msg)
local ok , msg, sz = pcall(skynet.rawcall, addr, "lua", msg)
local response
if ok then
response = cluster.packresponse(session, true, msg, sz)
else
response = cluster.packresponse(session, false, msg)
end
socket.write(fd, response)
elseif subcmd == "open" then
skynet.error(string.format("socket accept from %s", msg))
skynet.call(source, "lua", "accept", fd)
else
skynet.error(string.format("socket %s %d : %s", subcmd, fd, msg))
end
end
skynet.start(function()
loadconfig()
skynet.dispatch("lua", function(session , source, cmd, ...)
local f = assert(command[cmd])
f(source, ...)
end)
end)

125
service/cmaster.lua Normal file
View File

@@ -0,0 +1,125 @@
local skynet = require "skynet"
local socket = require "socket"
--[[
master manage data :
1. all the slaves address : id -> ipaddr:port
2. all the global names : name -> address
master hold connections from slaves .
protocol slave->master :
package size 1 byte
type 1 byte :
'H' : HANDSHAKE, report slave id, and address.
'R' : REGISTER name address
'Q' : QUERY name
protocol master->slave:
package size 1 byte
type 1 byte :
'W' : WAIT n
'C' : CONNECT slave_id slave_address
'N' : NAME globalname address
'D' : DISCONNECT slave_id
]]
local slave_node = {}
local global_name = {}
local function read_package(fd)
local sz = socket.read(fd, 1)
assert(sz, "closed")
sz = string.byte(sz)
local content = socket.read(fd, sz)
return skynet.unpack(content)
end
local function pack_package(...)
local message = skynet.packstring(...)
local size = #message
assert(size <= 255 , "too long")
return string.char(size) .. message
end
local function report_slave(fd, slave_id, slave_addr)
local message = pack_package("C", slave_id, slave_addr)
local n = 0
for k,v in pairs(slave_node) do
if v.fd ~= 0 then
socket.write(v.fd, message)
n = n + 1
end
end
socket.write(fd, pack_package("W", n))
end
local function handshake(fd)
local t, slave_id, slave_addr = read_package(fd)
assert(t=='H', "Invalid handshake type " .. t)
assert(slave_id ~= 0 , "Invalid slave id 0")
if slave_node[slave_id] then
error(string.format("Slave %d already register on %s", slave_id, slave_node[slave_id].addr))
end
report_slave(fd, slave_id, slave_addr)
slave_node[slave_id] = {
fd = fd,
id = slave_id,
addr = slave_addr,
}
return slave_id , slave_addr
end
local function dispatch_slave(fd)
local t, name, address = read_package(fd)
if t == 'R' then
-- register name
assert(type(address)=="number", "Invalid request")
if not global_name[name] then
global_name[name] = address
end
local message = pack_package("N", name, address)
for k,v in pairs(slave_node) do
socket.write(v.fd, message)
end
elseif t == 'Q' then
-- query name
local address = global_name[name]
if address then
socket.write(fd, pack_package("N", name, address))
end
else
skynet.error("Invalid slave message type " .. t)
end
end
local function monitor_slave(slave_id, slave_address)
local fd = slave_node[slave_id].fd
skynet.error(string.format("Harbor %d (fd=%d) report %s", slave_id, fd, slave_address))
while pcall(dispatch_slave, fd) do end
skynet.error("slave " ..slave_id .. " is down")
local message = pack_package("D", slave_id)
slave_node[slave_id].fd = 0
for k,v in pairs(slave_node) do
socket.write(v.fd, message)
end
socket.close(fd)
end
skynet.start(function()
local master_addr = skynet.getenv "standalone"
skynet.error("master listen socket " .. tostring(master_addr))
local fd = socket.listen(master_addr)
socket.start(fd , function(id, addr)
skynet.error("connect from " .. addr .. " " .. id)
socket.start(id)
local ok, slave, slave_addr = pcall(handshake, id)
if ok then
skynet.fork(monitor_slave, slave, slave_addr)
else
skynet.error(string.format("disconnect fd = %d, error = %s", id, slave))
socket.close(id)
end
end)
end)

222
service/cslave.lua Normal file
View File

@@ -0,0 +1,222 @@
local skynet = require "skynet"
local socket = require "socket"
local slaves = {}
local connect_queue = {}
local globalname = {}
local harbor = {}
local harbor_service
local monitor = {}
local function read_package(fd)
local sz = socket.read(fd, 1)
assert(sz, "closed")
sz = string.byte(sz)
local content = socket.read(fd, sz)
return skynet.unpack(content)
end
local function pack_package(...)
local message = skynet.packstring(...)
local size = #message
assert(size <= 255 , "too long")
return string.char(size) .. message
end
local function monitor_clear(id)
local v = monitor[id]
if v then
monitor[id] = nil
for _, v in ipairs(v) do
skynet.redirect(v.address, 0, "response", v.session, "")
end
end
end
local function connect_slave(slave_id, address)
local ok, err = pcall(function()
if slaves[slave_id] == nil then
local fd = assert(socket.open(address), "Can't connect to "..address)
skynet.error(string.format("Connect to harbor %d (fd=%d), %s", slave_id, fd, address))
slaves[slave_id] = fd
monitor_clear(slave_id)
socket.abandon(fd)
skynet.send(harbor_service, "harbor", string.format("S %d %d",fd,slave_id))
end
end)
if not ok then
skynet.error(err)
end
end
local function ready()
local queue = connect_queue
connect_queue = nil
for k,v in pairs(queue) do
connect_slave(k,v)
end
for name,address in pairs(globalname) do
skynet.redirect(harbor_service, address, "harbor", "N " .. name)
end
end
local function monitor_master(master_fd)
while true do
local ok, t, id_name, address = pcall(read_package,master_fd)
if ok then
if t == 'C' then
if connect_queue then
connect_queue[id_name] = address
else
connect_slave(id_name, address)
end
elseif t == 'N' then
globalname[id_name] = address
if connect_queue == nil then
skynet.redirect(harbor_service, address, "harbor", 0, "N " .. id_name)
end
elseif t == 'D' then
local fd = slaves[id_name]
slaves[id_name] = false
if fd then
socket.close(fd)
end
end
else
skynet.error("Master disconnect")
socket.close(master_fd)
break
end
end
end
local function accept_slave(fd)
socket.start(fd)
local id = socket.read(fd, 1)
if not id then
skynet.error(string.format("Connection (fd =%d) closed", fd))
socket.close(fd)
return
end
id = string.byte(id)
if slaves[id] ~= nil then
skynet.error(string.format("Slave %d exist (fd =%d)", id, fd))
socket.close(fd)
return
end
slaves[id] = fd
monitor_clear(id)
socket.abandon(fd)
skynet.error(string.format("Harbor %d connected (fd = %d)", id, fd))
skynet.send(harbor_service, "harbor", string.format("A %d %d", fd, id))
end
skynet.register_protocol {
name = "harbor",
id = skynet.PTYPE_HARBOR,
pack = function(...) return ... end,
unpack = skynet.tostring,
}
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
pack = function(...) return ... end,
unpack = skynet.tostring,
}
local function monitor_harbor(master_fd)
return function(session, source, command)
local t = string.sub(command, 1, 1)
local arg = string.sub(command, 3)
if t == "Q" then
-- query name
if globalname[arg] then
skynet.redirect(harbor_service, globalname[arg], "harbor", 0, "N " .. arg)
else
socket.write(master_fd, pack_package("Q", arg))
end
elseif t == "D" then
-- harbor down
local id = tonumber(arg)
if slaves[id] then
monitor_clear(id)
end
slaves[id] = false
else
skynet.error("Unknown command ", command)
end
end
end
function harbor.REGISTER(_,_, fd, name, handle)
assert(globalname[name] == nil)
globalname[name] = handle
socket.write(fd, pack_package("R", name, handle))
skynet.redirect(harbor_service, handle, "harbor", 0, "N " .. name)
end
function harbor.LINK(session, source, fd, id)
if slaves[id] then
if monitor[id] == nil then
monitor[id] = {}
end
table.insert(monitor[id], { address = source, session = session })
else
skynet.ret()
end
end
function harbor.CONNECT(session, source, fd, id)
if not slaves[id] then
if monitor[id] == nil then
monitor[id] = {}
end
table.insert(monitor[id], { address = source, session = session })
else
skynet.ret()
end
end
skynet.start(function()
local master_addr = skynet.getenv "master"
local harbor_id = tonumber(skynet.getenv "harbor")
local slave_address = assert(skynet.getenv "address")
local slave_fd = socket.listen(slave_address)
skynet.error("slave connect to master " .. tostring(master_addr))
local master_fd = socket.open(master_addr)
skynet.dispatch("lua", function (session,source,command,...)
local f = assert(harbor[command])
f(session, source, master_fd, ...)
end)
skynet.dispatch("text", monitor_harbor(master_fd))
harbor_service = assert(skynet.launch("harbor", harbor_id, skynet.self()))
local hs_message = pack_package("H", harbor_id, slave_address)
socket.write(master_fd, hs_message)
local t, n = read_package(master_fd)
assert(t == "W" and type(n) == "number", "slave shakehand failed")
skynet.error(string.format("Waiting for %d harbors", n))
skynet.fork(monitor_master, master_fd)
if n > 0 then
local co = coroutine.running()
socket.start(slave_fd, function(fd, addr)
skynet.error(string.format("New connection (fd = %d, %s)",fd, addr))
if pcall(accept_slave,fd) then
local s = 0
for k,v in pairs(slaves) do
s = s + 1
end
if s >= n then
skynet.wakeup(co)
end
end
end)
skynet.wait()
end
socket.close(slave_fd)
skynet.error("Shakehand ready")
skynet.fork(ready)
end)

View File

@@ -2,6 +2,8 @@ local skynet = require "skynet"
local command = {}
local database = {}
local wait_queue = {}
local mode = {}
local function query(db, key, ...)
if key == nil then
@@ -22,7 +24,7 @@ local function update(db, key, value, ...)
if select("#",...) == 0 then
local ret = db[key]
db[key] = value
return ret
return ret, value
else
if db[key] == nil then
db[key] = {}
@@ -31,13 +33,82 @@ local function update(db, key, value, ...)
end
end
local function wakeup(db, key1, key2, value, ...)
if key1 == nil then
return
end
local q = db[key1]
if q == nil then
return
end
if q[mode] == "queue" then
db[key1] = nil
if value then
-- throw error because can't wake up a branch
for _,v in ipairs(q) do
local session = v[1]
local source = v[2]
skynet.redirect(source, 0, "error", session, "")
end
else
return q
end
else
-- it's branch
return wakeup(q , key2, value, ...)
end
end
function command.UPDATE(...)
return update(database, ...)
local ret, value = update(database, ...)
if ret or value == nil then
return ret
end
local q = wakeup(wait_queue, ...)
if q then
for _, v in ipairs(q) do
local session = v[1]
local source = v[2]
skynet.redirect(source, 0, "response", session, skynet.pack(value))
end
end
end
local function waitfor(session, source, db, key1, key2, ...)
if key2 == nil then
-- push queue
local q = db[key1]
if q == nil then
q = { [mode] = "queue" }
db[key1] = q
else
assert(q[mode] == "queue")
end
table.insert(q, { session, source })
else
local q = db[key1]
if q == nil then
q = { [mode] = "branch" }
db[key1] = q
else
assert(q[mode] == "branch")
end
return waitfor(session, source, q, key2, ...)
end
end
skynet.start(function()
skynet.dispatch("lua", function (_, source, cmd, ...)
local f = assert(command[cmd])
skynet.ret(skynet.pack(f(...)))
skynet.dispatch("lua", function (session, source, cmd, ...)
if cmd == "WAIT" then
local ret = command.QUERY(...)
if ret then
skynet.ret(skynet.pack(ret))
else
waitfor(session, source, wait_queue, ...)
end
else
local f = assert(command[cmd])
skynet.ret(skynet.pack(f(...)))
end
end)
end)

View File

@@ -88,7 +88,7 @@ end
skynet.start(function()
local listen_socket = socket.listen ("127.0.0.1", port)
print("Start debug console at 127.0.0.1",port)
skynet.error("Start debug console at 127.0.0.1 " .. port)
socket.start(listen_socket , function(id, addr)
local function print(...)
local t = { ... }
@@ -113,6 +113,7 @@ function COMMAND.help()
snax = "lanuch a new snax service",
clearcache = "clear lua code cache",
service = "List unique service",
task = "task address : show service task detail",
}
end

View File

@@ -8,6 +8,7 @@ local watchdog
local maxclient
local client_number = 0
local CMD = setmetatable({}, { __gc = function() netpack.clear(queue) end })
local nodelay = false
local connection = {} -- fd -> connection : { fd , client, agent , ip, mode }
local forwarding = {} -- agent -> connection
@@ -22,6 +23,13 @@ function CMD.open( source , conf )
socketdriver.start(socket)
end
function CMD.nodelay(source, v)
if v ~= false then
v = true
end
nodelay = v
end
function CMD.close()
assert(socket)
socketdriver.close(socket)
@@ -85,7 +93,7 @@ function MSG.data(fd, msg, sz)
if agent then
skynet.redirect(agent, c.client, "client", 0, msg, sz)
else
skynet.send(watchdog, "lua", "socket", "data", netpack.tostring(msg, sz))
skynet.send(watchdog, "lua", "socket", "data", fd, netpack.tostring(msg, sz))
end
end
@@ -106,6 +114,9 @@ function MSG.open(fd, msg)
}
connection[fd] = c
client_number = client_number + 1
if nodelay then
socketdriver.nodelay(fd)
end
skynet.send(watchdog, "lua", "socket", "open", fd, msg)
end

View File

@@ -38,6 +38,16 @@ function command.INFO(_, _, handle)
end
end
function command.TASK(_, _, handle)
handle = handle_to_address(handle)
if services[handle] == nil then
return
else
local result = skynet.call(handle,"debug","TASK")
return result
end
end
function command.KILL(_, _, handle)
handle = handle_to_address(handle)
skynet.kill(handle)
@@ -88,7 +98,7 @@ function command.ERROR(address)
skynet.redirect(reply.address , 0, "response", reply.session, "")
instance[address] = nil
end
services[address] = nil
return NORET
end

View File

@@ -176,7 +176,7 @@ skynet.start(function()
end
end)
local handle = skynet.localname ".service"
if handle ~= 0 then
if handle then
skynet.error(".service is already register by ", skynet.address(handle))
skynet.exit()
else

View File

@@ -106,7 +106,7 @@ mallctl_int64(const char* name, size_t* newval) {
} else {
je_mallctl(name, &v, &len, NULL, 0);
}
// printf("name: %s, value: %zd\n", name, v);
// skynet_error(NULL, "name: %s, value: %zd\n", name, v);
return v;
}
@@ -117,9 +117,9 @@ mallctl_opt(const char* name, int* newval) {
if(newval) {
int ret = je_mallctl(name, &v, &len, newval, sizeof(int));
if(ret == 0) {
printf("set new value(%d) for (%s) succeed\n", *newval, name);
skynet_error(NULL, "set new value(%d) for (%s) succeed\n", *newval, name);
} else {
printf("set new value(%d) for (%s) failed: error -> %d\n", *newval, name, ret);
skynet_error(NULL, "set new value(%d) for (%s) failed: error -> %d\n", *newval, name, ret);
}
} else {
je_mallctl(name, &v, &len, NULL, 0);
@@ -196,15 +196,15 @@ void
dump_c_mem() {
int i;
size_t total = 0;
printf("dump all service mem:\n");
skynet_error(NULL, "dump all service mem:");
for(i=0; i<SLOT_SIZE; i++) {
mem_data* data = &mem_stats[i];
if(data->handle != 0 && data->allocated != 0) {
total += data->allocated;
printf("0x%x -> %zdkb\n", data->handle, data->allocated >> 10);
skynet_error(NULL, "0x%x -> %zdkb", data->handle, data->allocated >> 10);
}
}
printf("+total: %zdkb\n",total >> 10);
skynet_error(NULL, "+total: %zdkb",total >> 10);
}
char *

View File

@@ -13,12 +13,13 @@
#define PTYPE_SYSTEM 4
#define PTYPE_HARBOR 5
#define PTYPE_SOCKET 6
// read lualib/skynet.lua lualib/simplemonitor.lua
// read lualib/skynet.lua examples/simplemonitor.lua
#define PTYPE_ERROR 7
// read lualib/skynet.lua lualib/mqueue.lua
// read lualib/skynet.lua lualib/mqueue.lua lualib/snax.lua
#define PTYPE_RESERVED_QUEUE 8
#define PTYPE_RESERVED_DEBUG 9
#define PTYPE_RESERVED_LUA 10
#define PTYPE_RESERVED_SNAX 11
#define PTYPE_TAG_DONTCOPY 0x10000
#define PTYPE_TAG_ALLOCSESSION 0x20000

View File

@@ -0,0 +1,96 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include "skynet_daemon.h"
static int
check_pid(const char *pidfile) {
int pid = 0;
FILE *f = fopen(pidfile,"r");
if (f == NULL)
return 0;
int n = fscanf(f,"%d", &pid);
fclose(f);
if (n !=1 || pid == 0 || pid == getpid()) {
return 0;
}
if (kill(pid, 0) && errno == ESRCH)
return 0;
return pid;
}
static int
write_pid(const char *pidfile) {
FILE *f;
int pid = 0;
int fd = open(pidfile, O_RDWR|O_CREAT, 0644);
if (fd == -1) {
fprintf(stderr, "Can't create %s.\n", pidfile);
return 0;
}
f = fdopen(fd, "r+");
if (f == NULL) {
fprintf(stderr, "Can't open %s.\n", pidfile);
return 0;
}
if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
int n = fscanf(f, "%d", &pid);
fclose(f);
if (n != 1) {
fprintf(stderr, "Can't lock and read pidfile.\n");
} else {
fprintf(stderr, "Can't lock pidfile, lock is held by pid %d.\n", pid);
}
return 0;
}
pid = getpid();
if (!fprintf(f,"%d\n", pid)) {
fprintf(stderr, "Can't write pid.\n");
close(fd);
return 0;
}
fflush(f);
return pid;
}
int
daemon_init(const char *pidfile) {
int pid = check_pid(pidfile);
if (pid) {
fprintf(stderr, "Skynet is already running, pid = %d.\n", pid);
return 1;
}
#ifdef __APPLE__
fprintf(stderr, "'daemon' is deprecated: first deprecated in OS X 10.5 , use launchd instead.\n");
#else
if (daemon(1,0)) {
fprintf(stderr, "Can't daemonize.\n");
return 1;
}
#endif
pid = write_pid(pidfile);
if (pid == 0) {
return 1;
}
return 0;
}
int
daemon_exit(const char *pidfile) {
return unlink(pidfile);
}

View File

@@ -0,0 +1,7 @@
#ifndef skynet_daemon_h
#define skynet_daemon_h
int daemon_init(const char *pidfile);
int daemon_exit(const char *pidfile);
#endif

View File

@@ -9,6 +9,7 @@
#include <string.h>
#define DEFAULT_SLOT_SIZE 4
#define MAX_SLOT_SIZE 0x40000000
struct handle_name {
char * name;
@@ -168,6 +169,7 @@ static void
_insert_name_before(struct handle_storage *s, char *name, uint32_t handle, int before) {
if (s->name_count >= s->name_cap) {
s->name_cap *= 2;
assert(s->name_cap <= MAX_SLOT_SIZE);
struct handle_name * n = skynet_malloc(s->name_cap * sizeof(struct handle_name));
int i;
for (i=0;i<before;i++) {

View File

@@ -7,34 +7,19 @@
#include <assert.h>
static struct skynet_context * REMOTE = 0;
static unsigned int HARBOR = 0;
static unsigned int HARBOR = ~0;
void
skynet_harbor_send(struct remote_message *rmsg, uint32_t source, int session) {
int type = rmsg->sz >> HANDLE_REMOTE_SHIFT;
rmsg->sz &= HANDLE_MASK;
assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR);
assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR && REMOTE);
skynet_context_send(REMOTE, rmsg, sizeof(*rmsg) , source, type , session);
}
void
skynet_harbor_register(struct remote_name *rname) {
int i;
int number = 1;
for (i=0;i<GLOBALNAME_LENGTH;i++) {
char c = rname->name[i];
if (!(c >= '0' && c <='9')) {
number = 0;
break;
}
}
assert(number == 0);
skynet_context_send(REMOTE, rname, sizeof(*rname), 0, PTYPE_SYSTEM , 0);
}
int
skynet_harbor_message_isremote(uint32_t handle) {
assert(HARBOR != 0);
assert(HARBOR != ~0);
int h = (handle & ~HANDLE_MASK);
return h != HARBOR && h !=0;
}

View File

@@ -23,7 +23,6 @@ struct remote_message {
};
void skynet_harbor_send(struct remote_message *rmsg, uint32_t source, int session);
void skynet_harbor_register(struct remote_name *rname);
int skynet_harbor_message_isremote(uint32_t handle);
void skynet_harbor_init(int harbor);
void skynet_harbor_start(void * ctx);

View File

@@ -4,8 +4,10 @@
struct skynet_config {
int thread;
int harbor;
const char * daemon;
const char * module_path;
const char * bootstrap;
const char * logger;
};
#define THREAD_WORKER 0

View File

@@ -35,6 +35,7 @@ optboolean(const char *key, int opt) {
return strcmp(str,"true")==0;
}
*/
static const char *
optstring(const char *key,const char * opt) {
const char * str = skynet_getenv(key);
@@ -109,21 +110,17 @@ main(int argc, char *argv[]) {
}
_init_env(L);
#ifdef LUA_CACHELIB
printf("Skynet lua code cache enable\n");
#endif
config.thread = optint("thread",8);
config.module_path = optstring("cpath","./cservice/?.so");
config.harbor = optint("harbor", 1);
config.bootstrap = optstring("bootstrap","snlua bootstrap");
config.daemon = optstring("daemon", NULL);
config.logger = optstring("logger", NULL);
lua_close(L);
skynet_start(&config);
skynet_globalexit();
printf("skynet exit\n");
return 0;
}

View File

@@ -34,7 +34,6 @@ struct global_queue {
struct message_queue ** queue;
// We use a separated flag array to ensure the mq is pushed.
// See the comments below.
bool * flag;
struct message_queue *list;
};
@@ -45,11 +44,14 @@ static struct global_queue *Q = NULL;
#define GP(p) ((p) % MAX_GLOBAL_MQ)
static void
void
skynet_globalmq_push(struct message_queue * queue) {
struct global_queue *q= Q;
if (q->flag[GP(q->tail)]) {
uint32_t tail = GP(__sync_fetch_and_add(&q->tail,1));
// only one thread can set the slot (change q->queue[tail] from NULL to queue)
if (!__sync_bool_compare_and_swap(&q->queue[tail], NULL, queue)) {
// The queue may full seldom, save queue in list
assert(queue->next == NULL);
struct message_queue * last;
@@ -60,14 +62,6 @@ skynet_globalmq_push(struct message_queue * queue) {
return;
}
uint32_t tail = GP(__sync_fetch_and_add(&q->tail,1));
// The thread would suspend here, and the q->queue[tail] is last version ,
// but the queue tail is increased.
// So we set q->flag[tail] after changing q->queue[tail].
q->queue[tail] = queue;
__sync_synchronize();
q->flag[tail] = true;
}
struct message_queue *
@@ -93,18 +87,18 @@ skynet_globalmq_pop() {
}
}
// Check the flag first, if the flag is false, the pushing may not complete.
if(!q->flag[head_ptr]) {
struct message_queue * mq = q->queue[head_ptr];
if (mq == NULL) {
// globalmq push not complete
return NULL;
}
__sync_synchronize();
struct message_queue * mq = q->queue[head_ptr];
if (!__sync_bool_compare_and_swap(&q->head, head, head+1)) {
return NULL;
}
q->flag[head_ptr] = false;
// only one thread can get the slot (change q->queue[head_ptr] to NULL)
if (!__sync_bool_compare_and_swap(&q->queue[head_ptr], mq, NULL)) {
return NULL;
}
return mq;
}
@@ -220,26 +214,10 @@ skynet_mq_init() {
struct global_queue *q = skynet_malloc(sizeof(*q));
memset(q,0,sizeof(*q));
q->queue = skynet_malloc(MAX_GLOBAL_MQ * sizeof(struct message_queue *));
q->flag = skynet_malloc(MAX_GLOBAL_MQ * sizeof(bool));
memset(q->flag, 0, sizeof(bool) * MAX_GLOBAL_MQ);
memset(q->queue, 0, sizeof(struct message_queue *) * MAX_GLOBAL_MQ);
Q=q;
}
void
skynet_mq_force_push(struct message_queue * queue) {
assert(queue->in_global);
skynet_globalmq_push(queue);
}
void
skynet_mq_pushglobal(struct message_queue *queue) {
LOCK(queue)
assert(queue->in_global);
skynet_globalmq_push(queue);
queue->in_global = MQ_IN_GLOBAL;
UNLOCK(queue)
}
void
skynet_mq_mark_release(struct message_queue *q) {
LOCK(q)
@@ -268,7 +246,7 @@ skynet_mq_release(struct message_queue *q, message_drop drop_func, void *ud) {
UNLOCK(q)
_drop_queue(q, drop_func, ud);
} else {
skynet_mq_force_push(q);
skynet_globalmq_push(q);
UNLOCK(q)
}
}

View File

@@ -13,6 +13,7 @@ struct skynet_message {
struct message_queue;
void skynet_globalmq_push(struct message_queue * queue);
struct message_queue * skynet_globalmq_pop(void);
struct message_queue * skynet_mq_create(uint32_t handle);
@@ -30,9 +31,6 @@ void skynet_mq_push(struct message_queue *q, struct skynet_message *message);
// return the length of message queue, for debug
int skynet_mq_length(struct message_queue *q);
void skynet_mq_force_push(struct message_queue *q);
void skynet_mq_pushglobal(struct message_queue *q);
void skynet_mq_init();
#endif

View File

@@ -52,6 +52,7 @@ struct skynet_context {
struct skynet_node {
int total;
int init;
uint32_t monitor_exit;
pthread_key_t handle_key;
};
@@ -75,8 +76,13 @@ context_dec() {
uint32_t
skynet_current_handle(void) {
void * handle = pthread_getspecific(G_NODE.handle_key);
return (uint32_t)(uintptr_t)handle;
if (G_NODE.init) {
void * handle = pthread_getspecific(G_NODE.handle_key);
return (uint32_t)(uintptr_t)handle;
} else {
uintptr_t v = (uint32_t)(-THREAD_MAIN);
return v;
}
}
static void
@@ -139,7 +145,7 @@ skynet_context_new(const char * name, const char *param) {
if (ret) {
ctx->init = true;
}
skynet_mq_force_push(queue);
skynet_globalmq_push(queue);
if (ret) {
skynet_error(ret, "LAUNCH %s %s", name, param ? param : "");
}
@@ -228,11 +234,23 @@ _dispatch_message(struct skynet_context *ctx, struct skynet_message *msg) {
CHECKCALLING_END(ctx)
}
int
skynet_context_message_dispatch(struct skynet_monitor *sm) {
struct message_queue * q = skynet_globalmq_pop();
if (q==NULL)
return 1;
void
skynet_context_dispatchall(struct skynet_context * ctx) {
// for skynet_error
struct skynet_message msg;
struct message_queue *q = ctx->queue;
while (!skynet_mq_pop(q,&msg)) {
_dispatch_message(ctx, &msg);
}
}
struct message_queue *
skynet_context_message_dispatch(struct skynet_monitor *sm, struct message_queue *q, int weight) {
if (q == NULL) {
q = skynet_globalmq_pop();
if (q==NULL)
return NULL;
}
uint32_t handle = skynet_mq_handle(q);
@@ -240,30 +258,43 @@ skynet_context_message_dispatch(struct skynet_monitor *sm) {
if (ctx == NULL) {
struct drop_t d = { handle };
skynet_mq_release(q, drop_message, &d);
return 0;
return skynet_globalmq_pop();
}
int i,n=1;
struct skynet_message msg;
if (skynet_mq_pop(q,&msg)) {
skynet_context_release(ctx);
return 0;
}
skynet_monitor_trigger(sm, msg.source , handle);
for (i=0;i<n;i++) {
if (skynet_mq_pop(q,&msg)) {
skynet_context_release(ctx);
return skynet_globalmq_pop();
} else if (i==0 && weight >= 0) {
n = skynet_mq_length(q);
n >>= weight;
}
if (ctx->cb == NULL) {
skynet_free(msg.data);
} else {
_dispatch_message(ctx, &msg);
skynet_monitor_trigger(sm, msg.source , handle);
if (ctx->cb == NULL) {
skynet_free(msg.data);
} else {
_dispatch_message(ctx, &msg);
}
skynet_monitor_trigger(sm, 0,0);
}
assert(q == ctx->queue);
skynet_mq_pushglobal(q);
struct message_queue *nq = skynet_globalmq_pop();
if (nq) {
// If global mq is not empty , push q back, and return next queue (nq)
// Else (global mq is empty or block, don't push q back, and return q again (for next dispatch)
skynet_globalmq_push(q);
q = nq;
}
skynet_context_release(ctx);
skynet_monitor_trigger(sm, 0,0);
return 0;
return q;
}
static void
@@ -328,11 +359,7 @@ cmd_reg(struct skynet_context * context, const char * param) {
} else if (param[0] == '.') {
return skynet_handle_namehandle(context->handle, param + 1);
} else {
assert(context->handle!=0);
struct remote_name *rname = skynet_malloc(sizeof(*rname));
copy_name(rname->name, param);
rname->handle = context->handle;
skynet_harbor_register(rname);
skynet_error(context, "Can't register global name %s in C", param);
return NULL;
}
}
@@ -341,8 +368,10 @@ static const char *
cmd_query(struct skynet_context * context, const char * param) {
if (param[0] == '.') {
uint32_t handle = skynet_handle_findname(param+1);
sprintf(context->result, ":%x", handle);
return context->result;
if (handle) {
sprintf(context->result, ":%x", handle);
return context->result;
}
}
return NULL;
}
@@ -363,10 +392,7 @@ cmd_name(struct skynet_context * context, const char * param) {
if (name[0] == '.') {
return skynet_handle_namehandle(handle_id, name + 1);
} else {
struct remote_name *rname = skynet_malloc(sizeof(*rname));
copy_name(rname->name, name);
rname->handle = handle_id;
skynet_harbor_register(rname);
skynet_error(context, "Can't set global name %s in C", name);
}
return NULL;
}
@@ -545,12 +571,16 @@ _filter_args(struct skynet_context * context, int type, int *session, void ** da
*data = msg;
}
assert((*sz & HANDLE_MASK) == *sz);
*sz |= type << HANDLE_REMOTE_SHIFT;
}
int
skynet_send(struct skynet_context * context, uint32_t source, uint32_t destination , int type, int session, void * data, size_t sz) {
if ((sz & HANDLE_MASK) != sz) {
skynet_error(context, "The message to %x is too large (sz = %lu)", destination, sz);
skynet_free(data);
return -1;
}
_filter_args(context, type, &session, (void **)&data, &sz);
if (source == 0) {
@@ -642,6 +672,7 @@ void
skynet_globalinit(void) {
G_NODE.total = 0;
G_NODE.monitor_exit = 0;
G_NODE.init = 1;
if (pthread_key_create(&G_NODE.handle_key, NULL)) {
fprintf(stderr, "pthread_key_create failed");
exit(1);

View File

@@ -16,8 +16,9 @@ void skynet_context_init(struct skynet_context *, uint32_t handle);
int skynet_context_push(uint32_t handle, struct skynet_message *message);
void skynet_context_send(struct skynet_context * context, void * msg, size_t sz, uint32_t source, int type, int session);
int skynet_context_newsession(struct skynet_context *);
int skynet_context_message_dispatch(struct skynet_monitor *); // return 1 when block
struct message_queue * skynet_context_message_dispatch(struct skynet_monitor *, struct message_queue *, int weight); // return next queue
int skynet_context_total();
void skynet_context_dispatchall(struct skynet_context * context); // for skynet_error output before exit
void skynet_context_endless(uint32_t handle); // for monitor

View File

@@ -133,12 +133,6 @@ skynet_socket_connect(struct skynet_context *ctx, const char *host, int port) {
return socket_server_connect(SOCKET_SERVER, source, host, port);
}
int
skynet_socket_block_connect(struct skynet_context *ctx, const char *host, int port) {
uint32_t source = skynet_context_handle(ctx);
return socket_server_block_connect(SOCKET_SERVER, source, host, port);
}
int
skynet_socket_bind(struct skynet_context *ctx, int fd) {
uint32_t source = skynet_context_handle(ctx);
@@ -156,3 +150,8 @@ skynet_socket_start(struct skynet_context *ctx, int id) {
uint32_t source = skynet_context_handle(ctx);
socket_server_start(SOCKET_SERVER, source, id);
}
void
skynet_socket_nodelay(struct skynet_context *ctx, int id) {
socket_server_nodelay(SOCKET_SERVER, id);
}

View File

@@ -25,9 +25,9 @@ int skynet_socket_send(struct skynet_context *ctx, int id, void *buffer, int sz)
void skynet_socket_send_lowpriority(struct skynet_context *ctx, int id, void *buffer, int sz);
int skynet_socket_listen(struct skynet_context *ctx, const char *host, int port, int backlog);
int skynet_socket_connect(struct skynet_context *ctx, const char *host, int port);
int skynet_socket_block_connect(struct skynet_context *ctx, const char *host, int port);
int skynet_socket_bind(struct skynet_context *ctx, int fd);
void skynet_socket_close(struct skynet_context *ctx, int id);
void skynet_socket_start(struct skynet_context *ctx, int id);
void skynet_socket_nodelay(struct skynet_context *ctx, int id);
#endif

View File

@@ -7,6 +7,7 @@
#include "skynet_timer.h"
#include "skynet_monitor.h"
#include "skynet_socket.h"
#include "skynet_daemon.h"
#include <pthread.h>
#include <unistd.h>
@@ -26,6 +27,7 @@ struct monitor {
struct worker_parm {
struct monitor *m;
int id;
int weight;
};
#define CHECK_ABORT if (skynet_context_total()==0) break;
@@ -117,11 +119,14 @@ static void *
_worker(void *p) {
struct worker_parm *wp = p;
int id = wp->id;
int weight = wp->weight;
struct monitor *m = wp->m;
struct skynet_monitor *sm = m->m[id];
skynet_initthread(THREAD_WORKER);
struct message_queue * q = NULL;
for (;;) {
if (skynet_context_message_dispatch(sm)) {
q = skynet_context_message_dispatch(sm, q, weight);
if (q == NULL) {
CHECK_ABORT
if (pthread_mutex_lock(&m->mutex) == 0) {
++ m->sleep;
@@ -166,10 +171,20 @@ _start(int thread) {
create_thread(&pid[1], _timer, m);
create_thread(&pid[2], _socket, m);
static int weight[] = {
-1, -1, -1, -1, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, };
struct worker_parm wp[thread];
for (i=0;i<thread;i++) {
wp[i].m = m;
wp[i].id = i;
if (i < sizeof(weight)/sizeof(weight[0])) {
wp[i].weight= weight[i];
} else {
wp[i].weight = 0;
}
create_thread(&pid[i+3], _worker, &wp[i]);
}
@@ -181,7 +196,7 @@ _start(int thread) {
}
static void
bootstrap(const char * cmdline) {
bootstrap(struct skynet_context * logger, const char * cmdline) {
int sz = strlen(cmdline);
char name[sz+1];
char args[sz+1];
@@ -189,12 +204,18 @@ bootstrap(const char * cmdline) {
struct skynet_context *ctx = skynet_context_new(name, args);
if (ctx == NULL) {
skynet_error(NULL, "Bootstrap error : %s\n", cmdline);
skynet_context_dispatchall(logger);
exit(1);
}
}
void
skynet_start(struct skynet_config * config) {
if (config->daemon) {
if (daemon_init(config->daemon)) {
exit(1);
}
}
skynet_harbor_init(config->harbor);
skynet_handle_init(config->harbor);
skynet_mq_init();
@@ -202,8 +223,17 @@ skynet_start(struct skynet_config * config) {
skynet_timer_init();
skynet_socket_init();
bootstrap(config->bootstrap);
struct skynet_context *ctx = skynet_context_new("logger", config->logger);
if (ctx == NULL) {
fprintf(stderr, "Can't launch logger service\n");
exit(1);
}
bootstrap(ctx, config->bootstrap);
_start(config->thread);
skynet_socket_free();
if (config->daemon) {
daemon_exit(config->daemon);
}
}

View File

@@ -16,6 +16,9 @@
typedef void (*timer_execute_func)(void *ud,void *arg);
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
#define TIME_NEAR_SHIFT 8
#define TIME_NEAR (1 << TIME_NEAR_SHIFT)
#define TIME_LEVEL_SHIFT 6
@@ -45,13 +48,14 @@ struct timer {
int time;
uint32_t current;
uint32_t starttime;
uint64_t current_point;
uint64_t origin_point;
};
static struct timer * TI = NULL;
static inline struct timer_node *
link_clear(struct link_list *list)
{
link_clear(struct link_list *list) {
struct timer_node * ret = list->head.next;
list->head.next = 0;
list->tail = &(list->head);
@@ -60,23 +64,20 @@ link_clear(struct link_list *list)
}
static inline void
link(struct link_list *list,struct timer_node *node)
{
link(struct link_list *list,struct timer_node *node) {
list->tail->next = node;
list->tail = node;
node->next=0;
}
static void
add_node(struct timer *T,struct timer_node *node)
{
add_node(struct timer *T,struct timer_node *node) {
int time=node->expire;
int current_time=T->time;
if ((time|TIME_NEAR_MASK)==(current_time|TIME_NEAR_MASK)) {
link(&T->near[time&TIME_NEAR_MASK],node);
}
else {
} else {
int i;
int mask=TIME_NEAR << TIME_LEVEL_SHIFT;
for (i=0;i<3;i++) {
@@ -90,21 +91,21 @@ add_node(struct timer *T,struct timer_node *node)
}
static void
timer_add(struct timer *T,void *arg,size_t sz,int time)
{
timer_add(struct timer *T,void *arg,size_t sz,int time) {
struct timer_node *node = (struct timer_node *)skynet_malloc(sizeof(*node)+sz);
memcpy(node+1,arg,sz);
while (__sync_lock_test_and_set(&T->lock,1)) {};
LOCK(T);
node->expire=time+T->time;
add_node(T,node);
__sync_lock_release(&T->lock);
UNLOCK(T);
}
static void
timer_shift(struct timer *T) {
LOCK(T);
int mask = TIME_NEAR;
int time = (++T->time) >> TIME_NEAR_SHIFT;
int i=0;
@@ -125,50 +126,57 @@ timer_shift(struct timer *T) {
time >>= TIME_LEVEL_SHIFT;
++i;
}
UNLOCK(T);
}
static inline void
dispatch_list(struct timer_node *current) {
do {
struct timer_event * event = (struct timer_event *)(current+1);
struct skynet_message message;
message.source = 0;
message.session = event->session;
message.data = NULL;
message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT;
skynet_context_push(event->handle, &message);
struct timer_node * temp = current;
current=current->next;
skynet_free(temp);
} while (current);
}
static inline void
timer_execute(struct timer *T) {
LOCK(T);
int idx = T->time & TIME_NEAR_MASK;
while (T->near[idx].head.next) {
struct timer_node *current = link_clear(&T->near[idx]);
do {
struct timer_event * event = (struct timer_event *)(current+1);
struct skynet_message message;
message.source = 0;
message.session = event->session;
message.data = NULL;
message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT;
skynet_context_push(event->handle, &message);
struct timer_node * temp = current;
current=current->next;
skynet_free(temp);
} while (current);
UNLOCK(T);
// dispatch_list don't need lock T
dispatch_list(current);
LOCK(T);
}
UNLOCK(T);
}
static void
timer_update(struct timer *T)
{
while (__sync_lock_test_and_set(&T->lock,1)) {};
timer_update(struct timer *T) {
// try to dispatch timeout 0 (rare condition)
timer_execute(T);
// shift time first, and then dispatch timer message
timer_shift(T);
timer_execute(T);
__sync_lock_release(&T->lock);
}
static struct timer *
timer_create_timer()
{
timer_create_timer() {
struct timer *r=(struct timer *)skynet_malloc(sizeof(struct timer));
memset(r,0,sizeof(*r));
@@ -212,18 +220,41 @@ skynet_timeout(uint32_t handle, int time, int session) {
return session;
}
static uint32_t
_gettime(void) {
uint32_t t;
// centisecond: 1/100 second
static void
systime(uint32_t *sec, uint32_t *cs) {
#if !defined(__APPLE__)
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint32_t)(ti.tv_sec & 0xffffff) * 100;
clock_gettime(CLOCK_REALTIME, &ti);
*sec = (uint32_t)ti.tv_sec;
*cs = (uint32_t)(ti.tv_nsec / 10000000);
#else
struct timeval tv;
gettimeofday(&tv, NULL);
*sec = tv.tv_sec;
*cs = tv.tv_usec / 10000;
#endif
}
static uint64_t
gettime() {
uint64_t t;
#if !defined(__APPLE__)
#ifdef CLOCK_MONOTONIC_RAW
#define CLOCK_TIMER CLOCK_MONOTONIC_RAW
#else
#define CLOCK_TIMER CLOCK_MONOTONIC
#endif
struct timespec ti;
clock_gettime(CLOCK_TIMER, &ti);
t = (uint64_t)ti.tv_sec * 100;
t += ti.tv_nsec / 10000000;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
t = (uint32_t)(tv.tv_sec & 0xffffff) * 100;
t = (uint64_t)tv.tv_sec * 100;
t += tv.tv_usec / 10000;
#endif
return t;
@@ -231,10 +262,19 @@ _gettime(void) {
void
skynet_updatetime(void) {
uint32_t ct = _gettime();
if (ct != TI->current) {
int diff = ct>=TI->current?ct-TI->current:(0xffffff+1)*100-TI->current+ct;
TI->current = ct;
uint64_t cp = gettime();
if(cp < TI->current_point) {
skynet_error(NULL, "time diff error: change from %lld to %lld", cp, TI->current_point);
} else if (cp != TI->current_point) {
uint32_t diff = (uint32_t)(cp - TI->current_point);
TI->current_point = cp;
uint32_t oc = TI->current;
TI->current += diff;
if (TI->current < oc) {
// when cs > 0xffffffff(about 497 days), time rewind
TI->starttime += 0xffffffff / 100;
}
int i;
for (i=0;i<diff;i++) {
timer_update(TI);
@@ -255,18 +295,9 @@ skynet_gettime(void) {
void
skynet_timer_init(void) {
TI = timer_create_timer();
TI->current = _gettime();
#if !defined(__APPLE__)
struct timespec ti;
clock_gettime(CLOCK_REALTIME, &ti);
uint32_t sec = (uint32_t)ti.tv_sec;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
uint32_t sec = (uint32_t)tv.tv_sec;
#endif
uint32_t mono = _gettime() / 100;
TI->starttime = sec - mono;
systime(&TI->starttime, &TI->current);
uint64_t point = gettime();
TI->current_point = point;
TI->origin_point = point;
}

View File

@@ -5,6 +5,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
@@ -34,6 +35,8 @@
#define PRIORITY_HIGH 0
#define PRIORITY_LOW 1
#define HASH_ID(id) (((unsigned)id) % MAX_SOCKET)
struct write_buffer {
struct write_buffer * next;
char *ptr;
@@ -107,6 +110,12 @@ struct request_start {
uintptr_t opaque;
};
struct request_setopt {
int id;
int what;
int value;
};
struct request_package {
uint8_t header[8]; // 6 bytes dummy
union {
@@ -117,6 +126,7 @@ struct request_package {
struct request_listen listen;
struct request_bind bind;
struct request_start start;
struct request_setopt setopt;
} u;
uint8_t dummy[256];
};
@@ -144,9 +154,11 @@ reserve_id(struct socket_server *ss) {
if (id < 0) {
id = __sync_and_and_fetch(&(ss->alloc_id), 0x7fffffff);
}
struct socket *s = &ss->slot[id % MAX_SOCKET];
struct socket *s = &ss->slot[HASH_ID(id)];
if (s->type == SOCKET_TYPE_INVALID) {
if (__sync_bool_compare_and_swap(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) {
s->id = id;
s->fd = -1;
return id;
} else {
// retry
@@ -265,7 +277,7 @@ check_wb_list(struct wb_list *s) {
static struct socket *
new_fd(struct socket_server *ss, int id, int fd, uintptr_t opaque, bool add) {
struct socket * s = &ss->slot[id % MAX_SOCKET];
struct socket * s = &ss->slot[HASH_ID(id)];
assert(s->type == SOCKET_TYPE_RESERVE);
if (add) {
@@ -287,7 +299,7 @@ new_fd(struct socket_server *ss, int id, int fd, uintptr_t opaque, bool add) {
// return -1 when connecting
static int
open_socket(struct socket_server *ss, struct request_open * request, struct socket_message *result, bool blocking) {
open_socket(struct socket_server *ss, struct request_open * request, struct socket_message *result) {
int id = request->id;
result->opaque = request->opaque;
result->id = id;
@@ -316,18 +328,14 @@ open_socket(struct socket_server *ss, struct request_open * request, struct sock
continue;
}
socket_keepalive(sock);
if (!blocking) {
sp_nonblocking(sock);
}
sp_nonblocking(sock);
status = connect( sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if ( status != 0 && errno != EINPROGRESS) {
close(sock);
sock = -1;
continue;
}
if (blocking) {
sp_nonblocking(sock);
}
sp_nonblocking(sock);
break;
}
@@ -359,7 +367,7 @@ open_socket(struct socket_server *ss, struct request_open * request, struct sock
return -1;
_failed:
freeaddrinfo( ai_list );
ss->slot[id % MAX_SOCKET].type = SOCKET_TYPE_INVALID;
ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID;
return SOCKET_ERROR;
}
@@ -504,7 +512,7 @@ send_buffer_empty(struct socket *s) {
static int
send_socket(struct socket_server *ss, struct request_send * request, struct socket_message *result, int priority) {
int id = request->id;
struct socket * s = &ss->slot[id % MAX_SOCKET];
struct socket * s = &ss->slot[HASH_ID(id)];
if (s->type == SOCKET_TYPE_INVALID || s->id != id
|| s->type == SOCKET_TYPE_HALFCLOSE
|| s->type == SOCKET_TYPE_PACCEPT) {
@@ -512,7 +520,7 @@ send_socket(struct socket_server *ss, struct request_send * request, struct sock
return -1;
}
assert(s->type != SOCKET_TYPE_PLISTEN && s->type != SOCKET_TYPE_LISTEN);
if (send_buffer_empty(s)) {
if (send_buffer_empty(s) && s->type == SOCKET_TYPE_CONNECTED) {
int n = write(s->fd, request->buffer, request->sz);
if (n<0) {
switch(errno) {
@@ -558,7 +566,7 @@ _failed:
result->id = id;
result->ud = 0;
result->data = NULL;
ss->slot[id % MAX_SOCKET].type = SOCKET_TYPE_INVALID;
ss->slot[HASH_ID(id)].type = SOCKET_TYPE_INVALID;
return SOCKET_ERROR;
}
@@ -566,7 +574,7 @@ _failed:
static int
close_socket(struct socket_server *ss, struct request_close *request, struct socket_message *result) {
int id = request->id;
struct socket * s = &ss->slot[id % MAX_SOCKET];
struct socket * s = &ss->slot[HASH_ID(id)];
if (s->type == SOCKET_TYPE_INVALID || s->id != id) {
result->id = id;
result->opaque = request->opaque;
@@ -614,7 +622,7 @@ start_socket(struct socket_server *ss, struct request_start *request, struct soc
result->opaque = request->opaque;
result->ud = 0;
result->data = NULL;
struct socket *s = &ss->slot[id % MAX_SOCKET];
struct socket *s = &ss->slot[HASH_ID(id)];
if (s->type == SOCKET_TYPE_INVALID || s->id !=id) {
return SOCKET_ERROR;
}
@@ -635,6 +643,17 @@ start_socket(struct socket_server *ss, struct request_start *request, struct soc
return -1;
}
static void
setopt_socket(struct socket_server *ss, struct request_setopt *request) {
int id = request->id;
struct socket *s = &ss->slot[HASH_ID(id)];
if (s->type == SOCKET_TYPE_INVALID || s->id !=id) {
return;
}
int v = request->value;
setsockopt(s->fd, IPPROTO_TCP, request->what, &v, sizeof(v));
}
static void
block_readpipe(int pipefd, void *buffer, int sz) {
for (;;) {
@@ -687,7 +706,7 @@ ctrl_cmd(struct socket_server *ss, struct socket_message *result) {
case 'K':
return close_socket(ss,(struct request_close *)buffer, result);
case 'O':
return open_socket(ss, (struct request_open *)buffer, result, false);
return open_socket(ss, (struct request_open *)buffer, result);
case 'X':
result->opaque = 0;
result->id = 0;
@@ -698,6 +717,9 @@ ctrl_cmd(struct socket_server *ss, struct socket_message *result) {
return send_socket(ss, (struct request_send *)buffer, result, PRIORITY_HIGH);
case 'P':
return send_socket(ss, (struct request_send *)buffer, result, PRIORITY_LOW);
case 'T':
setopt_socket(ss, (struct request_setopt *)buffer);
return -1;
default:
fprintf(stderr, "socket-server: Unknown ctrl %c.\n",type);
return -1;
@@ -765,7 +787,9 @@ report_connect(struct socket_server *ss, struct socket *s, struct socket_message
result->opaque = s->opaque;
result->id = s->id;
result->ud = 0;
sp_write(ss->event_fd, s->fd, s, false);
if (send_buffer_empty(s)) {
sp_write(ss->event_fd, s->fd, s, false);
}
union sockaddr_all u;
socklen_t slen = sizeof(u);
if (getpeername(s->fd, &u.s, &slen) == 0) {
@@ -815,6 +839,22 @@ report_accept(struct socket_server *ss, struct socket *s, struct socket_message
return 1;
}
static inline void
clear_closed_event(struct socket_server *ss, struct socket_message * result, int type) {
if (type == SOCKET_CLOSE || type == SOCKET_ERROR) {
int id = result->id;
int i;
for (i=ss->event_index; i<ss->event_n; i++) {
struct event *e = &ss->ev[i];
struct socket *s = e->s;
if (s) {
if (s->type == SOCKET_TYPE_INVALID && s->id == id) {
e->s = NULL;
}
}
}
}
}
// return type
int
@@ -823,9 +863,10 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int
if (ss->checkctrl) {
if (has_cmd(ss)) {
int type = ctrl_cmd(ss, result);
if (type != -1)
if (type != -1) {
clear_closed_event(ss, result, type);
return type;
else
} else
continue;
} else {
ss->checkctrl = 0;
@@ -865,12 +906,14 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int
int type = send_buffer(ss, s, result);
if (type == -1)
break;
clear_closed_event(ss, result, type);
return type;
}
if (e->read) {
int type = forward_message(ss, s, result);
if (type == -1)
break;
clear_closed_event(ss, result, type);
return type;
}
break;
@@ -920,27 +963,13 @@ socket_server_connect(struct socket_server *ss, uintptr_t opaque, const char * a
return request.u.open.id;
}
int
socket_server_block_connect(struct socket_server *ss, uintptr_t opaque, const char * addr, int port) {
struct request_package request;
struct socket_message result;
open_request(ss, &request, opaque, addr, port);
int ret = open_socket(ss, &request.u.open, &result, true);
if (ret == SOCKET_OPEN) {
return result.id;
} else {
return -1;
}
}
// return -1 when error
int64_t
socket_server_send(struct socket_server *ss, int id, const void * buffer, int sz) {
struct socket * s = &ss->slot[id % MAX_SOCKET];
struct socket * s = &ss->slot[HASH_ID(id)];
if (s->id != id || s->type == SOCKET_TYPE_INVALID) {
return -1;
}
assert(s->type != SOCKET_TYPE_RESERVE);
struct request_package request;
request.u.send.id = id;
@@ -953,11 +982,10 @@ socket_server_send(struct socket_server *ss, int id, const void * buffer, int sz
void
socket_server_send_lowpriority(struct socket_server *ss, int id, const void * buffer, int sz) {
struct socket * s = &ss->slot[id % MAX_SOCKET];
struct socket * s = &ss->slot[HASH_ID(id)];
if (s->id != id || s->type == SOCKET_TYPE_INVALID) {
return;
}
assert(s->type != SOCKET_TYPE_RESERVE);
struct request_package request;
request.u.send.id = id;
@@ -1049,4 +1077,11 @@ socket_server_start(struct socket_server *ss, uintptr_t opaque, int id) {
send_request(ss, &request, 'S', sizeof(request.u.start));
}
void
socket_server_nodelay(struct socket_server *ss, int id) {
struct request_package request;
request.u.setopt.id = id;
request.u.setopt.what = TCP_NODELAY;
request.u.setopt.value = 1;
send_request(ss, &request, 'T', sizeof(request.u.setopt));
}

View File

@@ -36,6 +36,6 @@ int socket_server_listen(struct socket_server *, uintptr_t opaque, const char *
int socket_server_connect(struct socket_server *, uintptr_t opaque, const char * addr, int port);
int socket_server_bind(struct socket_server *, uintptr_t opaque, int fd);
int socket_server_block_connect(struct socket_server *, uintptr_t opaque, const char * addr, int port);
void socket_server_nodelay(struct socket_server *, int id);
#endif

View File

@@ -1,12 +0,0 @@
local skynet = require "skynet"
local mqueue = require "mqueue"
skynet.start(function()
local id = 0
local pingserver = skynet.newservice "pingserver"
mqueue.register(function(str)
id = id + 1
str = string.format("id = %d , %s",id, str)
return skynet.call(pingserver, "lua", "PING", str)
end)
end)

View File

@@ -1,4 +1,5 @@
local skynet = require "skynet"
local queue = require "skynet.queue"
local i = 0
local hello = "hello"
@@ -8,9 +9,27 @@ function response.ping(hello)
return hello
end
-- response.sleep and accept.hello share one lock
local lock
function accept.sleep(queue, n)
if queue then
lock(
function()
print("queue=",queue, n)
skynet.sleep(n)
end)
else
print("queue=",queue, n)
skynet.sleep(n)
end
end
function accept.hello()
lock(function()
i = i + 1
print (i, hello)
end)
end
function response.error()
@@ -19,6 +38,8 @@ end
function init( ... )
print ("ping server start:", ...)
-- init queue
lock = queue()
-- You can return "queue" for queue service mode
-- return "queue"

23
test/testdatacenter.lua Normal file
View File

@@ -0,0 +1,23 @@
local skynet = require "skynet"
local datacenter = require "datacenter"
local function f1()
print("====1==== wait hello")
print("\t1>",datacenter.wait ("hello"))
print("====1==== wait key.foobar")
print("\t1>", pcall(datacenter.wait,"key")) -- will failed, because "key" is a branch
print("\t1>",datacenter.wait ("key", "foobar"))
end
local function f2()
skynet.sleep(10)
print("====2==== set key.foobar")
datacenter.set("key", "foobar", "bingo")
end
skynet.start(function()
datacenter.set("hello", "world")
print(datacenter.get "hello")
skynet.fork(f1)
skynet.fork(f2)
end)

View File

@@ -14,12 +14,10 @@ end)
else
skynet.start(function()
local test = skynet.newservice("testdeadcall", "test") -- launch self in test mode
local test = skynet.newservice(SERVICE_NAME, "test") -- launch self in test mode
print(pcall(function()
skynet.send(test,"lua", "hello world")
skynet.send(test,"lua", "never get there")
skynet.call(test,"lua", "fake call")
skynet.call(test,"lua", "dead call")
end))
skynet.exit()

11
test/testharborlink.lua Normal file
View File

@@ -0,0 +1,11 @@
local skynet = require "skynet"
local harbor = require "skynet.harbor"
skynet.start(function()
print("wait for harbor 2")
print("run skynet examples/config_log please")
harbor.connect(2)
print("harbor 2 connected")
harbor.link(2)
print("disconnected")
end)

View File

@@ -27,7 +27,7 @@ skynet.start(function()
local channel = mc.new()
print("New channel", channel)
for i=1,10 do
local sub = skynet.newservice("testmulticast", "sub")
local sub = skynet.newservice(SERVICE_NAME, "sub")
skynet.call(sub, "lua", "init", channel.channel)
end

18
test/testqueue.lua Normal file
View File

@@ -0,0 +1,18 @@
local skynet = require "skynet"
local snax = require "snax"
skynet.start(function()
local ps = snax.uniqueservice ("pingserver", "test queue")
for i=1, 10 do
ps.post.sleep(true,i*10)
ps.post.hello()
end
for i=1, 10 do
ps.post.sleep(false,i*10)
ps.post.hello()
end
skynet.exit()
end)

53
test/testredis2.lua Normal file
View File

@@ -0,0 +1,53 @@
local skynet = require "skynet"
local redis = require "redis"
local db
function add1(key, count)
local t = {}
for i = 1, count do
t[2*i -1] = "key" ..i
t[2*i] = "value" .. i
end
db:hmset(key, table.unpack(t))
end
function add2(key, count)
local t = {}
for i = 1, count do
t[2*i -1] = "key" ..i
t[2*i] = "value" .. i
end
table.insert(t, 1, key)
db:hmset(t)
end
function __init__()
db = redis.connect {
host = "127.0.0.1",
port = 6300,
db = 0,
auth = "foobared"
}
print("dbsize:", db:dbsize())
local ok, msg = xpcall(add1, debug.traceback, "test1", 250000)
if not ok then
print("add1 failed", msg)
else
print("add1 succeed")
end
local ok, msg = xpcall(add2, debug.traceback, "test2", 250000)
if not ok then
print("add2 failed", msg)
else
print("add2 succeed")
end
print("dbsize:", db:dbsize())
print("redistest launched")
end
skynet.start(__init__)

View File

@@ -21,6 +21,9 @@ if mode == "agent" then
id = tonumber(id)
skynet.start(function()
-- A small limit, if socket buffer overflow, close the client
socket.limit(64)
skynet.fork(function()
echo(id)
skynet.exit()
@@ -30,7 +33,7 @@ else
local function accept(id)
socket.start(id)
socket.write(id, "Hello Skynet\n")
skynet.newservice("testsocket", "agent", id)
skynet.newservice(SERVICE_NAME, "agent", id)
-- notice: Some data on this connection(id) may lost before new service start.
-- So, be careful when you want to use start / abandon / start .
socket.abandon(id)

22
test/time.lua Normal file
View File

@@ -0,0 +1,22 @@
local skynet = require "skynet"
skynet.start(function()
print(skynet.starttime())
print(skynet.now())
skynet.timeout(1, function()
print("in 1", skynet.now())
end)
skynet.timeout(2, function()
print("in 2", skynet.now())
end)
skynet.timeout(3, function()
print("in 3", skynet.now())
end)
skynet.timeout(4, function()
print("in 4", skynet.now())
end)
skynet.timeout(100, function()
print("in 100", skynet.now())
end)
end)