Compare commits

...

276 Commits

Author SHA1 Message Date
Cloud Wu
d3a6b8d80b fix #1141 2019-12-30 10:57:44 +08:00
yxt945
672bdcf39f 增加mysql存贮过程和blob读写示例 2019-12-30 10:56:49 +08:00
Cloud Wu
d232af70f2 fix #1139 2019-12-25 17:58:03 +08:00
zixun
c075de7425 use SSL_CTX_use_certificate_chain_file instead of SSL_CTX_use_certificate_file 2019-12-23 19:25:39 +08:00
冉朋
f2d3bc3e5c 测试单元 2019-12-17 20:06:18 +08:00
冉朋
386c709f42 修改制表符 2019-12-17 20:06:18 +08:00
冉朋
64d6baa176 修改制表符 2019-12-17 20:06:18 +08:00
冉朋
ed6dd39670 支持预处理句柄重置和释放 2019-12-17 20:06:18 +08:00
fisherman
5527e9e32e 增加 查询错误 提示 2019-12-13 16:15:54 +08:00
Hanlei Qin
3c7279a6b7 1. disambiguation: testdb --> testcoll (test collection)
2. let `c` as cllient, `db` as `c[db_name]`
3. clear up as lua-check
2019-12-10 12:54:59 +08:00
Hanlei Qin
b2e50c3bfa fixed 2019-12-10 12:54:59 +08:00
Cloud Wu
99a7d745fb use socket_channle:changehost, this may also fix #1130 2019-12-04 15:33:01 +08:00
wudeng
b295b875c8 fix sharedata emptyslot 2019-11-29 15:11:33 +08:00
zixun
a15c64a73b fix sharetable update when match self coroutine 2019-11-29 10:13:00 +08:00
zixun
b7b595e53a fix kqueue read with eof 2019-11-28 10:20:00 +08:00
Jay Li
0e3f37f38b Call tls.closefunc 2019-11-22 16:24:11 +08:00
Cloud Wu
a6293f27cd 1.3.0 rc 2019-11-19 16:42:03 +08:00
zixun
8450e7f366 add result of accept 2019-11-19 16:25:43 +08:00
Hanlei Qin
4585da9cbd bug fixed 2019-11-19 16:25:43 +08:00
zixun
38c47b8a5d add websocket address and url param 2019-11-19 16:25:43 +08:00
zixun
21d680d5b7 triger handle close when force close 2019-11-19 16:25:43 +08:00
zixun
ec8e518abc only server websocket check frame size 2019-11-19 16:25:43 +08:00
zixun
082fb732e5 fix httpver 2019-11-19 16:25:43 +08:00
zixun
b5ea18f44b check full frame size 2019-11-19 16:25:43 +08:00
zixun
8aac2114e3 delete debug print 2019-11-19 16:25:43 +08:00
zixun
0e96c761f8 add write with masked and limit payload 2019-11-19 16:25:43 +08:00
zixun
60f4f26b85 fix closed and delete send_buf 2019-11-19 16:25:43 +08:00
zixun
7240de08a9 use sockethelper connect 2019-11-19 16:25:43 +08:00
zixun
4341106364 fix mask and close 2019-11-19 16:25:43 +08:00
zixun
81a7c44a05 add ws/wss server and client support 2019-11-19 16:25:43 +08:00
Cloud Wu
80d1082b42 bugfix 2019-11-14 10:49:25 +08:00
Cloud Wu
9d7ea09789 Add socket_sendbuffer 2019-11-14 10:49:25 +08:00
Hanlei Qin
58291a2a48 restore some styles as before. 2019-10-29 19:14:06 +08:00
Hanlei Qin
49c21916a2 format up by vscode plugin 2019-10-29 19:14:06 +08:00
Hanlei Qin
6b4050bf2c format up :
0. remove some useless multiple blank lines.
1. uniform indent as white-space.
2. add some expression white-space pad.
2019-10-29 19:14:06 +08:00
Hanlei Qin
f4d54182e9 may improve Intermediate variables. 2019-10-29 19:14:06 +08:00
Hanlei Qin
f6679a778f remove useless Intermediate variables 2019-10-29 19:14:06 +08:00
yxt945
082430147f 使用toingeger代替math.floor判断是否整数 2019-10-29 11:50:33 +08:00
yxt945
6dd47e6690 COM_STMT_EXECUTE改为'\x17',保持COM_XXX变量类型统一
整数除法改为//,不再使用math.floor
_compose_packet改为使用string.pack编码
2019-10-29 11:50:33 +08:00
yxt945
d3c4bee0c9 _compose_packet取消size参数,直接从#req读取数据大小
read_prepare_result使用string.unpack一次性读取数据
_get_datetime使用string.unpack一次性读取数据
_parse_row_data_binary计算null_count修改为 mathfloor((ncols+9)/8)
2019-10-29 11:50:33 +08:00
yxt945
15ae26b8bc 取消变量 pow_2_16,pow_2_24,改为立即数 1<<16,1<<24
取消预处理语句缓存,由用户自行管理
COM_QUERY,COM_PING,COM_STMT_PREPARE改为字符类型,避免使用时转换
2019-10-29 11:50:33 +08:00
yxt945
29e7256948 替换换行符 \r 为unix风格 \n 2019-10-29 11:50:33 +08:00
yxt945
4f050fa987 增加mysql.ping测试网络状态
增加blob数据格式支持
增加mysql.execute支持预处理语句和存储过程调用
2019-10-29 11:50:33 +08:00
yxt945
066c2c3a54 增加mysql.ping测试网络状态
增加blob数据格式支持
增加mysql.execute支持预处理语句和存储过程调用
2019-10-29 11:50:33 +08:00
Cloud Wu
41c66d1b20 add skynet.trace_timeout(on), see #1098 2019-10-22 16:11:36 +08:00
Cloud Wu
82ed7efb1b use traceback 2019-10-22 15:25:39 +08:00
zixun
f17c17b8c7 fix match intern mt and stackvalues 2019-10-21 11:41:05 +08:00
zixun
8a1d7006eb fix match thread, table key 2019-10-21 11:41:05 +08:00
wudeng
4ddc1577ef fix: coroutine leak when dispatch failed 2019-10-10 11:25:12 +08:00
Sean Feng
9c4e0d5bb7 add senders command in clusterd service 2019-09-29 08:34:43 +08:00
hong
21b1c449de luaH_set check shared table 2019-09-21 15:59:23 +08:00
Cloud Wu
e485aae55b This may fix #1080 2019-08-30 10:16:31 +08:00
Cloud Wu
5025e6887f fix #1079 2019-08-29 16:21:01 +08:00
Cloud Wu
e4224137f1 fix #1078 2019-08-28 20:19:15 +08:00
wudeng
478575436b uniqtask for gm 2019-08-27 21:58:47 +08:00
zixun
65eb351a3b fix replace mt when sharetable update 2019-08-15 19:08:06 +08:00
xjdrew
2e8659d5fc dns: remove unused variable 2019-08-15 19:07:51 +08:00
Cloud Wu
baf5987b0b fix #1062 2019-08-07 10:20:38 +08:00
Cloud Wu
7e42653f80 fix #1057 2019-07-29 16:54:49 +08:00
Cloud Wu
89f487e0a4 bugfix: init the lock of code cache at start 2019-07-02 23:08:54 +08:00
Cloud Wu
9193035767 Improve error message , see issue #1050 2019-07-01 20:26:53 +08:00
zixun
4fa1ba57cb add SSL_CTX_new error string 2019-06-27 15:37:13 +08:00
Cloud Wu
10fd5791f7 dec id would be better 2019-06-25 10:01:19 +08:00
Cloud Wu
5d26fb3f18 remove ssm and add string id 2019-06-25 10:01:19 +08:00
hong
7032f21d18 bugfix Proto is gcobject 2019-06-18 10:41:33 +08:00
Cloud Wu
c80b462412 remove l_G from Proto 2019-06-18 10:41:33 +08:00
Cloud Wu
744fbea7ee update jemalloc 5.2.0 2019-06-17 10:19:17 +08:00
Cloud Wu
5750b2d5ee Merge branch 'bugfix' 2019-06-17 09:57:11 +08:00
zixun
e9581adfc4 pass sharedtable match 2019-06-15 16:02:32 +08:00
zixun
6803f45aa1 add sharetable update 2019-06-15 16:02:32 +08:00
lwkienun
8e2facbfb8 fix crash of sharedata by incref before sharedated.monitor return cobj to client.
crash occr analise:
1.sharedated.update call many times in a short time(eg:3 times) to change a same name conf value to a->b->c->d.
2.sharedated sending 3 response  to monitoring clients。a->b and b->c and c->d.
3.if b is destroyed and it's memory is reallocated and rewrited when client process the first message a->b, client's call lbox will crash.

solution:
conf b must be keeped before message(a->b) is processed by inc it's ref.
Any return value from host to client must use incref before send to client.
2019-06-15 15:59:37 +08:00
Cloud Wu
6f0e88dc59 bugfix, See issue #1027 2019-06-15 00:37:42 +08:00
Cloud Wu
5a0f68999e fix #1032 2019-06-14 11:04:20 +08:00
Cloud Wu
24b333a5e9 add api lua_sharestring 2019-06-13 20:01:10 +08:00
Cloud Wu
b45384cc9f short string in matrix should be in fixed set 2019-06-13 17:55:45 +08:00
Cloud Wu
7fed938593 mark all short string shared, see #1027 2019-06-13 16:58:57 +08:00
Cloud Wu
ca4f549f0d free all objects in matrix 2019-06-13 14:55:57 +08:00
hong
a04e6b5b29 lua_checksig LUA_CACHELIB 2019-06-10 15:11:51 +08:00
hong
82f3e80e06 collectref的时候减少nuse 2019-06-10 15:11:51 +08:00
hong
9ffa0c6e30 markref冲突时候刷新 cache 2019-06-10 15:11:51 +08:00
hong
64d99c1bd5 nuse计数错误 2019-06-10 15:11:51 +08:00
hong
da87df6b86 有概率出现total为0的时候garbage不为0的情况 2019-06-10 15:11:51 +08:00
hong
fafc4cad34 do not makeshared to LUA_TSHRSTR 2019-06-10 15:11:51 +08:00
hong
1b60c522b0 字符串引用计数BUG 2019-06-10 15:11:51 +08:00
Cloud Wu
a8c1828786 fix #1011 2019-06-10 15:11:51 +08:00
hong
ff9b0538a4 Reserve SHAREDBIT in GC 2019-06-10 15:11:51 +08:00
hong
bed5f878dc use ttnov in shareproto 2019-06-10 15:11:51 +08:00
hong
505da68cb6 Should not link shared table to gray 2019-06-10 15:11:51 +08:00
Cloud Wu
68e94b2792 add sharetable.loadtable 2019-06-10 15:11:51 +08:00
Cloud Wu
e3c5d63a97 setmetatable raise error 2019-06-10 15:11:51 +08:00
Cloud Wu
3a0981661c don't use SSM.garbage 2019-06-10 15:11:51 +08:00
Cloud Wu
47d1047004 sweep garbage strings 2019-06-10 15:11:51 +08:00
Cloud Wu
2bcc691c4d add gc service 2019-06-10 15:11:51 +08:00
Cloud Wu
76b166f04a Add new sharetable 2019-06-10 15:11:51 +08:00
Cloud Wu
2ceb642b5d rewrite SSM and clonefunction 2019-06-10 15:11:51 +08:00
zixun
2d6d2c75a4 fix BIO_read and BIO_write return 0 2019-05-22 18:30:44 +08:00
zixun
194940822e fix SSL_read and SSL_write return 0 2019-05-22 14:52:45 +08:00
zixun
be590cfa8c #1016 bugfix SSL_read and SSL_do_handshake 2019-05-21 22:24:37 +08:00
Cloud Wu
6addb504e4 fix #1012 2019-05-15 10:49:19 +08:00
hong
db61ec376a clustersender tracetag bug 2019-05-07 10:05:06 +08:00
zixun
431feb6f16 bugfix #1007 2019-05-06 14:52:06 +08:00
zixun
2c8d373236 fix use NOUSE_JEMALLOC 2019-05-06 11:17:05 +08:00
Cloud Wu
9b69af0a4d use tinsert instead of table.insert 2019-05-06 10:29:23 +08:00
Cloud Wu
046fb69f84 bugfix 2019-05-06 10:20:15 +08:00
wudeng
6231f1c884 build jemalloc with --enable-prof 2019-05-03 18:15:07 +08:00
wudeng
35aa00fb13 Add jemalloc heap profilling in debug console 2019-05-01 20:37:48 +08:00
Cloud Wu
4159600fbc order fork, see #1000 2019-04-28 09:53:52 +08:00
hong
04e2a36c4a Update service_provider.lua
boot成功后的launch消息异常
2019-04-28 00:18:24 +08:00
wudeng
95cb848772 collectgarbage count change to lua 5.3 2019-04-19 19:09:05 +08:00
Cloud Wu
302fc580a5 bugfix 2019-04-18 15:41:24 +08:00
Cloud Wu
3048eed2aa try to fix #988 2019-04-18 15:41:24 +08:00
云风
e0729a483d Revert "bugfix:cluster初始化节点的时候有可能导致消息乱序"
This reverts commit 9ba0860c70.
2019-04-18 15:40:22 +08:00
云风
201becd3d1 Revert "避免失败卡住"
This reverts commit 77e2643728.
2019-04-18 15:40:22 +08:00
hong
77e2643728 避免失败卡住
add pcall
2019-04-18 15:39:50 +08:00
hong
9ba0860c70 bugfix:cluster初始化节点的时候有可能导致消息乱序 2019-04-18 15:39:50 +08:00
hong
4c17005c03 优化SSM查询 2019-04-17 17:46:05 +08:00
Cloud Wu
cf18b59d90 fix #981 2019-04-16 17:32:46 +08:00
Cloud Wu
fbd932e846 OOM check 2019-04-03 11:29:37 +08:00
Cloud Wu
8e8a92ca2d overflow check 2019-04-03 11:15:33 +08:00
Cloud Wu
6ab841beec turn on SSM during lua_load 2019-04-03 10:17:20 +08:00
Cloud Wu
6f40120ad8 expand SSM during loadfile 2019-04-02 20:47:27 +08:00
Cloud Wu
f8d55affba use sign n for SSM 2019-04-02 19:32:44 +08:00
Cloud Wu
56d24f46d6 overflow check 2019-04-02 19:15:35 +08:00
Cloud Wu
64e0c4daff calc variance 2019-04-02 19:15:35 +08:00
Cloud Wu
5bf635c75c SSM expanding 2019-04-02 19:15:35 +08:00
Cloud Wu
2011596de0 fix #979 2019-04-02 17:43:24 +08:00
zixun
3c6c0f7aa4 bugfix #976 long string instead of global seed 2019-03-28 21:21:44 +08:00
zixun
ea0cc1fade fix check header limit 2019-03-28 21:21:44 +08:00
xjdrew
ee1f5055ea bugfix: dns parse hosts.conf 2019-03-28 21:16:06 +08:00
drew.zxj
305a29d885 dns: parse /etc/hosts 2019-03-27 17:25:33 +08:00
CoolDesert
2651929f5b fix tls make 2019-03-27 11:05:05 +08:00
CoolDesert
1af78bc585 fix tls make 2019-03-27 11:05:05 +08:00
Cloud Wu
062f767bbf fix #967 2019-03-26 23:45:33 +08:00
zixun
0c66252cd1 fix post with https 2019-03-26 21:31:36 +08:00
Cloud Wu
45afa0fdcf fix #965 2019-03-26 18:46:31 +08:00
Cloud Wu
4c9c2ac41d Merge branch 'lvzixun-self_skynet' 2019-03-26 10:32:23 +08:00
Cloud Wu
bfbbe91efa turn off ltls by default 2019-03-26 10:31:47 +08:00
Cloud Wu
eda9f771e6 Merge branch 'self_skynet' of https://github.com/lvzixun/skynet into lvzixun-self_skynet 2019-03-26 10:08:10 +08:00
Cloud Wu
7cb4bbb960 Merge branch 'cluster' 2019-03-26 09:46:57 +08:00
Cloud Wu
2c247b511e Merge branch 'sharedk' 2019-03-26 09:46:38 +08:00
Cloud Wu
ea1affda4c fix #962 2019-03-25 09:42:53 +08:00
Cloud Wu
1c3b563ef8 add wait queue 2019-03-20 19:44:08 +08:00
Dalton
9ffdf2dbde Update skynet_daemon.c 2019-03-20 18:26:45 +08:00
Cloud Wu
000fa2be3a multi cluster sender 2019-03-20 17:56:39 +08:00
zixun
7746193b5f add https client and server support by bios 2019-03-14 10:36:02 +08:00
Cloud Wu
3f38a711ad Shared K 2019-03-14 09:54:40 +08:00
Cloud Wu
1d4308f33a Fix memory leak, See #952 2019-03-06 00:19:51 +08:00
Cloud Wu
48e5c36b5e volatile for signal, see #950 2019-03-01 16:47:29 +08:00
Cloud Wu
1422cae7fb Consider __pairs, see #942 2019-02-13 15:36:55 +08:00
Naix
9e16b04a5b dns reInit bug
recall dns.server()
false	./lualib/skynet/dns.lua:340: assertion failed!
2019-01-18 20:01:04 +08:00
Cloud Wu
0fbbd5f4d5 type can be DATA 2019-01-15 10:55:18 +08:00
Cloud Wu
6eb9b64f06 remove mysqlaux.c 2019-01-15 10:55:18 +08:00
Cloud Wu
d71c8f8b7d remove new_tab 2019-01-15 10:55:18 +08:00
Cloud Wu
68c3762abf bugfix : handshake error handle 2019-01-15 10:55:18 +08:00
Cloud Wu
304272249e fix #919 2018-11-14 11:43:23 +08:00
Oneoeigh
2102d8b9f0 Revise README.md
Slight revisions of readme to make it more concise.
2018-11-14 09:10:08 +08:00
Cloud Wu
2ee85a91f9 Release 1.2.0 2018-11-06 11:11:29 +08:00
Cloud Wu
8a3a0c1b71 register logger name in framework, see #909 2018-10-21 13:21:51 +08:00
Sean Feng
b4752f2394 multiresultset spelling mistake 2018-10-17 19:54:38 +08:00
Cloud Wu
f110b51290 add socketchannel.overload 2018-10-17 14:54:44 +08:00
Cloud Wu
e0f16b8df5 remove dead_service table, address may reused 2018-10-15 10:05:23 +08:00
Cloud Wu
08e56f4316 fix #793 2018-10-11 17:38:49 +08:00
Cloud Wu
7e57e498f6 remove dead_service table, address may reused 2018-10-08 15:44:12 +08:00
Cloud Wu
98b5c7c7c6 address 0 is reserved 2018-10-08 14:20:53 +08:00
sundream
02d5f4fbe9 rediscluster: support eval/evalshal + subscribe/publish 2018-09-27 10:00:30 +08:00
Hanlei Qin
818ff8314d remove unused code 2018-09-27 09:59:18 +08:00
Hanlei Qin
d23e6f8d8e 1. remove unused code; 2. weird indents fixed. 2018-09-20 00:31:14 +08:00
Hanlei Qin
f217a56f6e Uniform indent to tab and clear up. 2018-09-20 00:29:19 +08:00
Hanlei Qin
46b49adf9e remove useless file 2018-09-16 18:41:30 +08:00
Hanlei Qin
d9fb4d06ec remove useless local function 2018-09-16 18:41:06 +08:00
Cloud Wu
34a9979255 check launching address 2018-09-13 18:59:03 +08:00
Cloud Wu
89e7a06deb add more info when service init blocked 2018-09-13 18:27:05 +08:00
Cloud Wu
43d02ac456 update jemalloc to 5.1.0 2018-09-12 15:23:59 +08:00
Cloud Wu
c839159470 remove netpack from gate service 2018-09-12 11:45:41 +08:00
Cloud Wu
823b773051 remove unused require 2018-09-12 11:31:12 +08:00
Cloud Wu
f8434d34b6 report last accept time 2018-09-07 16:26:56 +08:00
Cloud Wu
61980c8a1f add socket.netstat 2018-09-07 16:11:27 +08:00
Cloud Wu
35176383b7 add skynet.context 2018-09-06 19:01:10 +08:00
Cloud Wu
c96e20e6c3 add skynet.context and enhance debug console command service 2018-09-06 18:59:33 +08:00
LiuYang
ce0cdc7bd3 add mongo test case: auth 2018-08-30 11:42:47 +08:00
Cloud Wu
7e63080c03 add mongo_db:auth 2018-08-30 10:50:52 +08:00
Cloud Wu
1c8ed8a46e add mongo config option: authdb, see issue #884 2018-08-30 10:50:52 +08:00
Cloud Wu
c4334be9c3 add mongo_db:auth 2018-08-30 09:51:55 +08:00
Cloud Wu
e6e69ae805 add mongo config option: authdb, see issue #884 2018-08-30 09:38:18 +08:00
LiuYang
8ce816de7f fix mongodb testcase 2018-08-29 23:33:17 +08:00
Cloud Wu
2fb52f6fce cleanup 2018-08-29 15:29:26 +08:00
Cloud Wu
c72d4d2134 support string address name, see #883 2018-08-28 15:15:38 +08:00
btt
18a36c171f debug console inject cmd support args 2018-08-23 17:02:06 +08:00
Cloud Wu
7b3c1631d1 more stable 2018-08-17 21:27:14 +08:00
Cloud Wu
4613fde654 fix #877 2018-08-17 21:16:35 +08:00
Cloud Wu
143baec319 remove duplicate code 2018-08-13 14:12:15 +08:00
fanyh
168a07d658 sleep time 1s-> 1m, sleep 1s prodcut more message 2018-08-09 19:28:59 +08:00
Cloud Wu
281acf4c71 Use fork instead of timeout 0, see #873 2018-08-07 14:55:26 +08:00
Cloud Wu
d2ab6863e3 fix #872 2018-08-07 10:49:21 +08:00
Cloud Wu
e55ad63d3c fix #873 2018-08-07 09:43:50 +08:00
Cloud Wu
ec2eaa70a4 Merge branch 'master' of https://github.com/cloudwu/skynet 2018-08-03 11:29:12 +08:00
Cloud Wu
d402619347 see #870 2018-08-03 11:28:18 +08:00
Cloud Wu
c101d9df17 see #870 2018-08-03 11:24:14 +08:00
hong
b5653a68ea runnging拼写错误 2018-08-02 21:30:03 +08:00
hong
c9942deaa9 queryname并发导致消息乱序
当有1个以上的co进入queryname,后面的协程有在第1个以后某个的co先执行(第一个已经返回),导致cluster消息乱序
2018-08-02 21:30:03 +08:00
yenshan98
2df1446c37 Rearranged sentence to be reader friendly. 2018-07-30 15:10:57 +08:00
Cloud Wu
9421815327 add posix_memalign hook 2018-07-23 15:32:35 +08:00
Cloud Wu
1a0c9997ec fix #863 2018-07-23 14:53:01 +08:00
Cloud Wu
16f060f864 hook aligned_alloc 2018-07-20 14:46:53 +08:00
Cloud Wu
ea7c6402dd update lua to 5.3.5 2018-07-10 22:11:56 +08:00
zixun
07db2580c4 fix kqueue error flag 2018-07-05 18:55:51 +08:00
zixun
1df72c0afe fix kqueue eof event 2018-07-05 18:37:50 +08:00
Cloud Wu
0e41231298 fix #857 2018-07-04 15:10:32 +08:00
Cloud Wu
8224b5a62a udp_connect may raise error 2018-06-26 09:49:18 +08:00
Cloud Wu
d8ab9dea1b fix #852 2018-06-25 14:24:04 +08:00
Cloud Wu
a8e5c31381 check udp address, see #852 2018-06-25 12:10:30 +08:00
Cloud Wu
3a1556e1fd add new debug command trace 2018-06-08 11:24:27 +08:00
Cloud Wu
4b5fbab129 recycle coroutine bugfix 2018-06-08 10:23:36 +08:00
Cloud Wu
b1ec1f4d18 token bugfix 2018-06-08 10:23:36 +08:00
Cloud Wu
16d8f4c774 cleanup 2018-06-08 10:23:36 +08:00
Cloud Wu
f8b5ec48e8 support user tag 2018-05-28 23:13:05 +08:00
Cloud Wu
7a26926965 resume trace log 2018-05-28 21:45:41 +08:00
Cloud Wu
2990fbc7cf ignore response, fix #841 2018-05-28 20:38:10 +08:00
Cloud Wu
e8e38f1682 add session log 2018-05-28 18:16:31 +08:00
Cloud Wu
35b4a09c3d unique cluster trace tag 2018-05-28 18:09:34 +08:00
Cloud Wu
9035fbe96b cluster trace 2018-05-28 16:39:04 +08:00
Cloud Wu
a41a5fadd2 ignore ret in clientagent 2018-05-28 11:24:55 +08:00
Cloud Wu
d6f265e703 call skynet.trace() in example 2018-05-26 17:37:19 +08:00
Cloud Wu
596c77afcd trace bugfix 2018-05-26 17:17:20 +08:00
Cloud Wu
e53d985c4f add skynet.trace() 2018-05-26 16:26:50 +08:00
Cloud Wu
348e53245b skynet.wait use token instead of coroutine.running() 2018-05-25 10:42:58 +08:00
Cloud Wu
2fde0a0ae4 log error when forget response a session. Add skynet.ignoreret() 2018-05-24 16:53:27 +08:00
Cloud Wu
85ec428f3f remove assert 2018-05-22 20:04:05 +08:00
Cloud Wu
a8ab809928 add __nowating flag to cluster config, see issue #803 2018-05-22 19:49:07 +08:00
caijietao
6c7cb5313d set backlog to 128 2018-05-22 13:08:00 +08:00
spin6lock
188e38198a add ipv6 host support to service_gate.c
service_gate的地址解析用strchr找到第一个':',并将后续的字符串作为
端口号解析。填ipv6地址"0:0:0:0:0:0:0:0:9999"的时候会出错,现在改成
strrchr,从右面找到的第一个':'
2018-05-22 13:07:02 +08:00
Cloud Wu
294f557268 lua 5.3.4 bug report 6 2018-05-17 12:03:03 +08:00
Cloud Wu
4dd622e180 socket channel order mode support padding, see issue #835 2018-05-09 17:38:32 +08:00
Cloud Wu
5f8e5f9be5 add random for seed 2018-05-07 11:10:45 +08:00
Cloud Wu
e561896966 Merge branch 'master' of github.com:cloudwu/skynet 2018-05-07 10:55:34 +08:00
Cloud Wu
ea25e20c88 more random seed 2018-05-07 10:55:18 +08:00
云风
003b0fdb02 Add logo 2018-05-03 23:26:53 +08:00
xjdrew
8de6500677 update mongo driver: safe_insert, safe_update, safe_delete 2018-05-02 01:36:00 +08:00
Cloud Wu
7df13e922b add testtimeout 2018-04-20 11:44:05 +08:00
Cloud Wu
182d7c7dc7 support @name, see #823 2018-04-20 10:11:16 +08:00
Cloud Wu
f4d5bc7aa4 forward fd to agent 2018-04-18 19:32:15 +08:00
Cloud Wu
d53d98b625 Merge branch 'clusteragent' 2018-04-18 19:30:24 +08:00
Cloud Wu
2bfba716ef forward fd to agent 2018-04-18 19:29:41 +08:00
Cloud Wu
4cbe33d15d remove unused sz 2018-04-17 10:47:41 +08:00
Cloud Wu
a9852273cb add addresscommand 2018-04-17 10:47:41 +08:00
Cloud Wu
eb8a2b5e65 Improve cluster package module 2018-04-17 10:47:41 +08:00
Cloud Wu
7304a990cb use clusteragent to dispatch cluster request 2018-04-17 10:47:41 +08:00
Cloud Wu
311d7c8f6a remove unused sz 2018-04-16 12:56:34 +08:00
Cloud Wu
5a3d2fdac7 add addresscommand 2018-04-14 20:30:47 +08:00
Cloud Wu
4b88f68ab8 Improve cluster package module 2018-04-14 18:14:44 +08:00
Cloud Wu
70c224c3e7 use clusteragent to dispatch cluster request 2018-04-14 16:11:26 +08:00
Cloud Wu
1932d33b41 set node = false when node is down, see #803 2018-02-24 21:26:24 +08:00
Cloud Wu
9cf4525a8f avoid error circulation 2018-02-12 18:07:16 +08:00
Cloud Wu
0846a6533d fix a legacy problem. make harbor service more stable 2018-02-12 18:07:16 +08:00
Cloud Wu
484404295e Merge branch 'hongling0-master' 2018-02-05 11:38:22 +08:00
云风
3e54becb95 Merge branch 'master' into master 2018-02-05 11:34:52 +08:00
hong
ab13305b64 monitor中不增加ref 2018-02-05 10:18:35 +08:00
Cloud Wu
6fdb123df4 bugfix, See #800 2018-02-04 21:32:41 +08:00
Cloud Wu
6cdc1cf95c collect used response, see #800 2018-02-04 16:25:19 +08:00
hong
2dd5a06616 抄写错误 2018-02-03 15:49:01 +08:00
hong
e7436bfa95 skynet.response() leak
datasheet在monitor接口里面产生的reponse在release接口里面没有释放
2018-02-03 15:43:33 +08:00
Cloud Wu
084aab4bcd dns server auto retire 2018-01-25 15:56:47 +08:00
Cloud Wu
cd99557368 udp send don't need inc/dec sending ref, see issue #794 2018-01-25 15:55:45 +08:00
Cloud Wu
04f4004934 sproto bugfix 2018-01-23 11:24:44 +08:00
Cloud Wu
bbf46f935a dec sending count asap, this may fix #794 2018-01-19 10:41:35 +08:00
Cloud Wu
b792c7144d clusterd wait for cluster.reload when the name no exist 2018-01-04 14:18:29 +08:00
Cloud Wu
5d5112257c use 32bit sending, see issue #777 2017-12-06 20:58:36 +08:00
云风
747e6c7848 Merge pull request #775 from cloudwu/tcpwriteorder
Tcpwriteorder, Fix #744
2017-12-04 11:45:49 +08:00
Cloud Wu
45d848c910 bugfix: inc sending ref, See issue #774 2017-12-04 10:55:47 +08:00
Cloud Wu
f12fa7e8f9 May fix issue #774 2017-12-03 00:26:12 +08:00
Cloud Wu
568a435e9e fix issue #773 2017-11-30 16:13:58 +08:00
Cloud Wu
c46f2633be fork may not execute when the service exit, and __gc would send message release without monitor 2017-11-16 10:47:18 +08:00
Cloud Wu
b51e28a3e0 set nodelay, see issue #763 2017-11-14 18:01:08 +08:00
云风
badfab8561 Merge pull request #761 from cloudwu/mongolimit
positive limit support
2017-11-07 10:17:04 +08:00
Cloud Wu
d5c0d687b3 positive limit support 2017-11-06 20:51:33 +08:00
Cloud Wu
57f08426ee concurrent cluster link, fix issue #757 2017-11-02 22:31:54 +08:00
157 changed files with 6077 additions and 2017 deletions

View File

@@ -1,5 +1,5 @@
/*
** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
** $Id: lapi.c,v 2.259.1.2 2017/12/06 18:35:12 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -534,6 +534,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
setfvalue(L->top, fn);
api_incr_top(L);
}
else {
CClosure *cl;
@@ -547,9 +548,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
/* does not need barrier because closure is white */
}
setclCvalue(L, L->top, cl);
api_incr_top(L);
luaC_checkGC(L);
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
}
@@ -857,6 +858,8 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
}
switch (ttnov(obj)) {
case LUA_TTABLE: {
if (isshared(hvalue(obj)))
luaG_runerror(L, "can't setmetatable to shared table");
hvalue(obj)->metatable = mt;
if (mt) {
luaC_objbarrier(L, gcvalue(obj), mt);
@@ -1012,46 +1015,15 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
return status;
}
static void cloneproto (lua_State *L, Proto *f, const Proto *src) {
/* copy constants and nested proto */
int i,n;
n = src->sp->sizek;
f->k=luaM_newvector(L,n,TValue);
for (i=0; i<n; i++) setnilvalue(&f->k[i]);
for (i=0; i<n; i++) {
const TValue *s=&src->k[i];
TValue *o=&f->k[i];
if (ttisstring(s)) {
TString * str = luaS_clonestring(L,tsvalue(s));
setsvalue2n(L,o,str);
} else {
setobj(L,o,s);
}
}
n = src->sp->sizep;
f->p=luaM_newvector(L,n,struct Proto *);
for (i=0; i<n; i++) f->p[i]=NULL;
for (i=0; i<n; i++) {
f->p[i]= luaF_newproto(L, src->p[i]->sp);
cloneproto(L, f->p[i], src->p[i]);
}
}
LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
LClosure *cl;
LClosure *f = cast(LClosure *, fp);
api_check(L, isshared(f->p), "Not a shared proto");
lua_lock(L);
if (f->p->sp->l_G == G(L)) {
setclLvalue(L,L->top,f);
api_incr_top(L);
lua_unlock(L);
return;
}
cl = luaF_newLclosure(L,f->nupvalues);
setclLvalue(L,L->top,cl);
api_incr_top(L);
cl->p = luaF_newproto(L, f->p->sp);
cloneproto(L, cl->p, f->p);
cl->p = f->p;
luaF_initupvals(L, cl);
if (cl->nupvalues >= 1) { /* does it have an upvalue? */
@@ -1065,6 +1037,34 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
lua_unlock(L);
}
LUA_API void lua_sharefunction (lua_State *L, int index) {
if (!lua_isfunction(L,index) || lua_iscfunction(L,index))
luaG_runerror(L, "Only Lua function can share");
LClosure *f = cast(LClosure *, lua_topointer(L, index));
luaF_shareproto(f->p);
}
LUA_API void lua_sharestring (lua_State *L, int index) {
const char *str = lua_tostring(L, index);
if (str == NULL)
luaG_runerror(L, "need a string to share");
TString *ts = (TString *)(str - sizeof(UTString));
luaS_share(ts);
}
LUA_API void lua_clonetable(lua_State *L, const void * tp) {
Table *t = cast(Table *, tp);
if (!isshared(t))
luaG_runerror(L, "Not a shared table");
lua_lock(L);
sethvalue(L, L->top, t);
api_incr_top(L);
lua_unlock(L);
}
LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
int status;
TValue *o;
@@ -1259,7 +1259,7 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val,
case LUA_TLCL: { /* Lua closure */
LClosure *f = clLvalue(fi);
TString *name;
SharedProto *p = f->p->sp;
Proto *p = f->p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
*val = f->upvals[n-1]->v;
if (uv) *uv = f->upvals[n - 1];
@@ -1311,7 +1311,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
StkId fi = index2addr(L, fidx);
api_check(L, ttisLclosure(fi), "Lua function expected");
f = clLvalue(fi);
api_check(L, (1 <= n && n <= f->p->sp->sizeupvalues), "invalid upvalue index");
api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
if (pf) *pf = f;
return &f->upvals[n - 1]; /* get its upvalue pointer */
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $
** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $
** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -699,8 +699,7 @@ static int skipcomment (LoadF *lf, int *cp) {
else return 0; /* no comment */
}
static int luaL_loadfilex_ (lua_State *L, const char *filename,
LUALIB_API int luaL_loadfilex_ (lua_State *L, const char *filename,
const char *mode) {
LoadF lf;
int status, readstatus;
@@ -1064,10 +1063,14 @@ clearcache() {
static void
init() {
SPIN_INIT(&CC);
CC.L = luaL_newstate();
}
LUALIB_API void
luaL_initcodecache(void) {
SPIN_INIT(&CC);
}
static const void *
load(const char *key) {
if (CC.L == NULL)
@@ -1091,21 +1094,20 @@ save(const char *key, const void * proto) {
SPIN_LOCK(&CC)
if (CC.L == NULL) {
init();
L = CC.L;
} else {
L = CC.L;
lua_pushstring(L, key);
lua_pushvalue(L, -1);
lua_rawget(L, LUA_REGISTRYINDEX);
result = lua_touserdata(L, -1); /* stack: key oldvalue */
if (result == NULL) {
lua_pop(L,1);
lua_pushlightuserdata(L, (void *)proto);
lua_rawset(L, LUA_REGISTRYINDEX);
} else {
lua_pop(L,2);
}
}
L = CC.L;
lua_pushstring(L, key);
lua_pushvalue(L, -1);
lua_rawget(L, LUA_REGISTRYINDEX);
result = lua_touserdata(L, -1); /* stack: key oldvalue */
if (result == NULL) {
lua_pop(L,1);
lua_pushlightuserdata(L, (void *)proto);
lua_rawset(L, LUA_REGISTRYINDEX);
} else {
lua_pop(L,2);
}
SPIN_UNLOCK(&CC)
return result;
}
@@ -1179,6 +1181,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lua_close(eL);
return err;
}
lua_sharefunction(eL, -1);
proto = lua_topointer(eL, -1);
const void * oldv = save(filename, proto);
if (oldv) {

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.h,v 1.131 2016/12/06 14:54:31 roberto Exp $
** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -82,6 +82,8 @@ LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
LUALIB_API int (luaL_loadfilex_) (lua_State *L, const char *filename,
const char *mode);
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp $
** $Id: lbaselib.c,v 1.314.1.1 2017/04/19 17:39:34 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $
** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcode.c,v 2.112 2016/12/22 13:08:50 roberto Exp $
** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -65,7 +65,7 @@ void luaK_nil (FuncState *fs, int from, int n) {
Instruction *previous;
int l = from + n - 1; /* last register to set nil */
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
previous = &fs->f->sp->code[fs->pc-1];
previous = &fs->f->code[fs->pc-1];
if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
int pfrom = GETARG_A(*previous); /* get previous range */
int pl = pfrom + GETARG_B(*previous);
@@ -88,7 +88,7 @@ void luaK_nil (FuncState *fs, int from, int n) {
** a list of jumps.
*/
static int getjump (FuncState *fs, int pc) {
int offset = GETARG_sBx(fs->f->sp->code[pc]);
int offset = GETARG_sBx(fs->f->code[pc]);
if (offset == NO_JUMP) /* point to itself represents end of list */
return NO_JUMP; /* end of list */
else
@@ -101,7 +101,7 @@ static int getjump (FuncState *fs, int pc) {
** (Jump addresses are relative in Lua)
*/
static void fixjump (FuncState *fs, int pc, int dest) {
Instruction *jmp = &fs->f->sp->code[pc];
Instruction *jmp = &fs->f->code[pc];
int offset = dest - (pc + 1);
lua_assert(dest != NO_JUMP);
if (abs(offset) > MAXARG_sBx)
@@ -177,7 +177,7 @@ int luaK_getlabel (FuncState *fs) {
** unconditional.
*/
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
Instruction *pi = &fs->f->sp->code[pc];
Instruction *pi = &fs->f->code[pc];
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
return pi-1;
else
@@ -278,10 +278,10 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
void luaK_patchclose (FuncState *fs, int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
for (; list != NO_JUMP; list = getjump(fs, list)) {
lua_assert(GET_OPCODE(fs->f->sp->code[list]) == OP_JMP &&
(GETARG_A(fs->f->sp->code[list]) == 0 ||
GETARG_A(fs->f->sp->code[list]) >= level));
SETARG_A(fs->f->sp->code[list], level);
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
(GETARG_A(fs->f->code[list]) == 0 ||
GETARG_A(fs->f->code[list]) >= level));
SETARG_A(fs->f->code[list], level);
}
}
@@ -294,13 +294,13 @@ static int luaK_code (FuncState *fs, Instruction i) {
Proto *f = fs->f;
dischargejpc(fs); /* 'pc' will change */
/* put new instruction in code array */
luaM_growvector(fs->ls->L, f->sp->code, fs->pc, f->sp->sizecode, Instruction,
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
MAX_INT, "opcodes");
f->sp->code[fs->pc] = i;
f->code[fs->pc] = i;
/* save corresponding line information */
luaM_growvector(fs->ls->L, f->sp->lineinfo, fs->pc, f->sp->sizelineinfo, int,
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
MAX_INT, "opcodes");
f->sp->lineinfo[fs->pc] = fs->ls->lastline;
f->lineinfo[fs->pc] = fs->ls->lastline;
return fs->pc++;
}
@@ -360,11 +360,11 @@ int luaK_codek (FuncState *fs, int reg, int k) {
*/
void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->sp->maxstacksize) {
if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXREGS)
luaX_syntaxerror(fs->ls,
"function or expression needs too many registers");
fs->f->sp->maxstacksize = cast_byte(newstack);
fs->f->maxstacksize = cast_byte(newstack);
}
}
@@ -438,13 +438,13 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
return k; /* reuse index */
}
/* constant not found; create a new entry */
oldsize = f->sp->sizek;
oldsize = f->sizek;
k = fs->nk;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setivalue(idx, k);
luaM_growvector(L, f->k, k, f->sp->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sp->sizek) setnilvalue(&f->k[oldsize++]);
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[k], v);
fs->nk++;
luaC_barrier(L, f, v);
@@ -1175,7 +1175,7 @@ void luaK_posfix (FuncState *fs, BinOpr op,
** Change line information associated with current position.
*/
void luaK_fixline (FuncState *fs, int line) {
fs->f->sp->lineinfo[fs->pc - 1] = line;
fs->f->lineinfo[fs->pc - 1] = line;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -41,7 +41,7 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->sp->code[(e)->u.info])
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $
** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $
** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $
** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp $
** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -125,14 +125,14 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
static const char *upvalname (Proto *p, int uv) {
TString *s = check_exp(uv < p->sp->sizeupvalues, p->sp->upvalues[uv].name);
TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
if (s == NULL) return "?";
else return getstr(s);
}
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
int nparams = clLvalue(ci->func)->p->sp->numparams;
int nparams = clLvalue(ci->func)->p->numparams;
if (n >= cast_int(ci->u.l.base - ci->func) - nparams)
return NULL; /* no such vararg */
else {
@@ -216,7 +216,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
ar->what = "C";
}
else {
SharedProto *p = cl->l.p->sp;
Proto *p = cl->l.p;
ar->source = p->source ? getstr(p->source) : "=?";
ar->linedefined = p->linedefined;
ar->lastlinedefined = p->lastlinedefined;
@@ -234,12 +234,12 @@ static void collectvalidlines (lua_State *L, Closure *f) {
else {
int i;
TValue v;
int *lineinfo = f->l.p->sp->lineinfo;
int *lineinfo = f->l.p->lineinfo;
Table *t = luaH_new(L); /* new table to store active lines */
sethvalue(L, L->top, t); /* push it on stack */
api_incr_top(L);
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
for (i = 0; i < f->l.p->sp->sizelineinfo; i++) /* for all lines with code */
for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
}
}
@@ -279,8 +279,8 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
ar->nparams = 0;
}
else {
ar->isvararg = f->l.p->sp->is_vararg;
ar->nparams = f->l.p->sp->numparams;
ar->isvararg = f->l.p->is_vararg;
ar->nparams = f->l.p->numparams;
}
break;
}
@@ -387,7 +387,7 @@ static int findsetreg (Proto *p, int lastpc, int reg) {
int setreg = -1; /* keep last instruction that changed 'reg' */
int jmptarget = 0; /* any code before this address is conditional */
for (pc = 0; pc < lastpc; pc++) {
Instruction i = p->sp->code[pc];
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
int a = GETARG_A(i);
switch (op) {
@@ -437,7 +437,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
/* else try symbolic execution */
pc = findsetreg(p, lastpc, reg);
if (pc != -1) { /* could find instruction? */
Instruction i = p->sp->code[pc];
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_MOVE: {
@@ -463,7 +463,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
case OP_LOADK:
case OP_LOADKX: {
int b = (op == OP_LOADK) ? GETARG_Bx(i)
: GETARG_Ax(p->sp->code[pc + 1]);
: GETARG_Ax(p->code[pc + 1]);
if (ttisstring(&p->k[b])) {
*name = svalue(&p->k[b]);
return "constant";
@@ -493,7 +493,7 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
TMS tm = (TMS)0; /* (initial value avoids warnings) */
Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->sp->code[pc]; /* calling instruction */
Instruction i = p->code[pc]; /* calling instruction */
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
@@ -658,7 +658,7 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->sp->source, currentline(ci));
luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
luaG_errormsg(L);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $
** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -11,9 +11,9 @@
#include "lstate.h"
#define pcRel(pc, p) (cast(int, (pc) - (p)->sp->code) - 1)
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
#define getfuncline(f,pc) (((f)->sp->lineinfo) ? (f)->sp->lineinfo[pc] : -1)
#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1)
#define resethookcount(L) (L->hookcount = L->basehookcount)

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 2.157 2016/12/13 15:52:21 roberto Exp $
** $Id: ldo.c,v 2.157.1.1 2017/04/19 17:20:42 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -290,7 +290,7 @@ static void callhook (lua_State *L, CallInfo *ci) {
}
static StkId adjust_varargs (lua_State *L, SharedProto *p, int actual) {
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
@@ -439,7 +439,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
SharedProto *p = clLvalue(func)->p->sp;
Proto *p = clLvalue(func)->p;
int n = cast_int(L->top - func) - 1; /* number of real arguments */
int fsize = p->maxstacksize; /* frame size */
checkstackp(L, fsize, func);
@@ -775,7 +775,7 @@ static void f_parser (lua_State *L, void *ud) {
checkmode(L, p->mode, "text");
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
}
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
luaF_initupvals(L, cl);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $
** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -87,7 +87,7 @@ static void DumpString (const TString *s, DumpState *D) {
}
static void DumpCode (const SharedProto *f, DumpState *D) {
static void DumpCode (const Proto *f, DumpState *D) {
DumpInt(f->sizecode, D);
DumpVector(f->code, f->sizecode, D);
}
@@ -97,7 +97,7 @@ static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
static void DumpConstants (const Proto *f, DumpState *D) {
int i;
int n = f->sp->sizek;
int n = f->sizek;
DumpInt(n, D);
for (i = 0; i < n; i++) {
const TValue *o = &f->k[i];
@@ -127,14 +127,14 @@ static void DumpConstants (const Proto *f, DumpState *D) {
static void DumpProtos (const Proto *f, DumpState *D) {
int i;
int n = f->sp->sizep;
int n = f->sizep;
DumpInt(n, D);
for (i = 0; i < n; i++)
DumpFunction(f->p[i], f->sp->source, D);
DumpFunction(f->p[i], f->source, D);
}
static void DumpUpvalues (const SharedProto *f, DumpState *D) {
static void DumpUpvalues (const Proto *f, DumpState *D) {
int i, n = f->sizeupvalues;
DumpInt(n, D);
for (i = 0; i < n; i++) {
@@ -144,7 +144,7 @@ static void DumpUpvalues (const SharedProto *f, DumpState *D) {
}
static void DumpDebug (const SharedProto *f, DumpState *D) {
static void DumpDebug (const Proto *f, DumpState *D) {
int i, n;
n = (D->strip) ? 0 : f->sizelineinfo;
DumpInt(n, D);
@@ -163,8 +163,7 @@ static void DumpDebug (const SharedProto *f, DumpState *D) {
}
static void DumpFunction (const Proto *fp, TString *psource, DumpState *D) {
const SharedProto *f = fp->sp;
static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
if (D->strip || f->source == psource)
DumpString(NULL, D); /* no debug info or same source as its parent */
else
@@ -175,9 +174,9 @@ static void DumpFunction (const Proto *fp, TString *psource, DumpState *D) {
DumpByte(f->is_vararg, D);
DumpByte(f->maxstacksize, D);
DumpCode(f, D);
DumpConstants(fp, D);
DumpConstants(f, D);
DumpUpvalues(f, D);
DumpProtos(fp, D);
DumpProtos(f, D);
DumpDebug(f, D);
}
@@ -209,7 +208,7 @@ int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
D.strip = strip;
D.status = 0;
DumpHeader(&D);
DumpByte(f->sp->sizeupvalues, &D);
DumpByte(f->sizeupvalues, &D);
DumpFunction(f, NULL, &D);
return D.status;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $
** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -19,6 +19,7 @@
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
@@ -96,63 +97,48 @@ void luaF_close (lua_State *L, StkId level) {
}
Proto *luaF_newproto (lua_State *L, SharedProto *sp) {
Proto *luaF_newproto (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));
Proto *f = gco2p(o);
f->sp = NULL;
f->k = NULL;
f->sizek = 0;
f->p = NULL;
f->cache = NULL;
if (sp == NULL) {
sp = luaM_new(L, SharedProto);
sp->l_G = G(L);
sp->sizek = 0;
sp->sizep = 0;
sp->code = NULL;
sp->sizecode = 0;
sp->lineinfo = NULL;
sp->sizelineinfo = 0;
sp->upvalues = NULL;
sp->sizeupvalues = 0;
sp->numparams = 0;
sp->is_vararg = 0;
sp->maxstacksize = 0;
sp->locvars = NULL;
sp->sizelocvars = 0;
sp->linedefined = 0;
sp->lastlinedefined = 0;
sp->source = NULL;
}
f->sp = sp;
f->sizep = 0;
f->code = NULL;
f->sizecode = 0;
f->lineinfo = NULL;
f->sizelineinfo = 0;
f->upvalues = NULL;
f->sizeupvalues = 0;
f->numparams = 0;
f->is_vararg = 0;
f->maxstacksize = 0;
f->locvars = NULL;
f->sizelocvars = 0;
f->linedefined = 0;
f->lastlinedefined = 0;
f->source = NULL;
return f;
}
static void freesharedproto (lua_State *L, SharedProto *f) {
if (f == NULL || G(L) != f->l_G)
return;
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->code, f->sizecode);
luaM_freearray(L, f->p, f->sizep);
luaM_freearray(L, f->k, f->sizek);
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
luaM_freearray(L, f->locvars, f->sizelocvars);
luaM_freearray(L, f->upvalues, f->sizeupvalues);
luaM_free(L, f);
}
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->p, f->sp->sizep);
luaM_freearray(L, f->k, f->sp->sizek);
freesharedproto(L, f->sp);
luaM_free(L, f);
}
/*
** Look for n-th local variable at line 'line' in function 'func'.
** Returns NULL if not found.
*/
const char *luaF_getlocalname (const Proto *fp, int local_number, int pc) {
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
int i;
const SharedProto *f = fp->sp;
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
if (pc < f->locvars[i].endpc) { /* is variable active? */
local_number--;
@@ -163,3 +149,20 @@ const char *luaF_getlocalname (const Proto *fp, int local_number, int pc) {
return NULL; /* not found */
}
void luaF_shareproto (Proto *f) {
int i;
if (f == NULL)
return;
makeshared(f);
luaS_share(f->source);
for (i = 0; i < f->sizek; i++) {
if (ttnov(&f->k[i]) == LUA_TSTRING)
luaS_share(tsvalue(&f->k[i]));
}
for (i = 0; i < f->sizeupvalues; i++)
luaS_share(f->upvalues[i].name);
for (i = 0; i < f->sizelocvars; i++)
luaS_share(f->locvars[i].varname);
for (i = 0; i < f->sizep; i++)
luaF_shareproto(f->p[i]);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $
** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -47,7 +47,7 @@ struct UpVal {
#define upisopen(up) ((up)->v != &(up)->u.value)
LUAI_FUNC Proto *luaF_newproto (lua_State *L, SharedProto *sp);
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
@@ -56,6 +56,7 @@ LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
int pc);
LUAI_FUNC void luaF_shareproto (Proto *func);
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp $
** $Id: lgc.c,v 2.215.1.2 2017/08/31 16:15:27 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -65,7 +65,7 @@
*/
#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS))
#define makewhite(g,x) \
(x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g)))
(x->marked = cast_byte((x->marked & maskcolors) | (x->marked & bitmask(SHAREBIT)) | luaC_white(g)))
#define white2gray(x) resetbits(x->marked, WHITEBITS)
#define black2gray(x) resetbit(x->marked, BLACKBIT)
@@ -193,8 +193,7 @@ void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
void luaC_fix (lua_State *L, GCObject *o) {
global_State *g = G(L);
if (g->allgc != o)
return; /* if object is not 1st in 'allgc' list, it is in global short string table */
lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
white2gray(o); /* they will be gray forever */
g->allgc = o->next; /* remove object from 'allgc' list */
o->next = g->fixedgc; /* link it to 'fixedgc' list */
@@ -235,6 +234,8 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
*/
static void reallymarkobject (global_State *g, GCObject *o) {
reentry:
if (isshared(o))
return;
white2gray(o);
switch (o->tt) {
case LUA_TSHRSTR: {
@@ -471,20 +472,6 @@ static lu_mem traversetable (global_State *g, Table *h) {
sizeof(Node) * cast(size_t, allocsizenode(h));
}
static int marksharedproto (global_State *g, SharedProto *f) {
int i;
if (g != f->l_G)
return 0;
markobjectN(g, f->source);
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
markobjectN(g, f->upvalues[i].name);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
markobjectN(g, f->locvars[i].varname);
return sizeof(Instruction) * f->sizecode +
sizeof(int) * f->sizelineinfo +
sizeof(LocVar) * f->sizelocvars +
sizeof(Upvaldesc) * f->sizeupvalues;
}
/*
** Traverse a prototype. (While a prototype is being build, its
@@ -492,20 +479,22 @@ static int marksharedproto (global_State *g, SharedProto *f) {
** NULL, so the use of 'markobjectN')
*/
static int traverseproto (global_State *g, Proto *f) {
int i,nk,np;
if (f->cache && iswhite(f->cache))
f->cache = NULL; /* allow cache to be collected */
if (f->sp == NULL)
return sizeof(Proto);
nk = (f->k == NULL) ? 0 : f->sp->sizek;
np = (f->p == NULL) ? 0 : f->sp->sizep;
for (i = 0; i < nk; i++) /* mark literals */
int i;
markobjectN(g, f->source);
for (i = 0; i < f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < np; i++) /* mark nested protos */
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
markobjectN(g, f->upvalues[i].name);
for (i = 0; i < f->sizep; i++) /* mark nested protos */
markobjectN(g, f->p[i]);
return sizeof(Proto) + sizeof(Proto *) * np +
sizeof(TValue) * nk +
marksharedproto(g, f->sp);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
markobjectN(g, f->locvars[i].varname);
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
sizeof(Proto *) * f->sizep +
sizeof(TValue) * f->sizek +
sizeof(int) * f->sizelineinfo +
sizeof(LocVar) * f->sizelocvars +
sizeof(Upvaldesc) * f->sizeupvalues;
}
@@ -732,8 +721,13 @@ static void freeobj (lua_State *L, GCObject *o) {
}
#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
static void sweepwholelist (lua_State *L, GCObject **p) {
while (*p != NULL) {
GCObject *curr = *p;
*p = curr->next; /* remove 'curr' from list */
freeobj(L, curr); /* erase 'curr' */
}
}
/*
@@ -745,7 +739,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count);
*/
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
global_State *g = G(L);
int ow = otherwhite(g);
int ow = otherwhite(g) | bitmask(SHAREBIT); /* shared object never dead */
int white = luaC_white(g); /* current white */
while (*p != NULL && count-- > 0) {
GCObject *curr = *p;
@@ -755,7 +749,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
freeobj(L, curr); /* erase 'curr' */
}
else { /* change mark to 'white' */
curr->marked = cast_byte((marked & maskcolors) | white);
curr->marked = cast_byte((marked & maskcolors) | (marked & bitmask(SHAREBIT)) |white);
p = &curr->next; /* go to next element */
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -79,6 +79,7 @@
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
#define FINALIZEDBIT 3 /* object has been marked for finalization */
#define SHAREBIT 4 /* object shared from other state */
/* bit 7 is currently used by tests (luaL_checkmemory) */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
@@ -91,9 +92,11 @@
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
#define isshared(x) testbit((x)->marked, SHAREBIT)
#define makeshared(x) l_setbit((x)->marked, SHAREBIT)
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
#define isdead(g,v) isdeadm(otherwhite(g) | bitmask(SHAREBIT), (v)->marked)
#define changewhite(x) ((x)->marked ^= WHITEBITS)
#define gray2black(x) l_setbit((x)->marked, BLACKBIT)
@@ -116,15 +119,15 @@
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v)) && !isshared(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v)) && !isshared(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
(isblack(p) && iswhite(o) && !isshared(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_upvalbarrier(L,uv) ( \

View File

@@ -1,5 +1,5 @@
/*
** $Id: linit.c,v 1.39 2016/12/04 20:17:24 roberto Exp $
** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 2.151 2016/12/20 18:37:00 roberto Exp $
** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -206,11 +206,16 @@ static int aux_close (lua_State *L) {
}
static int f_close (lua_State *L) {
tofile(L); /* make sure argument is an open stream */
return aux_close(L);
}
static int io_close (lua_State *L) {
if (lua_isnone(L, 1)) /* no argument? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
tofile(L); /* make sure argument is an open stream */
return aux_close(L);
return f_close(L);
}
@@ -712,7 +717,7 @@ static const luaL_Reg iolib[] = {
** methods for file handles
*/
static const luaL_Reg flib[] = {
{"close", io_close},
{"close", f_close},
{"flush", f_flush},
{"lines", f_lines},
{"read", f_read},

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $
** $Id: llimits.h,v 1.141.1.1 2017/04/19 17:20:42 roberto Exp $
** Limits, basic types, and some other 'installation-dependent' definitions
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lmathlib.c,v 1.119 2016/12/22 13:08:50 roberto Exp $
** $Id: lmathlib.c,v 1.119.1.1 2017/04/19 17:20:42 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $
** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $
** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp $
** $Id: loadlib.c,v 1.130.1.1 2017/04/19 17:20:42 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**

View File

@@ -1,5 +1,5 @@
/*
** $Id: lobject.c,v 2.113 2016/12/22 13:08:50 roberto Exp $
** $Id: lobject.c,v 2.113.1.1 2017/04/19 17:29:57 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -435,7 +435,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
}
case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
void *p = va_arg(argp, void *);
int l = lua_pointer2str(buff, sizeof(buff), p);
pushstr(L, buff, l);
break;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lobject.h,v 2.117 2016/08/01 19:51:24 roberto Exp $
** $Id: lobject.h,v 2.117.1.1 2017/04/19 17:39:34 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -189,7 +189,7 @@ typedef struct lua_TValue {
#define checkliveness(L,obj) \
lua_longassert(!iscollectable(obj) || \
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)) || isshared(gcvalue(obj)))))
/* Macros to set values */
@@ -305,6 +305,7 @@ typedef struct TString {
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */
unsigned int hash;
size_t id; /* id for short strings */
union {
size_t lnglen; /* length for long strings */
struct TString *hnext; /* linked list for hash table */
@@ -400,7 +401,12 @@ typedef struct LocVar {
int endpc; /* first point where variable is dead */
} LocVar;
typedef struct SharedProto {
/*
** Function Prototypes
*/
typedef struct Proto {
CommonHeader;
lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg;
lu_byte maxstacksize; /* number of registers needed by this function */
@@ -412,23 +418,13 @@ typedef struct SharedProto {
int sizelocvars;
int linedefined; /* debug information */
int lastlinedefined; /* debug information */
void *l_G; /* global state belongs to */
TValue *k; /* constants used by the function */
Instruction *code; /* opcodes */
struct Proto **p; /* functions defined inside the function */
int *lineinfo; /* map from opcodes to source lines (debug information) */
LocVar *locvars; /* information about local variables (debug information) */
Upvaldesc *upvalues; /* upvalue information */
TString *source; /* used for debug information */
} SharedProto;
/*
** Function Prototypes
*/
typedef struct Proto {
CommonHeader;
struct SharedProto *sp;
TValue *k; /* constants used by the function */
struct Proto **p; /* functions defined inside the function */
struct LClosure *cache; /* last-created closure with this prototype */
GCObject *gclist;
} Proto;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $
** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $
** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp $
** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -293,7 +293,8 @@ static int os_date (lua_State *L) {
else
stm = l_localtime(&t, &tmr);
if (stm == NULL) /* invalid date? */
luaL_error(L, "time result cannot be represented in this installation");
return luaL_error(L,
"time result cannot be represented in this installation");
if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
setallfields(L, stm);
@@ -340,7 +341,8 @@ static int os_time (lua_State *L) {
setallfields(L, &ts); /* update fields with normalized values */
}
if (t != (time_t)(l_timet)t || t == (time_t)(-1))
luaL_error(L, "time result cannot be represented in this installation");
return luaL_error(L,
"time result cannot be represented in this installation");
l_pushtime(L, t);
return 1;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.c,v 2.155 2016/08/01 19:51:24 roberto Exp $
** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -79,7 +79,7 @@ static l_noret error_expected (LexState *ls, int token) {
static l_noret errorlimit (FuncState *fs, int limit, const char *what) {
lua_State *L = fs->ls->L;
const char *msg;
int line = fs->f->sp->linedefined;
int line = fs->f->linedefined;
const char *where = (line == 0)
? "main function"
: luaO_pushfstring(L, "function at line %d", line);
@@ -160,15 +160,14 @@ static void checkname (LexState *ls, expdesc *e) {
static int registerlocalvar (LexState *ls, TString *varname) {
FuncState *fs = ls->fs;
Proto *fp = fs->f;
SharedProto *f = fp->sp;
Proto *f = fs->f;
int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables");
while (oldsize < f->sizelocvars)
f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, fp, varname);
luaC_objbarrier(ls->L, f, varname);
return fs->nlocvars++;
}
@@ -196,7 +195,7 @@ static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
static LocVar *getlocvar (FuncState *fs, int i) {
int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
lua_assert(idx < fs->nlocvars);
return &fs->f->sp->locvars[idx];
return &fs->f->locvars[idx];
}
@@ -218,7 +217,7 @@ static void removevars (FuncState *fs, int tolevel) {
static int searchupvalue (FuncState *fs, TString *name) {
int i;
Upvaldesc *up = fs->f->sp->upvalues;
Upvaldesc *up = fs->f->upvalues;
for (i = 0; i < fs->nups; i++) {
if (eqstr(up[i].name, name)) return i;
}
@@ -227,8 +226,7 @@ static int searchupvalue (FuncState *fs, TString *name) {
static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
Proto *fp = fs->f;
SharedProto *f = fp->sp;
Proto *f = fs->f;
int oldsize = f->sizeupvalues;
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
@@ -238,7 +236,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;
luaC_objbarrier(fs->ls->L, fp, name);
luaC_objbarrier(fs->ls->L, f, name);
return fs->nups++;
}
@@ -503,13 +501,13 @@ static Proto *addprototype (LexState *ls) {
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f; /* prototype of current function */
if (fs->np >= f->sp->sizep) {
int oldsize = f->sp->sizep;
luaM_growvector(L, f->p, fs->np, f->sp->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sp->sizep)
if (fs->np >= f->sizep) {
int oldsize = f->sizep;
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sizep)
f->p[oldsize++] = NULL;
}
f->p[fs->np++] = clp = luaF_newproto(L, NULL);
f->p[fs->np++] = clp = luaF_newproto(L);
luaC_objbarrier(L, f, clp);
return clp;
}
@@ -529,7 +527,7 @@ static void codeclosure (LexState *ls, expdesc *v) {
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
SharedProto *f;
Proto *f;
fs->prev = ls->fs; /* linked list of funcstates */
fs->ls = ls;
ls->fs = fs;
@@ -544,7 +542,7 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
fs->nactvar = 0;
fs->firstlocal = ls->dyd->actvar.n;
fs->bl = NULL;
f = fs->f->sp;
f = fs->f;
f->source = ls->source;
f->maxstacksize = 2; /* registers 0/1 are always valid */
enterblock(fs, bl, 0);
@@ -555,21 +553,20 @@ static void close_func (LexState *ls) {
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f;
SharedProto *sp = f->sp;
luaK_ret(fs, 0, 0); /* final return */
leaveblock(fs);
luaM_reallocvector(L, sp->code, sp->sizecode, fs->pc, Instruction);
sp->sizecode = fs->pc;
luaM_reallocvector(L, sp->lineinfo, sp->sizelineinfo, fs->pc, int);
sp->sizelineinfo = fs->pc;
luaM_reallocvector(L, f->k, sp->sizek, fs->nk, TValue);
sp->sizek = fs->nk;
luaM_reallocvector(L, f->p, sp->sizep, fs->np, Proto *);
sp->sizep = fs->np;
luaM_reallocvector(L, sp->locvars, sp->sizelocvars, fs->nlocvars, LocVar);
sp->sizelocvars = fs->nlocvars;
luaM_reallocvector(L, sp->upvalues, sp->sizeupvalues, fs->nups, Upvaldesc);
sp->sizeupvalues = fs->nups;
luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
f->sizecode = fs->pc;
luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
f->sizelineinfo = fs->pc;
luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
f->sizek = fs->nk;
luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
f->sizep = fs->np;
luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
f->sizelocvars = fs->nlocvars;
luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
f->sizeupvalues = fs->nups;
lua_assert(fs->bl == NULL);
ls->fs = fs->prev;
luaC_checkGC(L);
@@ -745,8 +742,8 @@ static void constructor (LexState *ls, expdesc *t) {
} while (testnext(ls, ',') || testnext(ls, ';'));
check_match(ls, '}', '{', line);
lastlistfield(fs, &cc);
SETARG_B(fs->f->sp->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
SETARG_C(fs->f->sp->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
}
/* }====================================================================== */
@@ -756,7 +753,7 @@ static void constructor (LexState *ls, expdesc *t) {
static void parlist (LexState *ls) {
/* parlist -> [ param { ',' param } ] */
FuncState *fs = ls->fs;
SharedProto *f = fs->f->sp;
Proto *f = fs->f;
int nparams = 0;
f->is_vararg = 0;
if (ls->t.token != ')') { /* is 'parlist' not empty? */
@@ -787,7 +784,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
FuncState new_fs;
BlockCnt bl;
new_fs.f = addprototype(ls);
new_fs.f->sp->linedefined = line;
new_fs.f->linedefined = line;
open_func(ls, &new_fs, &bl);
checknext(ls, '(');
if (ismethod) {
@@ -797,7 +794,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
parlist(ls);
checknext(ls, ')');
statlist(ls);
new_fs.f->sp->lastlinedefined = ls->linenumber;
new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line);
codeclosure(ls, e);
close_func(ls);
@@ -963,7 +960,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
}
case TK_DOTS: { /* vararg */
FuncState *fs = ls->fs;
check_condition(ls, fs->f->sp->is_vararg,
check_condition(ls, fs->f->is_vararg,
"cannot use '...' outside a vararg function");
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
break;
@@ -1395,7 +1392,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */
enterblock(fs, &bl, 0); /* must enter block before 'goto' */
gotostat(ls, v.t); /* handle goto/break */
while (testnext(ls, ';')) {} /* skip semicolons */
while (testnext(ls, ';')) {} /* skip colons */
if (block_follow(ls, 0)) { /* 'goto' is the entire block? */
leaveblock(fs);
return; /* and that is it */
@@ -1599,7 +1596,7 @@ static void statement (LexState *ls) {
break;
}
}
lua_assert(ls->fs->f->sp->maxstacksize >= ls->fs->freereg &&
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
leavelevel(ls);
@@ -1616,7 +1613,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl;
expdesc v;
open_func(ls, fs, &bl);
fs->f->sp->is_vararg = 1; /* main function is always declared vararg */
fs->f->is_vararg = 1; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0); /* create and... */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */
@@ -1636,13 +1633,13 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue(L, L->top, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L, NULL);
funcstate.f->sp->source = luaS_new(L, name); /* create and anchor TString */
funcstate.f = cl->p = luaF_newproto(L);
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
lexstate.buff = buff;
lexstate.dyd = dyd;
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
luaX_setinput(L, &lexstate, z, funcstate.f->sp->source, firstchar);
luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
mainfunc(&lexstate, &funcstate);
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $
** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $
** Definitions for Lua code that must come before any other header file
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $
** $Id: lstate.c,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -70,27 +70,6 @@ typedef struct LG {
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
/*
** Compute an initial seed as random as possible. Rely on Address Space
** Layout Randomization (if present) to increase randomness..
*/
#define addbuff(b,p,e) \
{ size_t t = cast(size_t, e); \
memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
static unsigned int makeseed (lua_State *L) {
char buff[4 * sizeof(size_t)];
unsigned int h = luai_makeseed();
int p = 0;
addbuff(buff, p, L); /* heap variable */
addbuff(buff, p, &h); /* local variable */
addbuff(buff, p, luaO_nilobject); /* global variable */
addbuff(buff, p, &lua_newstate); /* public function */
lua_assert(p == sizeof(buff));
return luaS_hash(buff, p, h);
}
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
** invariant (and avoiding underflows in 'totalbytes')
@@ -308,7 +287,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
g->seed = makeseed(L);
g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
g->strt.size = g->strt.nuse = 0;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 2.133 2016/12/22 13:08:50 roberto Exp $
** $Id: lstate.h,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -26,6 +26,24 @@
** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words).
**
** Moreover, there is another set of lists that control gray objects.
** These lists are linked by fields 'gclist'. (All objects that
** can become gray have such a field. The field is not the same
** in all objects, but it always has this name.) Any gray object
** must belong to one of these lists, and all objects in these lists
** must be gray:
**
** 'gray': regular gray objects, still waiting to be visited.
** 'grayagain': objects that must be revisited at the atomic phase.
** That includes
** - black objects got in a write barrier;
** - all kinds of weak tables during propagation phase;
** - all threads.
** 'weak': tables with weak values to be cleared;
** 'ephemeron': ephemeron tables with white->white entries;
** 'allweak': tables with weak keys and/or weak values to be cleared.
** The last three lists are used only during the atomic phase.
*/
@@ -125,7 +143,6 @@ typedef struct global_State {
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
stringtable strt; /* hash table for strings */
TValue l_registry;
unsigned int seed; /* randomized seed for hashes */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $
** $Id: lstring.c,v 2.56.1.1 2017/04/19 17:20:42 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,7 @@
#include <string.h>
#include <time.h>
#include "lua.h"
@@ -20,7 +21,10 @@
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
#include "atomic.h"
static unsigned int STRSEED;
static size_t STRID = 0;
#define MEMERRMSG "not enough memory"
@@ -45,6 +49,26 @@ int luaS_eqlngstr (TString *a, TString *b) {
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
}
int luaS_eqshrstr (TString *a, TString *b) {
lu_byte len = a->shrlen;
lua_assert(b->tt == LUA_TSHRSTR);
int r = len == b->shrlen && (memcmp(getstr(a), getstr(b), len) == 0);
if (r) {
if (a->id < b->id) {
a->id = b->id;
} else {
b->id = a->id;
}
}
return r;
}
void luaS_share (TString *ts) {
if (ts == NULL)
return;
makeshared(ts);
ts->id = ATOM_DEC(&STRID);
}
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ cast(unsigned int, l);
@@ -109,6 +133,15 @@ void luaS_clearcache (global_State *g) {
}
}
static unsigned int make_str_seed(lua_State *L) {
size_t buff[4];
unsigned int h = time(NULL);
buff[0] = cast(size_t, h);
buff[1] = cast(size_t, &STRSEED);
buff[2] = cast(size_t, &make_str_seed);
buff[3] = cast(size_t, L);
return luaS_hash((const char*)buff, sizeof(buff), h);
}
/*
** Initialize the string table and the string cache
@@ -116,6 +149,9 @@ void luaS_clearcache (global_State *g) {
void luaS_init (lua_State *L) {
global_State *g = G(L);
int i, j;
if (STRSEED == 0) {
STRSEED = make_str_seed(L);
}
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
@@ -139,13 +175,14 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
ts = gco2ts(o);
ts->hash = h;
ts->extra = 0;
ts->id = 0;
getstr(ts)[l] = '\0'; /* ending 0 */
return ts;
}
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
TString *ts = createstrobj(L, l, LUA_TLNGSTR, STRSEED);
ts->u.lnglen = l;
return ts;
}
@@ -164,9 +201,10 @@ void luaS_remove (lua_State *L, TString *ts) {
/*
** checks whether short string exists and reuses it or creates a new one
*/
static TString *queryshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, STRSEED);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
@@ -178,13 +216,6 @@ static TString *queryshrstr (lua_State *L, const char *str, size_t l, unsigned i
return ts;
}
}
return NULL;
}
static TString *addshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
TString *ts;
global_State *g = G(L);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) {
luaS_resize(L, g->strt.size * 2);
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
@@ -198,7 +229,6 @@ static TString *addshrstr (lua_State *L, const char *str, size_t l, unsigned int
return ts;
}
static TString *internshrstr (lua_State *L, const char *str, size_t l);
/*
** new string (with explicit length)
@@ -253,217 +283,3 @@ Udata *luaS_newudata (lua_State *L, size_t s) {
return u;
}
/*
* global shared table
*/
#include "rwlock.h"
#include "atomic.h"
#include <stdlib.h>
#define SHRSTR_SLOT 0x10000
#define HASH_NODE(h) ((h) % SHRSTR_SLOT)
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
struct shrmap_slot {
struct rwlock lock;
TString *str;
};
struct shrmap {
struct shrmap_slot h[SHRSTR_SLOT];
int n;
};
static struct shrmap SSM;
LUA_API void
luaS_initshr() {
struct shrmap * s = &SSM;
int i;
for (i=0;i<SHRSTR_SLOT;i++) {
rwlock_init(&s->h[i].lock);
}
}
LUA_API void
luaS_exitshr() {
int i;
for (i=0;i<SHRSTR_SLOT;i++) {
TString *str = SSM.h[i].str;
while (str) {
TString * next = str->u.hnext;
free(str);
str = next;
}
}
}
static TString *
query_string(unsigned int h, const char *str, lu_byte l) {
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts->hash == h &&
ts->shrlen == l &&
memcmp(str, ts+1, l) == 0) {
break;
}
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
return ts;
}
static TString *
query_ptr(TString *t) {
unsigned int h = t->hash;
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts == t)
break;
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
return ts;
}
static TString *
new_string(unsigned int h, const char *str, lu_byte l) {
size_t sz = sizelstring(l);
TString *ts = malloc(sz);
memset(ts, 0, sz);
ts->tt = LUA_TSHRSTR;
ts->hash = h;
ts->shrlen = l;
memcpy(ts+1, str, l);
return ts;
}
static TString *
add_string(unsigned int h, const char *str, lu_byte l) {
TString * tmp = new_string(h, str, l);
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_wlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts->hash == h &&
ts->shrlen == l &&
memcmp(str, ts+1, l) == 0) {
break;
}
ts = ts->u.hnext;
}
if (ts == NULL) {
ts = tmp;
ts->u.hnext = s->str;
s->str = ts;
tmp = NULL;
}
rwlock_wunlock(&s->lock);
if (tmp) {
// string is create by other thread, so free tmp
free(tmp);
}
return ts;
}
static TString *
internshrstr (lua_State *L, const char *str, size_t l) {
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
unsigned int h0;
// lookup global state of this L first
ts = queryshrstr (L, str, l, h);
if (ts)
return ts;
// lookup SSM again
h0 = luaS_hash(str, l, 0);
ts = query_string(h0, str, l);
if (ts)
return ts;
// If SSM.n greate than 0, add it to SSM
if (SSM.n > 0) {
ATOM_DEC(&SSM.n);
return add_string(h0, str, l);
}
// Else add it to global state (local)
return addshrstr (L, str, l, h);
}
LUA_API void
luaS_expandshr(int n) {
ATOM_ADD(&SSM.n, n);
}
LUAI_FUNC TString *
luaS_clonestring(lua_State *L, TString *ts) {
unsigned int h;
int l;
const char * str = getaddrstr(ts);
global_State *g = G(L);
TString *result;
if (ts->tt == LUA_TLNGSTR)
return luaS_newlstr(L, str, ts->u.lnglen);
// look up global state of this L first
l = ts->shrlen;
h = luaS_hash(str, l, g->seed);
result = queryshrstr (L, str, l, h);
if (result)
return result;
// look up SSM by ptr
result = query_ptr(ts);
if (result)
return result;
h = luaS_hash(str, l, 0);
result = query_string(h, str, l);
if (result)
return result;
// ts is not in SSM, so recalc hash, and add it to SSM
return add_string(h, str, l);
}
struct slotinfo {
int len;
int size;
};
static void
getslot(struct shrmap_slot *s, struct slotinfo *info) {
memset(info, 0, sizeof(*info));
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
++info->len;
info->size += sizelstring(ts->shrlen);
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
}
LUA_API int
luaS_shrinfo(lua_State *L) {
struct slotinfo total;
struct slotinfo tmp;
memset(&total, 0, sizeof(total));
int i;
int len = 0;
for (i=0;i<SHRSTR_SLOT;i++) {
struct shrmap_slot *s = &SSM.h[i];
getslot(s, &tmp);
len += tmp.len;
if (tmp.len > total.len) {
total.len = tmp.len;
}
total.size += tmp.size;
}
lua_pushinteger(L, len);
lua_pushinteger(L, total.size);
lua_pushinteger(L, total.len);
lua_pushinteger(L, SSM.n);
return 4;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $
** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -28,14 +28,15 @@
/*
** equality for short strings, which are always internalized
** equality for short strings, compare id first
*/
#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b))
#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b) || \
( ((a)->id == (b)->id) ? ((a)->id != 0) : ((a)->hash == (b)->hash && luaS_eqshrstr(a,b)) ) )
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC int luaS_eqshrstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC void luaS_clearcache (global_State *g);
LUAI_FUNC void luaS_init (lua_State *L);
@@ -44,13 +45,7 @@ LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
LUAI_FUNC void luaS_share(TString *ts);
#define ENABLE_SHORT_STRING_TABLE
LUA_API void luaS_initshr();
LUA_API void luaS_exitshr();
LUA_API void luaS_expandshr(int n);
LUAI_FUNC TString *luaS_clonestring(lua_State *L, TString *);
LUA_API int luaS_shrinfo(lua_State *L);
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $
** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -879,7 +879,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
buff[i] = toupper(uchar(buff[i]));
}
else if (fmt[SIZELENMOD] != 'a')
luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
return n;
}
@@ -1199,8 +1199,8 @@ static int getnum (const char **fmt, int df) {
static int getnumlimit (Header *h, const char **fmt, int df) {
int sz = getnum(fmt, df);
if (sz > MAXINTSIZE || sz <= 0)
luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
sz, MAXINTSIZE);
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
sz, MAXINTSIZE);
return sz;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltable.c,v 2.118 2016/11/07 12:38:35 roberto Exp $
** $Id: ltable.c,v 2.118.1.4 2018/06/08 16:22:51 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -223,7 +223,9 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
unsigned int na = 0; /* number of elements to go to array part */
unsigned int optimal = 0; /* optimal size for array part */
/* loop while keys can fill more than half of total size */
for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) {
for (i = 0, twotoi = 1;
twotoi > 0 && *pna > twotoi / 2;
i++, twotoi *= 2) {
if (nums[i] > 0) {
a += nums[i];
if (a > twotoi/2) { /* more than half elements present? */
@@ -330,17 +332,34 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
}
typedef struct {
Table *t;
unsigned int nhsize;
} AuxsetnodeT;
static void auxsetnode (lua_State *L, void *ud) {
AuxsetnodeT *asn = cast(AuxsetnodeT *, ud);
setnodevector(L, asn->t, asn->nhsize);
}
void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int nhsize) {
unsigned int i;
int j;
AuxsetnodeT asn;
unsigned int oldasize = t->sizearray;
int oldhsize = allocsizenode(t);
Node *nold = t->node; /* save old hash ... */
if (nasize > oldasize) /* array part must grow? */
setarrayvector(L, t, nasize);
/* create new hash part with appropriate size */
setnodevector(L, t, nhsize);
asn.t = t; asn.nhsize = nhsize;
if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */
setarrayvector(L, t, oldasize); /* array back to its original size */
luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */
}
if (nasize < oldasize) { /* array part must shrink? */
t->sizearray = nasize;
/* re-insert elements from vanishing slice */
@@ -589,7 +608,10 @@ const TValue *luaH_get (Table *t, const TValue *key) {
** barrier and invalidate the TM cache.
*/
TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
const TValue *p = luaH_get(t, key);
const TValue *p;
if(isshared(t))
luaG_runerror(L,"attempt to change a shared table");
p = luaH_get(t, key);
if (p != luaO_nilobject)
return cast(TValue *, p);
else return luaH_newkey(L, t, key);
@@ -610,13 +632,13 @@ void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
}
static int unbound_search (Table *t, unsigned int j) {
unsigned int i = j; /* i is zero or a present index */
static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) {
lua_Unsigned i = j; /* i is zero or a present index */
j++;
/* find 'i' and 'j' such that i is present and j is not */
while (!ttisnil(luaH_getint(t, j))) {
i = j;
if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */
if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */
/* table was built with bad purposes: resort to linear search */
i = 1;
while (!ttisnil(luaH_getint(t, i))) i++;
@@ -626,7 +648,7 @@ static int unbound_search (Table *t, unsigned int j) {
}
/* now do a binary search between them */
while (j - i > 1) {
unsigned int m = (i+j)/2;
lua_Unsigned m = (i+j)/2;
if (ttisnil(luaH_getint(t, m))) j = m;
else i = m;
}
@@ -638,7 +660,7 @@ static int unbound_search (Table *t, unsigned int j) {
** Try to find a boundary in table 't'. A 'boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
int luaH_getn (Table *t) {
lua_Unsigned luaH_getn (Table *t) {
unsigned int j = t->sizearray;
if (j > 0 && ttisnil(&t->array[j - 1])) {
/* there is a boundary in the array part: (binary) search for it */

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp $
** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -54,7 +54,7 @@ LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
LUAI_FUNC int luaH_getn (Table *t);
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
#if defined(LUA_DEBUG)

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 roberto Exp $
** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.c,v 1.230 2017/01/12 17:14:26 roberto Exp $
** $Id: lua.c,v 1.230.1.1 2017/04/19 17:29:57 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -18,7 +18,6 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lstring.h"
@@ -139,7 +138,7 @@ static void print_usage (const char *badoption) {
"Available options are:\n"
" -e stat execute string 'stat'\n"
" -i enter interactive mode after executing 'script'\n"
" -l name require library 'name'\n"
" -l name require library 'name' into global 'name'\n"
" -v show version information\n"
" -E ignore environment variables\n"
" -- stop handling options\n"
@@ -596,9 +595,7 @@ static int pmain (lua_State *L) {
int main (int argc, char **argv) {
int status, result;
lua_State *L;
luaS_initshr(); /* init global short string table */
L = luaL_newstate(); /* create state */
lua_State *L = luaL_newstate(); /* create state */
if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
@@ -610,7 +607,6 @@ int main (int argc, char **argv) {
result = lua_toboolean(L, -1); /* get result */
report(L, status);
lua_close(L);
luaS_exitshr();
return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.332 2016/12/22 15:51:20 roberto Exp $
** $Id: lua.h,v 1.332.1.2 2018/06/13 16:58:17 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "4"
#define LUA_VERSION_RELEASE "5"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2017 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2018 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -234,6 +234,10 @@ LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
LUA_API void (lua_clonefunction) (lua_State *L, const void * fp);
LUA_API void (lua_sharefunction) (lua_State *L, int index);
LUA_API void (lua_sharestring) (lua_State *L, int index);
LUA_API void (lua_clonetable) (lua_State *L, const void * t);
/*
** get functions (Lua -> stack)
@@ -282,8 +286,6 @@ LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
LUA_API void (lua_clonefunction) (lua_State *L, const void *eL);
/*
** coroutine functions
@@ -467,7 +469,7 @@ LUA_API void (lua_checksig_)(lua_State *L);
#define lua_checksig(L) if (skynet_sig_L) { lua_checksig_(L); }
/******************************************************************************
* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
* Copyright (C) 1994-2018 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

View File

@@ -1,5 +1,5 @@
/*
** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $
** Lua compiler (saves bytecodes to files; also lists bytecodes)
** See Copyright Notice in lua.h
*/
@@ -21,7 +21,6 @@
#include "lobject.h"
#include "lstate.h"
#include "lundump.h"
#include "lstring.h"
static void PrintFunction(const Proto* f, int full);
#define luaU_print PrintFunction
@@ -150,9 +149,9 @@ static const Proto* combine(lua_State* L, int n)
for (i=0; i<n; i++)
{
f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sp->sizeupvalues>0) f->p[i]->sp->upvalues[0].instack=0;
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
}
f->sp->sizelineinfo=0;
f->sizelineinfo=0;
return f;
}
}
@@ -196,7 +195,6 @@ int main(int argc, char* argv[])
int i=doargs(argc,argv);
argc-=i; argv+=i;
if (argc<=0) usage("no input files given");
luaS_initshr();
L=luaL_newstate();
if (L==NULL) fatal("cannot create state: not enough memory");
lua_pushcfunction(L,&pmain);
@@ -208,7 +206,7 @@ int main(int argc, char* argv[])
}
/*
** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
@@ -284,13 +282,13 @@ static void PrintConstant(const Proto* f, int i)
}
}
#define UPVALNAME(x) ((f->sp->upvalues[x].name) ? getstr(f->sp->upvalues[x].name) : "-")
#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
#define MYK(x) (-1-(x))
static void PrintCode(const Proto* f)
{
const Instruction* code=f->sp->code;
int pc,n=f->sp->sizecode;
const Instruction* code=f->code;
int pc,n=f->sizecode;
for (pc=0; pc<n; pc++)
{
Instruction i=code[pc];
@@ -350,6 +348,7 @@ static void PrintCode(const Proto* f)
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_MOD:
case OP_POW:
case OP_DIV:
case OP_IDIV:
@@ -394,7 +393,7 @@ static void PrintCode(const Proto* f)
#define SS(x) ((x==1)?"":"s")
#define S(x) (int)(x),SS(x)
static void PrintHeader(const SharedProto* f)
static void PrintHeader(const Proto* f)
{
const char* s=f->source ? getstr(f->source) : "=?";
if (*s=='@' || *s=='=')
@@ -416,9 +415,8 @@ static void PrintHeader(const SharedProto* f)
static void PrintDebug(const Proto* f)
{
const SharedProto *sp = f->sp;
int i,n;
n=sp->sizek;
n=f->sizek;
printf("constants (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
@@ -426,26 +424,26 @@ static void PrintDebug(const Proto* f)
PrintConstant(f,i);
printf("\n");
}
n=sp->sizelocvars;
n=f->sizelocvars;
printf("locals (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
printf("\t%d\t%s\t%d\t%d\n",
i,getstr(sp->locvars[i].varname),sp->locvars[i].startpc+1,sp->locvars[i].endpc+1);
i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
}
n=f->sp->sizeupvalues;
n=f->sizeupvalues;
printf("upvalues (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
printf("\t%d\t%s\t%d\t%d\n",
i,UPVALNAME(i),sp->upvalues[i].instack,sp->upvalues[i].idx);
i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
}
}
static void PrintFunction(const Proto* f, int full)
{
int i,n=f->sp->sizep;
PrintHeader(f->sp);
int i,n=f->sizep;
PrintHeader(f);
PrintCode(f);
if (full) PrintDebug(f);
for (i=0; i<n; i++) PrintFunction(f->p[i],full);

View File

@@ -1,5 +1,5 @@
/*
** $Id: luaconf.h,v 1.259 2016/12/22 13:08:50 roberto Exp $
** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -620,6 +620,13 @@
#endif
/*
@@ lua_pointer2str converts a pointer to a readable string in a
** non-specified way.
*/
#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p)
/*
@@ lua_number2strx converts a float to an hexadecimal numeric string.
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.

View File

@@ -1,5 +1,5 @@
/*
** $Id: lualib.h,v 1.45 2017/01/12 17:14:26 roberto Exp $
** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@@ -49,6 +49,7 @@ LUAMOD_API int (luaopen_package) (lua_State *L);
#define LUA_CACHELIB
LUAMOD_API int (luaopen_cache) (lua_State *L);
LUALIB_API void (luaL_initcodecache) (void);
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $
** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -104,7 +104,7 @@ static TString *LoadString (LoadState *S) {
}
static void LoadCode (LoadState *S, SharedProto *f) {
static void LoadCode (LoadState *S, Proto *f) {
int n = LoadInt(S);
f->code = luaM_newvector(S->L, n, Instruction);
f->sizecode = n;
@@ -119,7 +119,7 @@ static void LoadConstants (LoadState *S, Proto *f) {
int i;
int n = LoadInt(S);
f->k = luaM_newvector(S->L, n, TValue);
f->sp->sizek = n;
f->sizek = n;
for (i = 0; i < n; i++)
setnilvalue(&f->k[i]);
for (i = 0; i < n; i++) {
@@ -153,17 +153,17 @@ static void LoadProtos (LoadState *S, Proto *f) {
int i;
int n = LoadInt(S);
f->p = luaM_newvector(S->L, n, Proto *);
f->sp->sizep = n;
f->sizep = n;
for (i = 0; i < n; i++)
f->p[i] = NULL;
for (i = 0; i < n; i++) {
f->p[i] = luaF_newproto(S->L, NULL);
LoadFunction(S, f->p[i], f->sp->source);
f->p[i] = luaF_newproto(S->L);
LoadFunction(S, f->p[i], f->source);
}
}
static void LoadUpvalues (LoadState *S, SharedProto *f) {
static void LoadUpvalues (LoadState *S, Proto *f) {
int i, n;
n = LoadInt(S);
f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
@@ -177,7 +177,7 @@ static void LoadUpvalues (LoadState *S, SharedProto *f) {
}
static void LoadDebug (LoadState *S, SharedProto *f) {
static void LoadDebug (LoadState *S, Proto *f) {
int i, n;
n = LoadInt(S);
f->lineinfo = luaM_newvector(S->L, n, int);
@@ -199,8 +199,7 @@ static void LoadDebug (LoadState *S, SharedProto *f) {
}
static void LoadFunction (LoadState *S, Proto *fp, TString *psource) {
SharedProto *f = fp->sp;
static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
f->source = LoadString(S);
if (f->source == NULL) /* no source in dump? */
f->source = psource; /* reuse parent's source */
@@ -210,9 +209,9 @@ static void LoadFunction (LoadState *S, Proto *fp, TString *psource) {
f->is_vararg = LoadByte(S);
f->maxstacksize = LoadByte(S);
LoadCode(S, f);
LoadConstants(S, fp);
LoadConstants(S, f);
LoadUpvalues(S, f);
LoadProtos(S, fp);
LoadProtos(S, f);
LoadDebug(S, f);
}
@@ -271,9 +270,9 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
cl = luaF_newLclosure(L, LoadByte(&S));
setclLvalue(L, L->top, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L, NULL);
cl->p = luaF_newproto(L);
LoadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
luai_verifycode(L, buff, cl->p);
return cl;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $
** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $
** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
@@ -171,7 +171,7 @@ static int byteoffset (lua_State *L) {
}
else {
if (iscont(s + posi))
luaL_error(L, "initial position is a continuation byte");
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -217,6 +217,8 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
const TValue *tm; /* '__newindex' metamethod */
if (slot != NULL) { /* is 't' a table? */
Table *h = hvalue(t); /* save 't' table */
if (isshared(h))
luaG_typeerror(L, t, "change");
lua_assert(ttisnil(slot)); /* old value must be nil */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */
@@ -612,27 +614,6 @@ lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
}
/*
** check whether cached closure in prototype 'p' may be reused, that is,
** whether there is a cached closure with the same upvalues needed by
** new closure to be created.
*/
static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
LClosure *c = p->cache;
if (c != NULL) { /* is there a cached closure? */
int nup = p->sp->sizeupvalues;
Upvaldesc *uv = p->sp->upvalues;
int i;
for (i = 0; i < nup; i++) { /* check whether it has right upvalues */
TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v;
if (c->upvals[i]->v != v)
return NULL; /* wrong upvalue; cannot reuse closure */
}
}
return c; /* return cached closure (or NULL if no cached closure) */
}
/*
** create a new Lua closure, push it in the stack, and initialize
** its upvalues. Note that the closure is not cached if prototype is
@@ -641,8 +622,8 @@ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) {
*/
static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
StkId ra) {
int nup = p->sp->sizeupvalues;
Upvaldesc *uv = p->sp->upvalues;
int nup = p->sizeupvalues;
Upvaldesc *uv = p->upvalues;
int i;
LClosure *ncl = luaF_newLclosure(L, nup);
ncl->p = p;
@@ -655,8 +636,6 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
ncl->upvals[i]->refcount++;
/* new closure is white, so we do not need a barrier here */
}
if (!isblack(p)) /* cache will not break GC invariant? */
p->cache = ncl; /* save it on cache for reuse */
}
@@ -1169,10 +1148,10 @@ void luaV_execute (lua_State *L) {
StkId nfunc = nci->func; /* called function */
StkId ofunc = oci->func; /* caller function */
/* last stack slot filled by 'precall' */
StkId lim = nci->u.l.base + getproto(nfunc)->sp->numparams;
StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
int aux;
/* close all upvalues from previous call */
if (cl->p->sp->sizep > 0) luaF_close(L, oci->u.l.base);
if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
/* move new frame into old one */
for (aux = 0; nfunc + aux < lim; aux++)
setobjs2s(L, ofunc + aux, nfunc + aux);
@@ -1181,14 +1160,14 @@ void luaV_execute (lua_State *L) {
oci->u.l.savedpc = nci->u.l.savedpc;
oci->callstatus |= CIST_TAIL; /* function was tail called */
ci = L->ci = oci; /* remove new frame */
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->sp->maxstacksize);
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
if (cl->p->sp->sizep > 0) luaF_close(L, base);
if (cl->p->sizep > 0) luaF_close(L, base);
b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
return; /* external invocation: return */
@@ -1299,18 +1278,14 @@ void luaV_execute (lua_State *L) {
}
vmcase(OP_CLOSURE) {
Proto *p = cl->p->p[GETARG_Bx(i)];
LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */
if (ncl == NULL) /* no match? */
pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
else
setclLvalue(L, ra, ncl); /* push cashed closure */
pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
int b = GETARG_B(i) - 1; /* required results */
int j;
int n = cast_int(base - ci->func) - cl->p->sp->numparams - 1;
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
if (n < 0) /* less arguments than parameters? */
n = 0; /* no vararg arguments */
if (b < 0) { /* B == 0? */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp $
** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -81,7 +81,7 @@
(!ttistable(t) \
? (slot = NULL, 0) \
: (slot = f(hvalue(t), k), \
ttisnil(slot) ? 0 \
(ttisnil(slot) || isshared(hvalue(t))) ? 0 \
: (luaC_barrierback(L, hvalue(t), v), \
setobj2t(L, cast(TValue *,slot), v), \
1)))

View File

@@ -1,5 +1,5 @@
/*
** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $
** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $
** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/

View File

@@ -1,3 +1,35 @@
v1.3.0 (2019-11-19)
-----------
* Improve mysql driver (@yxt945)
* Improve cluster
* Improve lua shared proto (@hongling0)
* Improve socket.write
* Add lua sharetable
* Add https support (@lvzixun)
* Add websocket support (@lvzixun)
* Fix bug in dns
* Fix some memory leaks
* jemalloc update to 5.2.1
v1.2.0 (2018-11-6)
-----------
* Improve cluster support
* Improve mongodb driver
* Improve redis driver
* Improve socket concurrent write
* Improve socket channel
* Improve service gate
* Improve udp support
* Add skynet.ignoreret
* Add skynet.trace
* Add skynet.context
* Improve skynet.wait/wakeup
* Add socket.netstat
* Add socketchannel.overload
* Fix memory leak for dead service
* lua update to 5.3.5
* jemalloc update to 5.1.0
v1.1.0 (2017-10-31)
-----------
* add socket.disconnected()

View File

@@ -17,7 +17,13 @@ LUA_INC ?= 3rd/lua
$(LUA_STATICLIB) :
cd 3rd/lua && $(MAKE) CC='$(CC) -std=gnu99' $(PLAT)
# jemalloc
# https : turn on TLS_MODULE to add https support
# TLS_MODULE=ltls
TLS_LIB=
TLS_INC=
# jemalloc
JEMALLOC_STATICLIB := 3rd/jemalloc/lib/libjemalloc_pic.a
JEMALLOC_INC := 3rd/jemalloc/include/jemalloc
@@ -35,7 +41,7 @@ $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
git submodule update --init
3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh
cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --disable-valgrind
cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --enable-prof
jemalloc : $(MALLOC_STATICLIB)
@@ -47,7 +53,7 @@ update3rd :
CSERVICE = snlua logger gate harbor
LUA_CLIB = skynet \
client \
bson md5 sproto lpeg
bson md5 sproto lpeg $(TLS_MODULE)
LUA_CLIB_SKYNET = \
lua-skynet.c lua-seri.c \
@@ -61,9 +67,9 @@ LUA_CLIB_SKYNET = \
lua-crypt.c lsha1.c \
lua-sharedata.c \
lua-stm.c \
lua-mysqlaux.c \
lua-debugchannel.c \
lua-datasheet.c \
lua-sharetable.c \
\
SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \
@@ -107,6 +113,9 @@ $(LUA_CLIB_PATH)/client.so : lualib-src/lua-clientsocket.c lualib-src/lua-crypt.
$(LUA_CLIB_PATH)/sproto.so : lualib-src/sproto/sproto.c lualib-src/sproto/lsproto.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Ilualib-src/sproto $^ -o $@
$(LUA_CLIB_PATH)/ltls.so : lualib-src/ltls.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src -L$(TLS_LIB) -I$(TLS_INC) $^ -o $@ -lssl
$(LUA_CLIB_PATH)/lpeg.so : 3rd/lpeg/lpcap.c 3rd/lpeg/lpcode.c 3rd/lpeg/lpprint.c 3rd/lpeg/lptree.c 3rd/lpeg/lpvm.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -I3rd/lpeg $^ -o $@

View File

@@ -1,6 +1,6 @@
## Skynet
## ![skynet logo](https://github.com/cloudwu/skynet/wiki/image/skynet_metro.jpg)
Skynet is a lightweight online game framework, and it can be used in many other fields.
Skynet is a lightweight online game framework which can be used in many other fields.
## Build
@@ -12,7 +12,7 @@ cd skynet
make 'PLATFORM' # PLATFORM can be linux, macosx, freebsd now
```
Or you can:
Or:
```
export PLAT=linux
@@ -32,11 +32,11 @@ Run these in different consoles:
## About Lua version
Skynet now uses a modified version of lua 5.3.4 ( https://github.com/ejoy/lua/tree/skynet ) for multiple lua states.
Skynet now uses a modified version of lua 5.3.5 ( https://github.com/ejoy/lua/tree/skynet ) for multiple lua states.
You can also use official Lua versions, just edit the Makefile by yourself.
Official Lua versions can also be used as long as the Makefile is edited.
## How To Use (Sorry, Only in Chinese now)
## How To Use (Sorry, currently only available in Chinese)
* Read Wiki for documents https://github.com/cloudwu/skynet/wiki
* The FAQ in wiki https://github.com/cloudwu/skynet/wiki/FAQ

View File

@@ -1,5 +1,4 @@
local skynet = require "skynet"
local netpack = require "skynet.netpack"
local socket = require "skynet.socket"
local sproto = require "sproto"
local sprotoloader = require "sprotoloader"
@@ -50,7 +49,10 @@ skynet.register_protocol {
unpack = function (msg, sz)
return host:dispatch(msg, sz)
end,
dispatch = function (_, _, type, ...)
dispatch = function (fd, _, type, ...)
assert(fd == client_fd) -- You can use fd to reply message
skynet.ignoreret() -- session is fd, don't call skynet.ret
skynet.trace()
if type == "REQUEST" then
local ok, result = pcall(request, ...)
if ok then
@@ -92,6 +94,7 @@ end
skynet.start(function()
skynet.dispatch("lua", function(_,_, command, ...)
skynet.trace()
local f = CMD[command]
skynet.ret(skynet.pack(f(...)))
end)

View File

@@ -2,22 +2,30 @@ local skynet = require "skynet"
local cluster = require "skynet.cluster"
skynet.start(function()
-- query name "sdb" of cluster db.
local sdb = cluster.query("db", "sdb")
print("db.sbd=",sdb)
local proxy = cluster.proxy("db", sdb)
local proxy = cluster.proxy "db@sdb" -- cluster.proxy("db", "@sdb")
local largekey = string.rep("X", 128*1024)
local largevalue = string.rep("R", 100 * 1024)
print(skynet.call(proxy, "lua", "SET", largekey, largevalue))
skynet.call(proxy, "lua", "SET", largekey, largevalue)
local v = skynet.call(proxy, "lua", "GET", largekey)
assert(largevalue == v)
skynet.send(proxy, "lua", "PING", "proxy")
print(cluster.call("db", sdb, "GET", "a"))
print(cluster.call("db2", sdb, "GET", "b"))
cluster.send("db2", sdb, "PING", "db2:longstring" .. largevalue)
skynet.fork(function()
skynet.trace("cluster")
print(cluster.call("db", "@sdb", "GET", "a"))
print(cluster.call("db2", "@sdb", "GET", "b"))
cluster.send("db2", "@sdb", "PING", "db2:longstring" .. largevalue)
end)
-- test snax service
local pingserver = cluster.snax("db", "pingserver")
skynet.timeout(300,function()
cluster.reload {
db = false, -- db is down
db3 = "127.0.0.1:2529"
}
print(pcall(cluster.call, "db", "@sdb", "GET", "a")) -- db is down
end)
cluster.reload { __nowaiting = false }
local pingserver = cluster.snax("db3", "pingserver")
print(pingserver.req.ping "hello")
end)

View File

@@ -1,2 +1,4 @@
__nowaiting = true -- If you turn this flag off, cluster.call would block when node name is absent
db = "127.0.0.1:2528"
db2 = "127.0.0.1:2529"

11
examples/config.mongodb Normal file
View File

@@ -0,0 +1,11 @@
root = "./"
thread = 8
logger = nil
harbor = 0
start = "main_mongodb" -- main script
bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
lualoader = "lualib/loader.lua"
snax = root.."examples/?.lua;"..root.."test/?.lua"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

12
examples/main_mongodb.lua Normal file
View File

@@ -0,0 +1,12 @@
local skynet = require "skynet"
skynet.start(function()
print("Main Server start")
local console = skynet.newservice(
"testmongodb", "127.0.0.1", 27017, "testdb", "test", "test"
)
print("Main Server exit")
skynet.exit()
end)

View File

@@ -33,5 +33,6 @@ skynet.start(function()
error(string.format("Unknown command %s", tostring(cmd)))
end
end)
-- skynet.traceproto("lua", false) -- true off tracelog
skynet.register "SIMPLEDB"
end)

View File

@@ -6,26 +6,64 @@ local urllib = require "http.url"
local table = table
local string = string
local mode = ...
local mode, protocol = ...
protocol = protocol or "http"
if mode == "agent" then
local function response(id, ...)
local ok, err = httpd.write_response(sockethelper.writefunc(id), ...)
local function response(id, write, ...)
local ok, err = httpd.write_response(write, ...)
if not ok then
-- if err == sockethelper.socket_error , that means socket closed.
skynet.error(string.format("fd = %d, %s", id, err))
end
end
local SSLCTX_SERVER = nil
local function gen_interface(protocol, fd)
if protocol == "http" then
return {
init = nil,
close = nil,
read = sockethelper.readfunc(fd),
write = sockethelper.writefunc(fd),
}
elseif protocol == "https" then
local tls = require "http.tlshelper"
if not SSLCTX_SERVER then
SSLCTX_SERVER = tls.newctx()
-- gen cert and key
-- openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-cert.pem
local certfile = skynet.getenv("certfile") or "./server-cert.pem"
local keyfile = skynet.getenv("keyfile") or "./server-key.pem"
print(certfile, keyfile)
SSLCTX_SERVER:set_cert(certfile, keyfile)
end
local tls_ctx = tls.newtls("server", SSLCTX_SERVER)
return {
init = tls.init_responsefunc(fd, tls_ctx),
close = tls.closefunc(tls_ctx),
read = tls.readfunc(fd, tls_ctx),
write = tls.writefunc(fd, tls_ctx),
}
else
error(string.format("Invalid protocol: %s", protocol))
end
end
skynet.start(function()
skynet.dispatch("lua", function (_,_,id)
socket.start(id)
local interface = gen_interface(protocol, id)
if interface.init then
interface.init()
end
-- limit request body size to 8192 (you can pass nil to unlimit)
local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id), 8192)
local code, url, method, header, body = httpd.read_request(interface.read, 8192)
if code then
if code ~= 200 then
response(id, code)
response(id, interface.write, code)
else
local tmp = {}
if header.host then
@@ -44,7 +82,7 @@ skynet.start(function()
table.insert(tmp, string.format("%s = %s",k,v))
end
table.insert(tmp, "-----body----\n" .. body)
response(id, code, table.concat(tmp,"\n"))
response(id, interface.write, code, table.concat(tmp,"\n"))
end
else
if url == sockethelper.socket_error then
@@ -54,6 +92,9 @@ skynet.start(function()
end
end
socket.close(id)
if interface.close then
interface.close()
end
end)
end)
@@ -61,12 +102,13 @@ else
skynet.start(function()
local agent = {}
local protocol = "http"
for i= 1, 20 do
agent[i] = skynet.newservice(SERVICE_NAME, "agent")
agent[i] = skynet.newservice(SERVICE_NAME, "agent", protocol)
end
local balance = 1
local id = socket.listen("0.0.0.0", 8001)
skynet.error("Listen web port 8001")
skynet.error(string.format("Listen web port 8001 protocol:%s", protocol))
socket.start(id , function(id, addr)
skynet.error(string.format("%s connected, pass it to agent :%08x", addr, agent[balance]))
skynet.send(agent[balance], "lua", id)

94
examples/simplewebsocket.lua Executable file
View File

@@ -0,0 +1,94 @@
local skynet = require "skynet"
local socket = require "skynet.socket"
local service = require "skynet.service"
local websocket = require "http.websocket"
local handle = {}
local MODE = ...
if MODE == "agent" then
function handle.connect(id)
print("ws connect from: " .. tostring(id))
end
function handle.handshake(id, header, url)
local addr = websocket.addrinfo(id)
print("ws handshake from: " .. tostring(id), "url", url, "addr:", addr)
print("----header-----")
for k,v in pairs(header) do
print(k,v)
end
print("--------------")
end
function handle.message(id, msg)
websocket.write(id, msg)
end
function handle.ping(id)
print("ws ping from: " .. tostring(id) .. "\n")
end
function handle.pong(id)
print("ws pong from: " .. tostring(id))
end
function handle.close(id, code, reason)
print("ws close from: " .. tostring(id), code, reason)
end
function handle.error(id)
print("ws error from: " .. tostring(id))
end
skynet.start(function ()
skynet.dispatch("lua", function (_,_, id, protocol, addr)
local ok, err = websocket.accept(id, handle, protocol, addr)
if not ok then
print(err)
end
end)
end)
else
local function simple_echo_client_service(protocol)
local skynet = require "skynet"
local websocket = require "http.websocket"
local url = string.format("%s://127.0.0.1:9948/test_websocket", protocol)
local ws_id = websocket.connect(url)
while true do
local msg = "hello world!"
websocket.write(ws_id, msg)
print(">: " .. msg)
local resp, close_reason = websocket.read(ws_id)
print("<: " .. (resp and resp or "[Close] " .. close_reason))
if not resp then
print("echo server close.")
break
end
websocket.ping(ws_id)
skynet.sleep(100)
end
end
skynet.start(function ()
local agent = {}
for i= 1, 20 do
agent[i] = skynet.newservice(SERVICE_NAME, "agent")
end
local balance = 1
local protocol = "ws"
local id = socket.listen("0.0.0.0", 9948)
skynet.error(string.format("Listen websocket port 9948 protocol:%s", protocol))
socket.start(id, function(id, addr)
print(string.format("accept client socket_id: %s addr:%s", id, addr))
skynet.send(agent[balance], "lua", id, protocol, addr)
balance = balance + 1
if balance > #agent then
balance = 1
end
end)
-- test echo client
service.new("websocket_echo_client", simple_echo_client_service, protocol)
end)
end

View File

@@ -1,6 +1,7 @@
local skynet = require "skynet"
require "skynet.manager"
-- register protocol text before skynet.start would be better.
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
@@ -21,5 +22,4 @@ skynet.register_protocol {
}
skynet.start(function()
skynet.register ".logger"
end)

414
lualib-src/ltls.c Normal file
View File

@@ -0,0 +1,414 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/dh.h>
#include <openssl/ssl.h>
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <lua.h>
#include <lauxlib.h>
static bool TLS_IS_INIT = false;
struct tls_context {
SSL* ssl;
BIO* in_bio;
BIO* out_bio;
bool is_server;
bool is_close;
};
struct ssl_ctx {
SSL_CTX* ctx;
};
// static int
// _ssl_verify_peer(int ok, X509_STORE_CTX* ctx) {
// return 1;
// }
static void
_init_bio(lua_State* L, struct tls_context* tls_p, struct ssl_ctx* ctx_p) {
tls_p->ssl = SSL_new(ctx_p->ctx);
if(!tls_p->ssl) {
luaL_error(L, "SSL_new faild");
}
tls_p->in_bio = BIO_new(BIO_s_mem());
if(!tls_p->in_bio) {
luaL_error(L, "new in bio faild");
}
BIO_set_mem_eof_return(tls_p->in_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
tls_p->out_bio = BIO_new(BIO_s_mem());
if(!tls_p->out_bio) {
luaL_error(L, "new out bio faild");
}
BIO_set_mem_eof_return(tls_p->out_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
SSL_set_bio(tls_p->ssl, tls_p->in_bio, tls_p->out_bio);
}
static void
_init_client_context(lua_State* L, struct tls_context* tls_p, struct ssl_ctx* ctx_p) {
tls_p->is_server = false;
_init_bio(L, tls_p, ctx_p);
SSL_set_connect_state(tls_p->ssl);
}
static void
_init_server_context(lua_State* L, struct tls_context* tls_p, struct ssl_ctx* ctx_p) {
tls_p->is_server = true;
_init_bio(L, tls_p, ctx_p);
SSL_set_accept_state(tls_p->ssl);
}
static struct tls_context *
_check_context(lua_State* L, int idx) {
struct tls_context* tls_p = (struct tls_context*)lua_touserdata(L, idx);
if(!tls_p) {
luaL_error(L, "need tls context");
}
if(tls_p->is_close) {
luaL_error(L, "context is closed");
}
return tls_p;
}
static struct ssl_ctx *
_check_sslctx(lua_State* L, int idx) {
struct ssl_ctx* ctx_p = (struct ssl_ctx*)lua_touserdata(L, idx);
if(!ctx_p) {
luaL_error(L, "need sslctx");
}
return ctx_p;
}
static int
_ltls_context_finished(lua_State* L) {
struct tls_context* tls_p = _check_context(L, 1);
int b = SSL_is_init_finished(tls_p->ssl);
lua_pushboolean(L, b);
return 1;
}
static int
_ltls_context_close(lua_State* L) {
struct tls_context* tls_p = lua_touserdata(L, 1);
if(!tls_p->is_close) {
SSL_free(tls_p->ssl);
tls_p->ssl = NULL;
tls_p->in_bio = NULL; //in_bio and out_bio will be free when SSL_free is called
tls_p->out_bio = NULL;
tls_p->is_close = true;
}
return 0;
}
static int
_bio_read(lua_State* L, struct tls_context* tls_p) {
char outbuff[4096];
int all_read = 0;
int read = 0;
int pending = BIO_ctrl_pending(tls_p->out_bio);
if(pending >0) {
luaL_Buffer b;
luaL_buffinit(L, &b);
while(pending > 0) {
read = BIO_read(tls_p->out_bio, outbuff, sizeof(outbuff));
// printf("BIO_read read:%d pending:%d\n", read, pending);
if(read <= 0) {
luaL_error(L, "BIO_read error:%d", read);
}else if(read <= sizeof(outbuff)) {
all_read += read;
luaL_addlstring(&b, (const char*)outbuff, read);
}else {
luaL_error(L, "invalid BIO_read:%d", read);
}
pending = BIO_ctrl_pending(tls_p->out_bio);
}
if(all_read>0) {
luaL_pushresult(&b);
}
}
return all_read;
}
static void
_bio_write(lua_State* L, struct tls_context* tls_p, const char* s, size_t len) {
char* p = (char*)s;
size_t sz = len;
while(sz > 0) {
int written = BIO_write(tls_p->in_bio, p, sz);
// printf("BIO_write written:%d sz:%zu\n", written, sz);
if(written <= 0) {
luaL_error(L, "BIO_write error:%d", written);
}else if (written <= sz) {
p += written;
sz -= written;
}else {
luaL_error(L, "invalid BIO_write:%d", written);
}
}
}
static int
_ltls_context_handshake(lua_State* L) {
struct tls_context* tls_p = _check_context(L, 1);
size_t slen = 0;
const char* exchange = lua_tolstring(L, 2, &slen);
// check handshake is finished
if(SSL_is_init_finished(tls_p->ssl)) {
luaL_error(L, "handshake is finished");
}
// handshake exchange
if(slen > 0 && exchange != NULL) {
_bio_write(L, tls_p, exchange, slen);
}
// first handshake; initiated by client
if(!SSL_is_init_finished(tls_p->ssl)) {
int ret = SSL_do_handshake(tls_p->ssl);
if(ret == 1) {
return 0;
} else if (ret < 0) {
int err = SSL_get_error(tls_p->ssl, ret);
if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
int all_read = _bio_read(L, tls_p);
if(all_read>0) {
return 1;
}
} else {
luaL_error(L, "SSL_do_handshake error:%d ret:%d", err, ret);
}
} else {
int err = SSL_get_error(tls_p->ssl, ret);
luaL_error(L, "SSL_do_handshake error:%d ret:%d", err, ret);
}
}
return 0;
}
static int
_ltls_context_read(lua_State* L) {
struct tls_context* tls_p = _check_context(L, 1);
size_t slen = 0;
const char* encrypted_data = lua_tolstring(L, 2, &slen);
// write encrypted data
if(slen>0 && encrypted_data) {
_bio_write(L, tls_p, encrypted_data, slen);
}
char outbuff[4096];
int read = 0;
luaL_Buffer b;
luaL_buffinit(L, &b);
do {
read = SSL_read(tls_p->ssl, outbuff, sizeof(outbuff));
if(read <= 0) {
int err = SSL_get_error(tls_p->ssl, read);
if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
break;
}
luaL_error(L, "SSL_read error:%d", err);
}else if(read <= sizeof(outbuff)) {
luaL_addlstring(&b, outbuff, read);
}else {
luaL_error(L, "invalid SSL_read:%d", read);
}
}while(true);
luaL_pushresult(&b);
return 1;
}
static int
_ltls_context_write(lua_State* L) {
struct tls_context* tls_p = _check_context(L, 1);
size_t slen = 0;
char* unencrypted_data = (char*)lua_tolstring(L, 2, &slen);
while(slen > 0) {
int written = SSL_write(tls_p->ssl, unencrypted_data, slen);
if(written <= 0) {
int err = SSL_get_error(tls_p->ssl, written);
luaL_error(L, "SSL_write error:%d", err);
}else if(written <= slen) {
unencrypted_data += written;
slen -= written;
}else {
luaL_error(L, "invalid SSL_write:%d", written);
}
}
int all_read = _bio_read(L, tls_p);
if(all_read <= 0) {
lua_pushstring(L, "");
}
return 1;
}
static int
_lctx_gc(lua_State* L) {
struct ssl_ctx* ctx_p = _check_sslctx(L, 1);
if(ctx_p->ctx) {
SSL_CTX_free(ctx_p->ctx);
ctx_p->ctx = NULL;
}
return 0;
}
static int
_lctx_cert(lua_State* L) {
struct ssl_ctx* ctx_p = _check_sslctx(L, 1);
const char* certfile = lua_tostring(L, 2);
const char* key = lua_tostring(L, 3);
if(!certfile) {
luaL_error(L, "need certfile");
}
if(!key) {
luaL_error(L, "need private key");
}
int ret = SSL_CTX_use_certificate_chain_file(ctx_p->ctx, certfile);
if(ret != 1) {
luaL_error(L, "SSL_CTX_use_certificate_chain_file error:%d", ret);
}
ret = SSL_CTX_use_PrivateKey_file(ctx_p->ctx, key, SSL_FILETYPE_PEM);
if(ret != 1) {
luaL_error(L, "SSL_CTX_use_PrivateKey_file error:%d", ret);
}
ret = SSL_CTX_check_private_key(ctx_p->ctx);
if(ret != 1) {
luaL_error(L, "SSL_CTX_check_private_key error:%d", ret);
}
return 0;
}
static int
_lctx_ciphers(lua_State* L) {
struct ssl_ctx* ctx_p = _check_sslctx(L, 1);
const char* s = lua_tostring(L, 2);
if(!s) {
luaL_error(L, "need cipher list");
}
int ret = SSL_CTX_set_tlsext_use_srtp(ctx_p->ctx, s);
if(ret != 0) {
luaL_error(L, "SSL_CTX_set_tlsext_use_srtp error:%d", ret);
}
return 0;
}
static int
lnew_ctx(lua_State* L) {
struct ssl_ctx* ctx_p = (struct ssl_ctx*)lua_newuserdata(L, sizeof(*ctx_p));
ctx_p->ctx = SSL_CTX_new(SSLv23_method());
if(!ctx_p->ctx) {
unsigned int err = ERR_get_error();
char buf[256];
ERR_error_string_n(err, buf, sizeof(buf));
luaL_error(L, "SSL_CTX_new client faild. %s\n", buf);
}
if(luaL_newmetatable(L, "_TLS_SSLCTX_METATABLE_")) {
luaL_Reg l[] = {
{"set_ciphers", _lctx_ciphers},
{"set_cert", _lctx_cert},
{NULL, NULL},
};
luaL_newlib(L, l);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, _lctx_gc);
lua_setfield(L, -2, "__gc");
}
lua_setmetatable(L, -2);
return 1;
}
static int
lnew_tls(lua_State* L) {
struct tls_context* tls_p = (struct tls_context*)lua_newuserdata(L, sizeof(*tls_p));
tls_p->is_close = false;
const char* method = luaL_optstring(L, 1, "nil");
struct ssl_ctx* ctx_p = _check_sslctx(L, 2);
lua_pushvalue(L, 2);
lua_setuservalue(L, -2); // set ssl_ctx associated to tls_context
if(strcmp(method, "client") == 0) {
_init_client_context(L, tls_p, ctx_p);
}else if(strcmp(method, "server") == 0) {
_init_server_context(L, tls_p, ctx_p);
} else {
luaL_error(L, "invalid method:%s e.g[server, client]", method);
}
if(luaL_newmetatable(L, "_TLS_CONTEXT_METATABLE_")) {
luaL_Reg l[] = {
{"close", _ltls_context_close},
{"finished", _ltls_context_finished},
{"handshake", _ltls_context_handshake},
{"read", _ltls_context_read},
{"write", _ltls_context_write},
{NULL, NULL},
};
luaL_newlib(L, l);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, _ltls_context_close);
lua_setfield(L, -2, "__gc");
}
lua_setmetatable(L, -2);
return 1;
}
int
luaopen_ltls_c(lua_State* L) {
luaL_Reg l[] = {
{"newctx", lnew_ctx},
{"newtls", lnew_tls},
{NULL, NULL},
};
luaL_checkversion(L);
luaL_newlib(L, l);
return 1;
}
void __attribute__((constructor)) ltls_init(void) {
#ifndef OPENSSL_EXTERNAL_INITIALIZATION
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
TLS_IS_INIT = true;
#endif
}
void __attribute__((destructor)) ltls_destory(void) {
if(TLS_IS_INIT) {
ENGINE_cleanup();
CONF_modules_unload(1);
ERR_free_strings();
EVP_cleanup();
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
CRYPTO_cleanup_all_ex_data();
}
}

View File

@@ -4,6 +4,7 @@
#include <lauxlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "skynet.h"
@@ -73,6 +74,11 @@ fill_header(lua_State *L, uint8_t *buf, int sz) {
BYTE 2/3 ; 2:multipart, 3:multipart end
DWORD SESSION
PADDING msgpart(sz)
trace
WORD stringsz + 1
BYTE 4
STRING tag
*/
static int
packreq_number(lua_State *L, int session, void * msg, uint32_t sz, int is_push) {
@@ -105,7 +111,11 @@ packreq_string(lua_State *L, int session, void * msg, uint32_t sz, int is_push)
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);
if (name == NULL) {
luaL_error(L, "name is not a string, it's a %s", lua_typename(L, lua_type(L, 1)));
} else {
luaL_error(L, "name is too long %s", name);
}
}
uint8_t buf[TEMP_LENGTH];
@@ -177,14 +187,14 @@ packrequest(lua_State *L, int is_push) {
} else {
multipak = packreq_string(L, session, msg, sz, is_push);
}
int current_session = session;
if (++session < 0) {
session = 1;
uint32_t new_session = (uint32_t)session + 1;
if (new_session > INT32_MAX) {
new_session = 1;
}
lua_pushinteger(L, session);
lua_pushinteger(L, new_session);
if (multipak) {
lua_createtable(L, multipak, 0);
packreq_multi(L, current_session, msg, sz);
packreq_multi(L, session, msg, sz);
skynet_free(msg);
return 3;
} else {
@@ -203,13 +213,30 @@ lpackpush(lua_State *L) {
return packrequest(L, 1);
}
static int
lpacktrace(lua_State *L) {
size_t sz;
const char * tag = luaL_checklstring(L, 1, &sz);
if (sz > 0x8000) {
return luaL_error(L, "trace tag is too long : %d", (int) sz);
}
uint8_t buf[TEMP_LENGTH];
buf[2] = 4;
fill_header(L, buf, sz+1);
memcpy(buf+3, tag, sz);
lua_pushlstring(L, (const char *)buf, sz+3);
return 1;
}
/*
string packed message
return
uint32_t or string addr
int session
string msg
lightuserdata msg
int sz
boolean padding
boolean is_push
*/
static inline uint32_t
@@ -217,6 +244,14 @@ unpack_uint32(const uint8_t * buf) {
return buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24;
}
static void
return_buffer(lua_State *L, const char * buffer, int sz) {
void * ptr = skynet_malloc(sz);
memcpy(ptr, buffer, sz);
lua_pushlightuserdata(L, ptr);
lua_pushinteger(L, sz);
}
static int
unpackreq_number(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 9) {
@@ -226,14 +261,15 @@ unpackreq_number(lua_State *L, const uint8_t * buf, int sz) {
uint32_t session = unpack_uint32(buf+5);
lua_pushinteger(L, address);
lua_pushinteger(L, session);
lua_pushlstring(L, (const char *)buf+9, sz-9);
return_buffer(L, (const char *)buf+9, sz-9);
if (session == 0) {
lua_pushnil(L);
lua_pushboolean(L,1); // is_push, no reponse
return 5;
return 6;
}
return 3;
return 4;
}
static int
@@ -246,11 +282,12 @@ unpackmreq_number(lua_State *L, const uint8_t * buf, int sz, int is_push) {
uint32_t size = unpack_uint32(buf+9);
lua_pushinteger(L, address);
lua_pushinteger(L, session);
lua_pushnil(L);
lua_pushinteger(L, size);
lua_pushboolean(L, 1); // padding multi part
lua_pushboolean(L, is_push);
return 5;
return 6;
}
static int
@@ -262,10 +299,16 @@ unpackmreq_part(lua_State *L, const uint8_t * buf, int sz) {
uint32_t session = unpack_uint32(buf+1);
lua_pushboolean(L, 0); // no address
lua_pushinteger(L, session);
lua_pushlstring(L, (const char *)buf+5, sz-5);
return_buffer(L, (const char *)buf+5, sz-5);
lua_pushboolean(L, padding);
return 4;
return 5;
}
static int
unpacktrace(lua_State *L, const char * buf, int sz) {
lua_pushlstring(L, buf + 1, sz - 1);
return 1;
}
static int
@@ -280,14 +323,14 @@ unpackreq_string(lua_State *L, const uint8_t * buf, int sz) {
lua_pushlstring(L, (const char *)buf+2, namesz);
uint32_t session = unpack_uint32(buf + namesz + 2);
lua_pushinteger(L, (uint32_t)session);
lua_pushlstring(L, (const char *)buf+2+namesz+4, sz - namesz - 6);
return_buffer(L, (const char *)buf+2+namesz+4, sz - namesz - 6);
if (session == 0) {
lua_pushnil(L);
lua_pushboolean(L,1); // is_push, no reponse
return 5;
return 6;
}
return 3;
return 4;
}
static int
@@ -303,18 +346,26 @@ unpackmreq_string(lua_State *L, const uint8_t * buf, int sz, int is_push) {
uint32_t session = unpack_uint32(buf + namesz + 2);
uint32_t size = unpack_uint32(buf + namesz + 6);
lua_pushinteger(L, session);
lua_pushnil(L);
lua_pushinteger(L, size);
lua_pushboolean(L, 1); // padding multipart
lua_pushboolean(L, is_push);
return 5;
return 6;
}
static int
lunpackrequest(lua_State *L) {
size_t ssz;
const char *msg = luaL_checklstring(L,1,&ssz);
int sz = (int)ssz;
int sz;
const char *msg;
if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) {
msg = (const char *)lua_touserdata(L, 1);
sz = luaL_checkinteger(L, 2);
} else {
size_t ssz;
msg = luaL_checklstring(L,1,&ssz);
sz = (int)ssz;
}
switch (msg[0]) {
case 0:
return unpackreq_number(L, (const uint8_t *)msg, sz);
@@ -325,6 +376,8 @@ lunpackrequest(lua_State *L) {
case 2:
case 3:
return unpackmreq_part(L, (const uint8_t *)msg, sz);
case 4:
return unpacktrace(L, msg, sz);
case '\x80':
return unpackreq_string(L, (const uint8_t *)msg, sz);
case '\x81':
@@ -474,6 +527,32 @@ lunpackresponse(lua_State *L) {
}
}
/*
table
pointer
sz
push (pointer/sz) as string into table, and free pointer
*/
static int
lappend(lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
int n = lua_rawlen(L, 1);
if (lua_isnil(L, 2)) {
lua_settop(L, 3);
lua_seti(L, 1, n + 1);
return 0;
}
void * buffer = lua_touserdata(L, 2);
if (buffer == NULL)
return luaL_error(L, "Need lightuserdata");
int sz = luaL_checkinteger(L, 3);
lua_pushlstring(L, (const char *)buffer, sz);
skynet_free((void *)buffer);
lua_seti(L, 1, n+1);
return 0;
}
static int
lconcat(lua_State *L) {
if (!lua_istable(L,1))
@@ -507,15 +586,41 @@ lconcat(lua_State *L) {
return 2;
}
static int
lisname(lua_State *L) {
const char * name = lua_tostring(L, 1);
if (name && name[0] == '@') {
lua_pushboolean(L, 1);
return 1;
}
return 0;
}
static int
lnodename(lua_State *L) {
pid_t pid = getpid();
char hostname[256];
if (gethostname(hostname, sizeof(hostname))==0) {
lua_pushfstring(L, "%s%d", hostname, (int)pid);
} else {
lua_pushfstring(L, "noname%d", (int)pid);
}
return 1;
}
LUAMOD_API int
luaopen_skynet_cluster_core(lua_State *L) {
luaL_Reg l[] = {
{ "packrequest", lpackrequest },
{ "packpush", lpackpush },
{ "packtrace", lpacktrace },
{ "unpackrequest", lunpackrequest },
{ "packresponse", lpackresponse },
{ "unpackresponse", lunpackresponse },
{ "append", lappend },
{ "concat", lconcat },
{ "isname", lisname },
{ "nodename", lnodename },
{ NULL, NULL },
};
luaL_checkversion(L);

View File

@@ -7,6 +7,7 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define SMALL_CHUNK 256
@@ -960,7 +961,7 @@ luaopen_skynet_crypt(lua_State *L) {
if (!init) {
// Don't need call srandom more than once.
init = 1 ;
srandom(time(NULL));
srandom((random() << 8) ^ (time(NULL) << 16) ^ getpid());
}
luaL_Reg l[] = {
{ "hashkey", lhashkey },

View File

@@ -4,7 +4,6 @@
#include <lauxlib.h>
#include "malloc_hook.h"
#include "luashrtbl.h"
static int
ltotal(lua_State *L) {
@@ -37,15 +36,28 @@ ldump(lua_State *L) {
}
static int
lexpandshrtbl(lua_State *L) {
int n = luaL_checkinteger(L, 1);
luaS_expandshr(n);
lcurrent(lua_State *L) {
lua_pushinteger(L, malloc_current_memory());
return 1;
}
static int
ldumpheap(lua_State *L) {
mallctl_cmd("prof.dump");
return 0;
}
static int
lcurrent(lua_State *L) {
lua_pushinteger(L, malloc_current_memory());
lprofactive(lua_State *L) {
bool *pval, active;
if (lua_isnone(L, 1)) {
pval = NULL;
} else {
active = lua_toboolean(L, 1) ? true : false;
pval = &active;
}
bool ret = mallctl_bool("prof.active", pval);
lua_pushboolean(L, ret);
return 1;
}
@@ -59,9 +71,9 @@ luaopen_skynet_memory(lua_State *L) {
{ "dumpinfo", ldumpinfo },
{ "dump", ldump },
{ "info", dump_mem_lua },
{ "ssinfo", luaS_shrinfo },
{ "ssexpand", lexpandshrtbl },
{ "current", lcurrent },
{ "dumpheap", ldumpheap },
{ "profactive", lprofactive },
{ NULL, NULL },
};

View File

@@ -133,6 +133,7 @@ mc_remote(lua_State *L) {
lua_pushlightuserdata(L, pack->data);
lua_pushinteger(L, (lua_Integer)(pack->size));
skynet_free(pack);
skynet_free(ptr);
return 2;
}
@@ -140,7 +141,8 @@ static int
mc_nextid(lua_State *L) {
uint32_t id = (uint32_t)luaL_checkinteger(L, 1);
id += 256;
lua_pushinteger(L, (uint32_t)id);
// remove the highest bit, see #1139
lua_pushinteger(L, id & 0x7fffffffu);
return 1;
}

View File

@@ -1,166 +0,0 @@
#define LUA_LIB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
static unsigned int num_escape_sql_str(unsigned char *dst, unsigned char *src, size_t size)
{
unsigned int n =0;
while (size) {
/* the highest bit of all the UTF-8 chars
* is always 1 */
if ((*src & 0x80) == 0) {
switch (*src) {
case '\0':
case '\b':
case '\n':
case '\r':
case '\t':
case 26: /* \Z */
case '\\':
case '\'':
case '"':
n++;
break;
default:
break;
}
}
src++;
size--;
}
return n;
}
static unsigned char*
escape_sql_str(unsigned char *dst, unsigned char *src, size_t size)
{
while (size) {
if ((*src & 0x80) == 0) {
switch (*src) {
case '\0':
*dst++ = '\\';
*dst++ = '0';
break;
case '\b':
*dst++ = '\\';
*dst++ = 'b';
break;
case '\n':
*dst++ = '\\';
*dst++ = 'n';
break;
case '\r':
*dst++ = '\\';
*dst++ = 'r';
break;
case '\t':
*dst++ = '\\';
*dst++ = 't';
break;
case 26:
*dst++ = '\\';
*dst++ = 'Z';
break;
case '\\':
*dst++ = '\\';
*dst++ = '\\';
break;
case '\'':
*dst++ = '\\';
*dst++ = '\'';
break;
case '"':
*dst++ = '\\';
*dst++ = '"';
break;
default:
*dst++ = *src;
break;
}
} else {
*dst++ = *src;
}
src++;
size--;
} /* while (size) */
return dst;
}
static int
quote_sql_str(lua_State *L)
{
size_t len, dlen, escape;
unsigned char *p;
unsigned char *src, *dst;
if (lua_gettop(L) != 1) {
return luaL_error(L, "expecting one argument");
}
src = (unsigned char *) luaL_checklstring(L, 1, &len);
if (len == 0) {
dst = (unsigned char *) "''";
dlen = sizeof("''") - 1;
lua_pushlstring(L, (char *) dst, dlen);
return 1;
}
escape = num_escape_sql_str(NULL, src, len);
dlen = sizeof("''") - 1 + len + escape;
p = lua_newuserdata(L, dlen);
dst = p;
*p++ = '\'';
if (escape == 0) {
memcpy(p, src, len);
p+=len;
} else {
p = (unsigned char *) escape_sql_str(p, src, len);
}
*p++ = '\'';
if (p != dst + dlen) {
return luaL_error(L, "quote sql string error");
}
lua_pushlstring(L, (char *) dst, p - dst);
return 1;
}
static struct luaL_Reg mysqlauxlib[] = {
{"quote_sql_str",quote_sql_str},
{NULL, NULL}
};
LUAMOD_API int luaopen_skynet_mysqlaux_c (lua_State *L) {
lua_newtable(L);
luaL_setfuncs(L, mysqlauxlib, 0);
return 1;
}

View File

@@ -253,6 +253,7 @@ fillcolliding(lua_State *L, struct context *ctx) {
for (i=emptyslot;i<sizehash;i++) {
if (tbl->hash[i].valuetype == VALUETYPE_NIL) {
n = &tbl->hash[i];
emptyslot = i + 1;
break;
}
}

263
lualib-src/lua-sharetable.c Normal file
View File

@@ -0,0 +1,263 @@
#define LUA_LIB
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "lgc.h"
#ifdef makeshared
static void
mark_shared(lua_State *L) {
if (lua_type(L, -1) != LUA_TTABLE) {
luaL_error(L, "Not a table, it's a %s.", lua_typename(L, lua_type(L, -1)));
}
Table * t = (Table *)lua_topointer(L, -1);
if (isshared(t))
return;
makeshared(t);
luaL_checkstack(L, 4, NULL);
if (lua_getmetatable(L, -1)) {
luaL_error(L, "Can't share metatable");
}
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
int i;
for (i=0;i<2;i++) {
int idx = -i-1;
int t = lua_type(L, idx);
switch (t) {
case LUA_TTABLE:
mark_shared(L);
break;
case LUA_TNUMBER:
case LUA_TBOOLEAN:
case LUA_TLIGHTUSERDATA:
break;
case LUA_TFUNCTION:
if (lua_getupvalue(L, idx, 1) != NULL) {
luaL_error(L, "Invalid function with upvalue");
} else if (!lua_iscfunction(L, idx)) {
LClosure *f = (LClosure *)lua_topointer(L, idx);
makeshared(f);
}
break;
case LUA_TSTRING:
lua_sharestring(L, idx);
break;
default:
luaL_error(L, "Invalid type [%s]", lua_typename(L, t));
break;
}
}
lua_pop(L, 1);
}
}
static int
lis_sharedtable(lua_State* L) {
int b = 0;
if(lua_type(L, 1) == LUA_TTABLE) {
Table * t = (Table *)lua_topointer(L, 1);
b = isshared(t);
}
lua_pushboolean(L, b);
return 1;
}
static int
make_matrix(lua_State *L) {
// turn off gc , because marking shared will prevent gc mark.
lua_gc(L, LUA_GCSTOP, 0);
mark_shared(L);
Table * t = (Table *)lua_topointer(L, -1);
lua_pushlightuserdata(L, t);
return 1;
}
static int
clone_table(lua_State *L) {
lua_clonetable(L, lua_touserdata(L, 1));
return 1;
}
static int
lco_stackvalues(lua_State* L) {
lua_State *cL = lua_tothread(L, 1);
luaL_argcheck(L, cL, 1, "thread expected");
int n = 0;
if(cL != L) {
luaL_checktype(L, 2, LUA_TTABLE);
n = lua_gettop(cL);
if(n > 0) {
luaL_checkstack(L, n+1, NULL);
int top = lua_gettop(L);
lua_xmove(cL, L, n);
int i=0;
for(i=1; i<=n; i++) {
lua_pushvalue(L, top+i);
lua_seti(L, 2, i);
}
lua_xmove(L, cL, n);
}
}
lua_pushinteger(L, n);
return 1;
}
struct state_ud {
lua_State *L;
};
static int
close_state(lua_State *L) {
struct state_ud *ud = (struct state_ud *)luaL_checkudata(L, 1, "BOXMATRIXSTATE");
if (ud->L) {
lua_close(ud->L);
ud->L = NULL;
}
return 0;
}
static int
get_matrix(lua_State *L) {
struct state_ud *ud = (struct state_ud *)luaL_checkudata(L, 1, "BOXMATRIXSTATE");
if (ud->L) {
const void * v = lua_topointer(ud->L, 1);
lua_pushlightuserdata(L, (void *)v);
return 1;
}
return 0;
}
static int
get_size(lua_State *L) {
struct state_ud *ud = (struct state_ud *)luaL_checkudata(L, 1, "BOXMATRIXSTATE");
if (ud->L) {
lua_Integer sz = lua_gc(ud->L, LUA_GCCOUNT, 0);
sz *= 1024;
sz += lua_gc(ud->L, LUA_GCCOUNTB, 0);
lua_pushinteger(L, sz);
} else {
lua_pushinteger(L, 0);
}
return 1;
}
static int
box_state(lua_State *L, lua_State *mL) {
struct state_ud *ud = (struct state_ud *)lua_newuserdata(L, sizeof(*ud));
ud->L = mL;
if (luaL_newmetatable(L, "BOXMATRIXSTATE")) {
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, close_state);
lua_setfield(L, -2, "close");
lua_pushcfunction(L, get_matrix);
lua_setfield(L, -2, "getptr");
lua_pushcfunction(L, get_size);
lua_setfield(L, -2, "size");
}
lua_setmetatable(L, -2);
return 1;
}
static int
load_matrixfile(lua_State *L) {
luaL_openlibs(L);
const char * source = (const char *)lua_touserdata(L, 1);
if (source[0] == '@') {
if (luaL_loadfilex_(L, source+1, NULL) != LUA_OK)
lua_error(L);
} else {
if (luaL_loadstring(L, source) != LUA_OK)
lua_error(L);
}
lua_replace(L, 1);
if (lua_pcall(L, lua_gettop(L) - 1, 1, 0) != LUA_OK)
lua_error(L);
lua_gc(L, LUA_GCCOLLECT, 0);
lua_pushcfunction(L, make_matrix);
lua_insert(L, -2);
lua_call(L, 1, 1);
return 1;
}
static int
matrix_from_file(lua_State *L) {
lua_State *mL = luaL_newstate();
if (mL == NULL) {
return luaL_error(L, "luaL_newstate failed");
}
const char * source = luaL_checkstring(L, 1);
int top = lua_gettop(L);
lua_pushcfunction(mL, load_matrixfile);
lua_pushlightuserdata(mL, (void *)source);
if (top > 1) {
if (!lua_checkstack(mL, top + 1)) {
return luaL_error(L, "Too many argument %d", top);
}
int i;
for (i=2;i<=top;i++) {
switch(lua_type(L, i)) {
case LUA_TBOOLEAN:
lua_pushboolean(mL, lua_toboolean(L, i));
break;
case LUA_TNUMBER:
if (lua_isinteger(L, i)) {
lua_pushinteger(mL, lua_tointeger(L, i));
} else {
lua_pushnumber(mL, lua_tonumber(L, i));
}
break;
case LUA_TLIGHTUSERDATA:
lua_pushlightuserdata(mL, lua_touserdata(L, i));
break;
case LUA_TFUNCTION:
if (lua_iscfunction(L, i) && lua_getupvalue(L, i, 1) == NULL) {
lua_pushcfunction(mL, lua_tocfunction(L, i));
break;
}
return luaL_argerror(L, i, "Only support light C function");
default:
return luaL_argerror(L, i, "Type invalid");
}
}
}
int ok = lua_pcall(mL, top, 1, 0);
if (ok != LUA_OK) {
lua_pushstring(L, lua_tostring(mL, -1));
lua_close(mL);
lua_error(L);
}
return box_state(L, mL);
}
LUAMOD_API int
luaopen_skynet_sharetable_core(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "clone", clone_table },
{ "stackvalues", lco_stackvalues },
{ "matrix", matrix_from_file },
{ "is_sharedtable", lis_sharedtable },
{ NULL, NULL },
};
luaL_newlib(L, l);
return 1;
}
#else
LUAMOD_API int
luaopen_skynet_sharetable_core(lua_State *L) {
return luaL_error(L, "No share string table support");
}
#endif

View File

@@ -11,6 +11,29 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include <time.h>
#if defined(__APPLE__)
#include <sys/time.h>
#endif
#include "skynet.h"
// return nsec
static int64_t
get_time() {
#if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
return (int64_t)1000000000 * ti.tv_sec + ti.tv_nsec;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)1000000000 * tv.tv_sec + tv.tv_usec * 1000;
#endif
}
struct snlua {
lua_State * L;
@@ -120,6 +143,38 @@ lcommand(lua_State *L) {
return 0;
}
static int
laddresscommand(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
const char * cmd = luaL_checkstring(L,1);
const char * result;
const char * parm = NULL;
if (lua_gettop(L) == 2) {
parm = luaL_checkstring(L,2);
}
result = skynet_command(context, cmd, parm);
if (result && result[0] == ':') {
int i;
uint32_t addr = 0;
for (i=1;result[i];i++) {
int c = result[i];
if (c>='0' && c<='9') {
c = c - '0';
} else if (c>='a' && c<='f') {
c = c - 'a' + 10;
} else if (c>='A' && c<='F') {
c = c - 'A' + 10;
} else {
return 0;
}
addr = addr * 16 + c;
}
lua_pushinteger(L, addr);
return 1;
}
return 0;
}
static int
lintcommand(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
@@ -223,6 +278,11 @@ send_message(lua_State *L, int source, int idx_type) {
luaL_error(L, "invalid param %s", lua_typename(L, lua_type(L,idx_type+2)));
}
if (session < 0) {
if (session == -2) {
// package is too large
lua_pushboolean(L, 0);
return 1;
}
// send to invalid address
// todo: maybe throw an error would be better
return 0;
@@ -346,6 +406,79 @@ lnow(lua_State *L) {
return 1;
}
static int
lhpc(lua_State *L) {
lua_pushinteger(L, get_time());
return 1;
}
#define MAX_LEVEL 3
struct source_info {
const char * source;
int line;
};
/*
string tag
string userstring
thread co (default nil/current L)
integer level (default nil)
*/
static int
ltrace(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
const char * tag = luaL_checkstring(L, 1);
const char * user = luaL_checkstring(L, 2);
if (!lua_isnoneornil(L, 3)) {
lua_State * co = L;
int level;
if (lua_isthread(L, 3)) {
co = lua_tothread (L, 3);
level = luaL_optinteger(L, 4, 1);
} else {
level = luaL_optinteger(L, 3, 1);
}
struct source_info si[MAX_LEVEL];
lua_Debug d;
int index = 0;
do {
if (!lua_getstack(co, level, &d))
break;
lua_getinfo(co, "Sl", &d);
level++;
si[index].source = d.source;
si[index].line = d.currentline;
if (d.currentline >= 0)
++index;
} while (index < MAX_LEVEL);
switch (index) {
case 1:
skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d", tag, get_time(), user, si[0].source, si[0].line);
break;
case 2:
skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d %s:%d", tag, get_time(), user,
si[0].source, si[0].line,
si[1].source, si[1].line
);
break;
case 3:
skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d %s:%d %s:%d", tag, get_time(), user,
si[0].source, si[0].line,
si[1].source, si[1].line,
si[2].source, si[2].line
);
break;
default:
skynet_error(context, "<TRACE %s> %" PRId64 " %s", tag, get_time(), user);
break;
}
return 0;
}
skynet_error(context, "<TRACE %s> %" PRId64 " %s", tag, get_time(), user);
return 0;
}
LUAMOD_API int
luaopen_skynet_core(lua_State *L) {
luaL_checkversion(L);
@@ -356,19 +489,27 @@ luaopen_skynet_core(lua_State *L) {
{ "redirect", lredirect },
{ "command" , lcommand },
{ "intcommand", lintcommand },
{ "addresscommand", laddresscommand },
{ "error", lerror },
{ "tostring", ltostring },
{ "harbor", lharbor },
{ "callback", lcallback },
{ "trace", ltrace },
{ NULL, NULL },
};
// functions without skynet_context
luaL_Reg l2[] = {
{ "tostring", ltostring },
{ "pack", luaseri_pack },
{ "unpack", luaseri_unpack },
{ "packstring", lpackstring },
{ "trash" , ltrash },
{ "callback", lcallback },
{ "now", lnow },
{ "hpc", lhpc }, // getHPCounter
{ NULL, NULL },
};
luaL_newlibtable(L, l);
lua_createtable(L, 0, sizeof(l)/sizeof(l[0]) + sizeof(l2)/sizeof(l2[0]) -2);
lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context");
struct skynet_context *ctx = lua_touserdata(L,-1);
@@ -376,7 +517,10 @@ luaopen_skynet_core(lua_State *L) {
return luaL_error(L, "Init skynet context first");
}
luaL_setfuncs(L,l,1);
luaL_setfuncs(L,l2,0);
return 1;
}

View File

@@ -525,41 +525,59 @@ concat_table(lua_State *L, int index, void *buffer, size_t tlen) {
lua_pop(L,1);
}
static void *
get_buffer(lua_State *L, int index, int *sz) {
static void
get_buffer(lua_State *L, int index, struct socket_sendbuffer *buf) {
void *buffer;
switch(lua_type(L, index)) {
const char * str;
size_t len;
case LUA_TUSERDATA:
case LUA_TLIGHTUSERDATA:
buffer = lua_touserdata(L,index);
*sz = luaL_checkinteger(L,index+1);
// lua full useobject must be a raw pointer, it can't be a socket object or a memory object.
buf->type = SOCKET_BUFFER_RAWPOINTER;
buf->buffer = lua_touserdata(L, index);
if (lua_isinteger(L, index+1)) {
buf->sz = lua_tointeger(L, index+1);
} else {
buf->sz = lua_rawlen(L, index);
}
break;
case LUA_TLIGHTUSERDATA: {
int sz = -1;
if (lua_isinteger(L, index+1)) {
sz = lua_tointeger(L,index+1);
}
if (sz < 0) {
buf->type = SOCKET_BUFFER_OBJECT;
} else {
buf->type = SOCKET_BUFFER_MEMORY;
}
buf->buffer = lua_touserdata(L,index);
buf->sz = (size_t)sz;
break;
}
case LUA_TTABLE:
// concat the table as a string
len = count_size(L, index);
buffer = skynet_malloc(len);
concat_table(L, index, buffer, len);
*sz = (int)len;
buf->type = SOCKET_BUFFER_MEMORY;
buf->buffer = buffer;
buf->sz = len;
break;
default:
str = luaL_checklstring(L, index, &len);
buffer = skynet_malloc(len);
memcpy(buffer, str, len);
*sz = (int)len;
buf->type = SOCKET_BUFFER_RAWPOINTER;
buf->buffer = luaL_checklstring(L, index, &buf->sz);
break;
}
return buffer;
}
static int
lsend(lua_State *L) {
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
int id = luaL_checkinteger(L, 1);
int sz = 0;
void *buffer = get_buffer(L, 2, &sz);
int err = skynet_socket_send(ctx, id, buffer, sz);
struct socket_sendbuffer buf;
buf.id = id;
get_buffer(L, 2, &buf);
int err = skynet_socket_sendbuffer(ctx, &buf);
lua_pushboolean(L, !err);
return 1;
}
@@ -568,9 +586,10 @@ static int
lsendlow(lua_State *L) {
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
int id = luaL_checkinteger(L, 1);
int sz = 0;
void *buffer = get_buffer(L, 2, &sz);
int err = skynet_socket_send_lowpriority(ctx, id, buffer, sz);
struct socket_sendbuffer buf;
buf.id = id;
get_buffer(L, 2, &buf);
int err = skynet_socket_sendbuffer_lowpriority(ctx, &buf);
lua_pushboolean(L, !err);
return 1;
}
@@ -645,9 +664,10 @@ ludp_send(lua_State *L) {
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
int id = luaL_checkinteger(L, 1);
const char * address = luaL_checkstring(L, 2);
int sz = 0;
void *buffer = get_buffer(L, 3, &sz);
int err = skynet_socket_udp_send(ctx, id, address, buffer, sz);
struct socket_sendbuffer buf;
buf.id = id;
get_buffer(L, 3, &buf);
int err = skynet_socket_udp_sendbuffer(ctx, address, &buf);
lua_pushboolean(L, !err);
@@ -680,6 +700,72 @@ ludp_address(lua_State *L) {
return 2;
}
static void
getinfo(lua_State *L, struct socket_info *si) {
lua_newtable(L);
lua_pushinteger(L, si->id);
lua_setfield(L, -2, "id");
lua_pushinteger(L, si->opaque);
lua_setfield(L, -2, "address");
switch(si->type) {
case SOCKET_INFO_LISTEN:
lua_pushstring(L, "LISTEN");
lua_setfield(L, -2, "type");
lua_pushinteger(L, si->read);
lua_setfield(L, -2, "accept");
lua_pushinteger(L, si->rtime);
lua_setfield(L, -2, "rtime");
if (si->name[0]) {
lua_pushstring(L, si->name);
lua_setfield(L, -2, "sock");
}
return;
case SOCKET_INFO_TCP:
lua_pushstring(L, "TCP");
break;
case SOCKET_INFO_UDP:
lua_pushstring(L, "UDP");
break;
case SOCKET_INFO_BIND:
lua_pushstring(L, "BIND");
break;
default:
lua_pushstring(L, "UNKNOWN");
lua_setfield(L, -2, "type");
return;
}
lua_setfield(L, -2, "type");
lua_pushinteger(L, si->read);
lua_setfield(L, -2, "read");
lua_pushinteger(L, si->write);
lua_setfield(L, -2, "write");
lua_pushinteger(L, si->wbuffer);
lua_setfield(L, -2, "wbuffer");
lua_pushinteger(L, si->rtime);
lua_setfield(L, -2, "rtime");
lua_pushinteger(L, si->wtime);
lua_setfield(L, -2, "wtime");
if (si->name[0]) {
lua_pushstring(L, si->name);
lua_setfield(L, -2, "peer");
}
}
static int
linfo(lua_State *L) {
lua_newtable(L);
struct socket_info * si = skynet_socket_info();
struct socket_info * temp = si;
int n = 0;
while (temp) {
getinfo(L, temp);
lua_seti(L, -2, ++n);
temp = temp->next;
}
socket_info_release(si);
return 1;
}
LUAMOD_API int
luaopen_skynet_socketdriver(lua_State *L) {
luaL_checkversion(L);
@@ -693,6 +779,7 @@ luaopen_skynet_socketdriver(lua_State *L) {
{ "readline", lreadline },
{ "str2p", lstr2p },
{ "header", lheader },
{ "info", linfo },
{ "unpack", lunpack },
{ NULL, NULL },

View File

@@ -2,6 +2,7 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "msvcint.h"
#include "lua.h"
@@ -56,9 +57,20 @@ static int64_t lua_tointegerx(lua_State *L, int idx, int *isnum) {
}
#endif
// work around , use push & lua_gettable may be better
#define lua_geti lua_rawgeti
#define lua_seti lua_rawseti
static void
lua_geti(lua_State *L, int index, lua_Integer i) {
index = lua_absindex(L, index);
lua_pushinteger(L, i);
lua_gettable(L, index);
}
static void
lua_seti(lua_State *L, int index, lua_Integer n) {
index = lua_absindex(L, index);
lua_pushinteger(L, n);
lua_insert(L, -2);
lua_settable(L, index);
}
#endif
@@ -109,13 +121,35 @@ struct encode_ud {
const char * array_tag;
int array_index;
int deep;
int iter_index;
int iter_func;
int iter_table;
int iter_key;
};
static int
next_list(lua_State *L, struct encode_ud * self) {
// todo: check the key is equal to mainindex value
if (self->iter_func) {
lua_pushvalue(L, self->iter_func);
lua_pushvalue(L, self->iter_table);
lua_pushvalue(L, self->iter_key);
lua_call(L, 2, 2);
if (lua_isnil(L, -2)) {
lua_pop(L, 2);
return 0;
}
return 1;
} else {
lua_pushvalue(L,self->iter_key);
return lua_next(L, self->array_index);
}
}
static int
encode(const struct sproto_arg *args) {
struct encode_ud *self = args->ud;
lua_State *L = self->L;
luaL_checkstack(L, 12, NULL);
if (self->deep >= ENCODE_DEEPLEVEL)
return luaL_error(L, "The table is too deep");
if (args->index > 0) {
@@ -130,29 +164,38 @@ encode(const struct sproto_arg *args) {
self->array_index = 0;
return SPROTO_CB_NOARRAY;
}
if (!lua_istable(L, -1)) {
return luaL_error(L, ".*%s(%d) should be a table (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
}
if (self->array_index) {
lua_replace(L, self->array_index);
} else {
self->array_index = lua_gettop(L);
}
if (luaL_getmetafield(L, self->array_index, "__pairs")) {
lua_pushvalue(L, self->array_index);
lua_call(L, 1, 3);
int top = lua_gettop(L);
self->iter_func = top - 2;
self->iter_table = top - 1;
self->iter_key = top;
} else if (!lua_istable(L,self->array_index)) {
return luaL_error(L, ".*%s(%d) should be a table or an userdata with metamethods (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
} else {
lua_pushnil(L);
self->iter_func = 0;
self->iter_table = 0;
self->iter_key = lua_gettop(L);
}
}
if (args->mainindex >= 0) {
// use lua_next to iterate the table
// todo: check the key is equal to mainindex value
lua_pushvalue(L,self->iter_index);
if (!lua_next(L, self->array_index)) {
if (!next_list(L, self)) {
// iterate end
lua_pushnil(L);
lua_replace(L, self->iter_index);
lua_replace(L, self->iter_key);
return SPROTO_CB_NIL;
}
lua_insert(L, -2);
lua_replace(L, self->iter_index);
lua_replace(L, self->iter_key);
} else {
lua_geti(L, self->array_index, args->index);
}
@@ -172,7 +215,7 @@ encode(const struct sproto_arg *args) {
// It's decimal.
lua_Number vn = lua_tonumber(L, -1);
// use 64bit integer for 32bit architecture.
v = (int64_t)(vn * args->extra + 0.5);
v = (int64_t)(round(vn * args->extra));
} else {
v = lua_tointegerx(L, -1, &isnum);
if(!isnum) {
@@ -221,18 +264,15 @@ encode(const struct sproto_arg *args) {
struct encode_ud sub;
int r;
int top = lua_gettop(L);
if (!lua_istable(L, top)) {
return luaL_error(L, ".%s[%d] is not a table (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
}
sub.L = L;
sub.st = args->subtype;
sub.tbl_index = top;
sub.array_tag = NULL;
sub.array_index = 0;
sub.deep = self->deep + 1;
lua_pushnil(L); // prepare an iterator slot
sub.iter_index = sub.tbl_index + 1;
sub.iter_func = 0;
sub.iter_table = 0;
sub.iter_key = 0;
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
lua_settop(L, top-1); // pop the value
if (r < 0)
@@ -280,8 +320,6 @@ lencode(lua_State *L) {
lua_pushstring(L, "");
return 1; // response nil
}
luaL_checktype(L, tbl_index, LUA_TTABLE);
luaL_checkstack(L, ENCODE_DEEPLEVEL*2 + 8, NULL);
self.L = L;
self.st = st;
self.tbl_index = tbl_index;
@@ -292,8 +330,9 @@ lencode(lua_State *L) {
self.deep = 0;
lua_settop(L, tbl_index);
lua_pushnil(L); // for iterator (stack slot 3)
self.iter_index = tbl_index+1;
self.iter_func = 0;
self.iter_table = 0;
self.iter_key = 0;
r = sproto_encode(st, buffer, sz, encode, &self);
if (r<0) {
@@ -322,6 +361,7 @@ decode(const struct sproto_arg *args) {
lua_State *L = self->L;
if (self->deep >= ENCODE_DEEPLEVEL)
return luaL_error(L, "The table is too deep");
luaL_checkstack(L, 12, NULL);
if (args->index != 0) {
// It's array
if (args->tagname != self->array_tag) {
@@ -460,7 +500,6 @@ ldecode(lua_State *L) {
if (!lua_istable(L, -1)) {
lua_newtable(L);
}
luaL_checkstack(L, ENCODE_DEEPLEVEL*3 + 8, NULL);
self.L = L;
self.result_index = lua_gettop(L);
self.array_index = 0;

View File

@@ -11,6 +11,8 @@
#define SIZEOF_LENGTH 4
#define SIZEOF_HEADER 2
#define SIZEOF_FIELD 2
#define SIZEOF_INT64 ((int)sizeof(uint64_t))
#define SIZEOF_INT32 ((int)sizeof(uint32_t))
struct field {
int tag;
@@ -758,7 +760,7 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
return NULL;
buffer++;
size--;
intlen = sizeof(uint32_t);
intlen = SIZEOF_INT32;
index = 1;
*noarray = 0;
@@ -781,36 +783,38 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
}
return NULL; // sz == SPROTO_CB_ERROR
}
if (size < sizeof(uint64_t))
// notice: sizeof(uint64_t) is size_t (unsigned) , size may be negative. See issue #75
// so use MACRO SIZOF_INT64 instead
if (size < SIZEOF_INT64)
return NULL;
if (sz == sizeof(uint32_t)) {
if (sz == SIZEOF_INT32) {
uint32_t v = u.u32;
buffer[0] = v & 0xff;
buffer[1] = (v >> 8) & 0xff;
buffer[2] = (v >> 16) & 0xff;
buffer[3] = (v >> 24) & 0xff;
if (intlen == sizeof(uint64_t)) {
if (intlen == SIZEOF_INT64) {
uint32_to_uint64(v & 0x80000000, buffer);
}
} else {
uint64_t v;
if (sz != sizeof(uint64_t))
if (sz != SIZEOF_INT64)
return NULL;
if (intlen == sizeof(uint32_t)) {
if (intlen == SIZEOF_INT32) {
int i;
// rearrange
size -= (index-1) * sizeof(uint32_t);
if (size < sizeof(uint64_t))
size -= (index-1) * SIZEOF_INT32;
if (size < SIZEOF_INT64)
return NULL;
buffer += (index-1) * sizeof(uint32_t);
buffer += (index-1) * SIZEOF_INT32;
for (i=index-2;i>=0;i--) {
int negative;
memcpy(header+1+i*sizeof(uint64_t), header+1+i*sizeof(uint32_t), sizeof(uint32_t));
negative = header[1+i*sizeof(uint64_t)+3] & 0x80;
uint32_to_uint64(negative, header+1+i*sizeof(uint64_t));
memcpy(header+1+i*SIZEOF_INT64, header+1+i*SIZEOF_INT32, SIZEOF_INT32);
negative = header[1+i*SIZEOF_INT64+3] & 0x80;
uint32_to_uint64(negative, header+1+i*SIZEOF_INT64);
}
intlen = sizeof(uint64_t);
intlen = SIZEOF_INT64;
}
v = u.u64;
@@ -956,14 +960,14 @@ sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_call
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
if (sz == sizeof(uint32_t)) {
if (sz == SIZEOF_INT32) {
if (u.u32 < 0x7fff) {
value = (u.u32+1) * 2;
sz = 2; // sz can be any number > 0
} else {
sz = encode_integer(u.u32, data, size);
}
} else if (sz == sizeof(uint64_t)) {
} else if (sz == SIZEOF_INT64) {
sz= encode_uint64(u.u64, data, size);
} else {
return -1;
@@ -1066,22 +1070,22 @@ decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
int len = *stream;
++stream;
--sz;
if (len == sizeof(uint32_t)) {
if (sz % sizeof(uint32_t) != 0)
if (len == SIZEOF_INT32) {
if (sz % SIZEOF_INT32 != 0)
return -1;
for (i=0;i<sz/sizeof(uint32_t);i++) {
uint64_t value = expand64(todword(stream + i*sizeof(uint32_t)));
for (i=0;i<sz/SIZEOF_INT32;i++) {
uint64_t value = expand64(todword(stream + i*SIZEOF_INT32));
args->index = i+1;
args->value = &value;
args->length = sizeof(value);
cb(args);
}
} else if (len == sizeof(uint64_t)) {
if (sz % sizeof(uint64_t) != 0)
} else if (len == SIZEOF_INT64) {
if (sz % SIZEOF_INT64 != 0)
return -1;
for (i=0;i<sz/sizeof(uint64_t);i++) {
uint64_t low = todword(stream + i*sizeof(uint64_t));
uint64_t hi = todword(stream + i*sizeof(uint64_t) + sizeof(uint32_t));
for (i=0;i<sz/SIZEOF_INT64;i++) {
uint64_t low = todword(stream + i*SIZEOF_INT64);
uint64_t hi = todword(stream + i*SIZEOF_INT64 + SIZEOF_INT32);
uint64_t value = low | hi << 32;
args->index = i+1;
args->value = &value;
@@ -1175,16 +1179,16 @@ sproto_decode(const struct sproto_type *st, const void * data, int size, sproto_
switch (f->type) {
case SPROTO_TINTEGER: {
uint32_t sz = todword(currentdata);
if (sz == sizeof(uint32_t)) {
if (sz == SIZEOF_INT32) {
uint64_t v = expand64(todword(currentdata + SIZEOF_LENGTH));
args.value = &v;
args.length = sizeof(v);
cb(&args);
} else if (sz != sizeof(uint64_t)) {
} else if (sz != SIZEOF_INT64) {
return -1;
} else {
uint32_t low = todword(currentdata + SIZEOF_LENGTH);
uint32_t hi = todword(currentdata + SIZEOF_LENGTH + sizeof(uint32_t));
uint32_t hi = todword(currentdata + SIZEOF_LENGTH + SIZEOF_INT32);
uint64_t v = (uint64_t)low | (uint64_t) hi << 32;
args.value = &v;
args.length = sizeof(v);

View File

@@ -8,78 +8,6 @@ local table = table
local httpc = {}
local function request(fd, method, host, url, recvheader, header, content)
local read = socket.readfunc(fd)
local write = socket.writefunc(fd)
local header_content = ""
if header then
if not header.host then
header.host = host
end
for k,v in pairs(header) do
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
end
else
header_content = string.format("host:%s\r\n",host)
end
if content then
local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n\r\n", method, url, header_content, #content)
write(data)
write(content)
else
local request_header = string.format("%s %s HTTP/1.1\r\n%scontent-length:0\r\n\r\n", method, url, header_content)
write(request_header)
end
local tmpline = {}
local body = internal.recvheader(read, tmpline, "")
if not body then
error(socket.socket_error)
end
local statusline = tmpline[1]
local code, info = statusline:match "HTTP/[%d%.]+%s+([%d]+)%s+(.*)$"
code = assert(tonumber(code))
local header = internal.parseheader(tmpline,2,recvheader or {})
if not header then
error("Invalid HTTP response header")
end
local length = header["content-length"]
if length then
length = tonumber(length)
end
local mode = header["transfer-encoding"]
if mode then
if mode ~= "identity" and mode ~= "chunked" then
error ("Unsupport transfer-encoding")
end
end
if mode == "chunked" then
body, header = internal.recvchunkedbody(read, nil, header, body)
if not body then
error("Invalid response body")
end
else
-- identity mode
if length then
if #body >= length then
body = body:sub(1,length)
else
local padding = read(length - #body)
body = body .. padding
end
else
-- no content-length, read all
body = body .. socket.readall(fd)
end
end
return code, body
end
local async_dns
@@ -88,11 +16,60 @@ function httpc.dns(server,port)
dns.server(server,port)
end
local function check_protocol(host)
local protocol = host:match("^[Hh][Tt][Tt][Pp][Ss]?://")
if protocol then
host = string.gsub(host, "^"..protocol, "")
protocol = string.lower(protocol)
if protocol == "https://" then
return "https", host
elseif protocol == "http://" then
return "http", host
else
error(string.format("Invalid protocol: %s", protocol))
end
else
return "http", host
end
end
local SSLCTX_CLIENT = nil
local function gen_interface(protocol, fd)
if protocol == "http" then
return {
init = nil,
close = nil,
read = socket.readfunc(fd),
write = socket.writefunc(fd),
readall = function ()
return socket.readall(fd)
end,
}
elseif protocol == "https" then
local tls = require "http.tlshelper"
SSLCTX_CLIENT = SSLCTX_CLIENT or tls.newctx()
local tls_ctx = tls.newtls("client", SSLCTX_CLIENT)
return {
init = tls.init_requestfunc(fd, tls_ctx),
close = tls.closefunc(tls_ctx),
read = tls.readfunc(fd, tls_ctx),
write = tls.writefunc(fd, tls_ctx),
readall = tls.readallfunc(fd, tls_ctx),
}
else
error(string.format("Invalid protocol: %s", protocol))
end
end
function httpc.request(method, host, url, recvheader, header, content)
local protocol
local timeout = httpc.timeout -- get httpc.timeout before any blocked api
protocol, host = check_protocol(host)
local hostname, port = host:match"([^:]+):?(%d*)$"
if port == "" then
port = 80
port = protocol=="http" and 80 or protocol=="https" and 443
else
port = tonumber(port)
end
@@ -101,20 +78,31 @@ function httpc.request(method, host, url, recvheader, header, content)
end
local fd = socket.connect(hostname, port, timeout)
if not fd then
error(string.format("http connect error host:%s, port:%s, timeout:%s", hostname, port, timeout))
error(string.format("%s connect error host:%s, port:%s, timeout:%s", protocol, hostname, port, timeout))
return
end
-- print("protocol hostname port", protocol, hostname, port)
local interface = gen_interface(protocol, fd)
local finish
if timeout then
skynet.timeout(timeout, function()
if not finish then
socket.shutdown(fd) -- shutdown the socket fd, need close later.
if interface.close then
interface.close()
end
end
end)
end
local ok , statuscode, body = pcall(request, fd,method, host, url, recvheader, header, content)
if interface.init then
interface.init()
end
local ok , statuscode, body = pcall(internal.request, interface, method, host, url, recvheader, header, content)
finish = true
socket.close(fd)
if interface.close then
interface.close()
end
if ok then
return statuscode, body
else

View File

@@ -48,9 +48,6 @@ function M.recvheader(readbytes, lines, header)
while true do
local bytes = readbytes()
header = header .. bytes
if #header > LIMIT then
return
end
e = header:find("\r\n\r\n", -#bytes-3, true)
if e then
result = header:sub(e+4)
@@ -59,6 +56,9 @@ function M.recvheader(readbytes, lines, header)
if header:find "^\r\n" then
return header:sub(3)
end
if #header > LIMIT then
return
end
end
end
for v in header:gmatch("(.-)\r\n") do
@@ -141,4 +141,85 @@ function M.recvchunkedbody(readbytes, bodylimit, header, body)
return result, header
end
function M.request(interface, method, host, url, recvheader, header, content)
local is_ws = interface.websocket
local read = interface.read
local write = interface.write
local header_content = ""
if header then
if not header.host then
header.host = host
end
for k,v in pairs(header) do
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
end
else
header_content = string.format("host:%s\r\n",host)
end
if content then
local data = string.format("%s %s HTTP/1.1\r\n%scontent-length:%d\r\n\r\n", method, url, header_content, #content)
write(data)
write(content)
else
local request_header = string.format("%s %s HTTP/1.1\r\n%scontent-length:0\r\n\r\n", method, url, header_content)
write(request_header)
end
local tmpline = {}
local body = M.recvheader(read, tmpline, "")
if not body then
error(socket.socket_error)
end
local statusline = tmpline[1]
local code, info = statusline:match "HTTP/[%d%.]+%s+([%d]+)%s+(.*)$"
code = assert(tonumber(code))
local header = M.parseheader(tmpline,2,recvheader or {})
if not header then
error("Invalid HTTP response header")
end
local length = header["content-length"]
if length then
length = tonumber(length)
end
local mode = header["transfer-encoding"]
if mode then
if mode ~= "identity" and mode ~= "chunked" then
error ("Unsupport transfer-encoding")
end
end
if mode == "chunked" then
body, header = M.recvchunkedbody(read, nil, header, body)
if not body then
error("Invalid response body")
end
else
-- identity mode
if length then
if #body >= length then
body = body:sub(1,length)
else
local padding = read(length - #body)
body = body .. padding
end
elseif code == 204 or code == 304 or code < 200 then
body = ""
-- See https://stackoverflow.com/questions/15991173/is-the-content-length-header-required-for-a-http-1-0-response
elseif is_ws and code == 101 then
-- if websocket handshake success
return code, body
else
-- no content-length, read all
body = body .. interface.readall()
end
end
return code, body
end
return M

96
lualib/http/tlshelper.lua Normal file
View File

@@ -0,0 +1,96 @@
local socket = require "http.sockethelper"
local c = require "ltls.c"
local tlshelper = {}
function tlshelper.init_requestfunc(fd, tls_ctx)
local readfunc = socket.readfunc(fd)
local writefunc = socket.writefunc(fd)
return function ()
local ds1 = tls_ctx:handshake()
writefunc(ds1)
while not tls_ctx:finished() do
local ds2 = readfunc()
local ds3 = tls_ctx:handshake(ds2)
if ds3 then
writefunc(ds3)
end
end
end
end
function tlshelper.init_responsefunc(fd, tls_ctx)
local readfunc = socket.readfunc(fd)
local writefunc = socket.writefunc(fd)
return function ()
while not tls_ctx:finished() do
local ds1 = readfunc()
local ds2 = tls_ctx:handshake(ds1)
if ds2 then
writefunc(ds2)
end
end
local ds3 = tls_ctx:write()
writefunc(ds3)
end
end
function tlshelper.closefunc(tls_ctx)
return function ()
tls_ctx:close()
end
end
function tlshelper.readfunc(fd, tls_ctx)
local readfunc = socket.readfunc(fd)
local read_buff = ""
return function (sz)
if not sz then
local s = ""
if #read_buff == 0 then
local ds = readfunc(sz)
s = tls_ctx:read(ds)
end
s = read_buff .. s
read_buff = ""
return s
else
while #read_buff < sz do
local ds = readfunc()
local s = tls_ctx:read(ds)
read_buff = read_buff .. s
end
local s = string.sub(read_buff, 1, sz)
read_buff = string.sub(read_buff, sz+1, #read_buff)
return s
end
end
end
function tlshelper.writefunc(fd, tls_ctx)
local writefunc = socket.writefunc(fd)
return function (s)
local ds = tls_ctx:write(s)
return writefunc(ds)
end
end
function tlshelper.readallfunc(fd, tls_ctx)
local readfunc = socket.readfunc(fd)
return function ()
local ds = socket.readall(fd)
local s = tls_ctx:read(ds)
return s
end
end
function tlshelper.newctx()
return c.newctx()
end
function tlshelper.newtls(method, ssl_ctx)
return c.newtls(method, ssl_ctx)
end
return tlshelper

507
lualib/http/websocket.lua Executable file
View File

@@ -0,0 +1,507 @@
local internal = require "http.internal"
local socket = require "skynet.socket"
local crypt = require "skynet.crypt"
local httpd = require "http.httpd"
local skynet = require "skynet"
local sockethelper = require "http.sockethelper"
local socket_error = sockethelper.socket_error
local GLOBAL_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
local MAX_FRAME_SIZE = 256 * 1024 -- max frame is 256K
local M = {}
local ws_pool = {}
local function _close_websocket(ws_obj)
local id = ws_obj.id
assert(ws_pool[id] == ws_obj)
ws_pool[id] = nil
ws_obj.close()
end
local function _isws_closed(id)
return not ws_pool[id]
end
local function write_handshake(self, host, url, header)
local key = crypt.base64encode(crypt.randomkey()..crypt.randomkey())
local request_header = {
["Upgrade"] = "websocket",
["Connection"] = "Upgrade",
["Sec-WebSocket-Version"] = "13",
["Sec-WebSocket-Key"] = key
}
if header then
for k,v in pairs(header) do
assert(request_header[k] == nil, k)
request_header[k] = v
end
end
local recvheader = {}
local code, body = internal.request(self, "GET", host, url, recvheader, request_header)
if code ~= 101 then
error(string.format("websocket handshake error: code[%s] info:%s", code, body))
end
if not recvheader["upgrade"] or recvheader["upgrade"]:lower() ~= "websocket" then
error("websocket handshake upgrade must websocket")
end
if not recvheader["connection"] or recvheader["connection"]:lower() ~= "upgrade" then
error("websocket handshake connection must upgrade")
end
local sw_key = recvheader["sec-websocket-accept"]
if not sw_key then
error("websocket handshake need Sec-WebSocket-Accept")
end
local guid = self.guid
sw_key = crypt.base64decode(sw_key)
if sw_key ~= crypt.sha1(key .. guid) then
error("websocket handshake invalid Sec-WebSocket-Accept")
end
end
local function read_handshake(self)
local tmpline = {}
local header_body = internal.recvheader(self.read, tmpline, "")
if not header_body then
return 413
end
local request = assert(tmpline[1])
local method, url, httpver = request:match "^(%a+)%s+(.-)%s+HTTP/([%d%.]+)$"
assert(method and url and httpver)
if method ~= "GET" then
return 400, "need GET method"
end
httpver = assert(tonumber(httpver))
if httpver < 1.1 then
return 505 -- HTTP Version not supported
end
local header = internal.parseheader(tmpline, 2, {})
if not header then
return 400 -- Bad request
end
if not header["upgrade"] or header["upgrade"]:lower() ~= "websocket" then
return 426, "Upgrade Required"
end
if not header["host"] then
return 400, "host Required"
end
if not header["connection"] or header["connection"]:lower() ~= "upgrade" then
return 400, "Connection must Upgrade"
end
local sw_key = header["sec-websocket-key"]
if not sw_key then
return 400, "Sec-WebSocket-Key Required"
else
local raw_key = crypt.base64decode(sw_key)
if #raw_key ~= 16 then
return 400, "Sec-WebSocket-Key invalid"
end
end
if not header["sec-websocket-version"] or header["sec-websocket-version"] ~= "13" then
return 400, "Sec-WebSocket-Version must 13"
end
local sw_protocol = header["sec-websocket-protocol"]
local sub_pro = ""
if sw_protocol then
local has_chat = false
for sub_protocol in string.gmatch(sw_protocol, "[^%s,]+") do
if sub_protocol == "chat" then
sub_pro = "Sec-WebSocket-Protocol: chat\r\n"
has_chat = true
break
end
end
if not has_chat then
return 400, "Sec-WebSocket-Protocol need include chat"
end
end
-- response handshake
local accept = crypt.base64encode(crypt.sha1(sw_key .. self.guid))
local resp = "HTTP/1.1 101 Switching Protocols\r\n"..
"Upgrade: websocket\r\n"..
"Connection: Upgrade\r\n"..
string.format("Sec-WebSocket-Accept: %s\r\n", accept)..
sub_pro ..
"\r\n"
self.write(resp)
return nil, header, url
end
local function try_handle(self, method, ...)
local handle = self.handle
local f = handle and handle[method]
if f then
f(self.id, ...)
end
end
local op_code = {
["frame"] = 0x00,
["text"] = 0x01,
["binary"] = 0x02,
["close"] = 0x08,
["ping"] = 0x09,
["pong"] = 0x0A,
[0x00] = "frame",
[0x01] = "text",
[0x02] = "binary",
[0x08] = "close",
[0x09] = "ping",
[0x0A] = "pong",
}
local function write_frame(self, op, payload_data, masking_key)
payload_data = payload_data or ""
local payload_len = #payload_data
local op_v = assert(op_code[op])
local v1 = 0x80 | op_v -- fin is 1 with opcode
local s
local mask = masking_key and 0x80 or 0x00
-- mask set to 0
if payload_len < 126 then
s = string.pack("I1I1", v1, mask | payload_len)
elseif payload_len < 0xffff then
s = string.pack("I1I1>I2", v1, mask | 126, payload_len)
else
s = string.pack("I1I1>I8", v1, mask | 127, payload_len)
end
self.write(s)
-- write masking_key
if masking_key then
s = string.pack(">I4", masking_key)
self.write(s)
payload_data = crypt.xor_str(payload_data, s)
end
if payload_len > 0 then
self.write(payload_data)
end
end
local function read_close(payload_data)
local code, reason
local payload_len = #payload_data
if payload_len > 2 then
local fmt = string.format(">I2c%d", payload_len - 2)
code, reason = string.unpack(fmt, payload_data)
end
return code, reason
end
local function read_frame(self)
local s = self.read(2)
local v1, v2 = string.unpack("I1I1", s)
local fin = (v1 & 0x80) ~= 0
-- unused flag
-- local rsv1 = (v1 & 0x40) ~= 0
-- local rsv2 = (v1 & 0x20) ~= 0
-- local rsv3 = (v1 & 0x10) ~= 0
local op = v1 & 0x0f
local mask = (v2 & 0x80) ~= 0
local payload_len = (v2 & 0x7f)
if payload_len == 126 then
s = self.read(2)
payload_len = string.unpack(">I2", s)
elseif payload_len == 127 then
s = self.read(8)
payload_len = string.unpack(">I8", s)
end
if self.mode == "server" and payload_len > MAX_FRAME_SIZE then
error("payload_len is too large")
end
-- print(string.format("fin:%s, op:%s, mask:%s, payload_len:%s", fin, op_code[op], mask, payload_len))
local masking_key = mask and self.read(4) or false
local payload_data = payload_len>0 and self.read(payload_len) or ""
payload_data = masking_key and crypt.xor_str(payload_data, masking_key) or payload_data
return fin, assert(op_code[op]), payload_data
end
local function resolve_accept(self)
try_handle(self, "connect")
local code, err, url = read_handshake(self)
if code then
local ok, s = httpd.write_response(self.write, code, err)
if not ok then
error(s)
end
end
local header = err
try_handle(self, "handshake", header, url)
local recv_count = 0
local recv_buf = {}
while true do
if _isws_closed(self.id) then
try_handle(self, "close")
return
end
local fin, op, payload_data = read_frame(self)
if op == "close" then
local code, reason = read_close(payload_data)
write_frame(self, "close")
try_handle(self, "close", code, reason)
break
elseif op == "ping" then
write_frame(self, "pong")
try_handle(self, "ping")
elseif op == "pong" then
try_handle(self, "pong")
else
if fin and #recv_buf == 0 then
try_handle(self, "message", payload_data)
else
recv_buf[#recv_buf+1] = payload_data
recv_count = recv_count + #payload_data
if recv_count > MAX_FRAME_SIZE then
error("payload_len is too large")
end
if fin then
local s = table.concat(recv_buf)
try_handle(self, "message", s)
recv_buf = {} -- clear recv_buf
recv_count = 0
end
end
end
end
end
local SSLCTX_CLIENT = nil
local function _new_client_ws(socket_id, protocol)
local obj
if protocol == "ws" then
obj = {
websocket = true,
close = function ()
socket.close(socket_id)
end,
read = sockethelper.readfunc(socket_id),
write = sockethelper.writefunc(socket_id),
readall = function ()
return socket.readall(socket_id)
end,
}
elseif protocol == "wss" then
local tls = require "http.tlshelper"
SSLCTX_CLIENT = SSLCTX_CLIENT or tls.newctx()
local tls_ctx = tls.newtls("client", SSLCTX_CLIENT)
local init = tls.init_requestfunc(socket_id, tls_ctx)
init()
obj = {
websocket = true,
close = function ()
socket.close(socket_id)
tls.closefunc(tls_ctx)()
end,
read = tls.readfunc(socket_id, tls_ctx),
write = tls.writefunc(socket_id, tls_ctx),
readall = tls.readallfunc(socket_id, tls_ctx),
}
else
error(string.format("invalid websocket protocol:%s", tostring(protocol)))
end
obj.mode = "client"
obj.id = assert(socket_id)
obj.guid = GLOBAL_GUID
ws_pool[socket_id] = obj
return obj
end
local SSLCTX_SERVER = nil
local function _new_server_ws(socket_id, handle, protocol)
local obj
if protocol == "ws" then
obj = {
close = function ()
socket.close(socket_id)
end,
read = sockethelper.readfunc(socket_id),
write = sockethelper.writefunc(socket_id),
}
elseif protocol == "wss" then
local tls = require "http.tlshelper"
if not SSLCTX_SERVER then
SSLCTX_SERVER = tls.newctx()
-- gen cert and key
-- openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-cert.pem
local certfile = skynet.getenv("certfile") or "./server-cert.pem"
local keyfile = skynet.getenv("keyfile") or "./server-key.pem"
SSLCTX_SERVER:set_cert(certfile, keyfile)
end
local tls_ctx = tls.newtls("server", SSLCTX_SERVER)
local init = tls.init_responsefunc(socket_id, tls_ctx)
init()
obj = {
close = function ()
socket.close(socket_id)
tls.closefunc(tls_ctx)()
end,
read = tls.readfunc(socket_id, tls_ctx),
write = tls.writefunc(socket_id, tls_ctx),
}
else
error(string.format("invalid websocket protocol:%s", tostring(protocol)))
end
obj.mode = "server"
obj.id = assert(socket_id)
obj.handle = handle
obj.guid = GLOBAL_GUID
ws_pool[socket_id] = obj
return obj
end
-- handle interface
-- connect / handshake / message / ping / pong / close / error
function M.accept(socket_id, handle, protocol, addr)
socket.start(socket_id)
protocol = protocol or "ws"
local ws_obj = _new_server_ws(socket_id, handle, protocol)
ws_obj.addr = addr
local on_warning = handle and handle["warning"]
if on_warning then
socket.warning(socket_id, function (id, sz)
on_warning(ws_obj, sz)
end)
end
local ok, err = xpcall(resolve_accept, debug.traceback, ws_obj)
local closed = _isws_closed(socket_id)
if not closed then
_close_websocket(ws_obj)
end
if not ok then
if err == socket_error then
if closed then
try_handle(ws_obj, "close")
else
try_handle(ws_obj, "error")
end
else
-- error(err)
return false, err
end
end
return true
end
function M.connect(url, header, timeout)
local protocol, host, uri = string.match(url, "^(wss?)://([^/]+)(.*)$")
if protocol ~= "wss" and protocol ~= "ws" then
error(string.format("invalid protocol: %s", protocol))
end
assert(host)
local host_name, host_port = string.match(host, "^([^:]+):?(%d*)$")
assert(host_name and host_port)
if host_port == "" then
host_port = protocol == "ws" and 80 or 443
end
uri = uri == "" and "/" or uri
local socket_id = sockethelper.connect(host_name, host_port, timeout)
local ws_obj = _new_client_ws(socket_id, protocol)
ws_obj.addr = host
write_handshake(ws_obj, host_name, uri, header)
return socket_id
end
function M.read(id)
local ws_obj = assert(ws_pool[id])
local recv_buf
while true do
local fin, op, payload_data = read_frame(ws_obj)
if op == "close" then
_close_websocket(ws_obj)
return false, payload_data
elseif op == "ping" then
write_frame(ws_obj, "pong")
elseif op ~= "pong" then -- op is frame, text binary
if fin and not recv_buf then
return payload_data
else
recv_buf = recv_buf or {}
recv_buf[#recv_buf+1] = payload_data
if fin then
local s = table.concat(recv_buf)
return s
end
end
end
end
assert(false)
end
function M.write(id, data, fmt, masking_key)
local ws_obj = assert(ws_pool[id])
fmt = fmt or "text"
assert(fmt == "text" or fmt == "binary")
write_frame(ws_obj, fmt, data, masking_key)
end
function M.ping(id)
local ws_obj = assert(ws_pool[id])
write_frame(ws_obj, "ping")
end
function M.addrinfo(id)
local ws_obj = assert(ws_pool[id])
return ws_obj.addr
end
function M.close(id, code ,reason)
local ws_obj = ws_pool[id]
if not ws_obj then
return
end
local ok, err = xpcall(function ()
reason = reason or ""
local payload_data
if code then
local fmt =string.format(">I2c%d", #reason)
payload_data = string.pack(fmt, code, reason)
end
write_frame(ws_obj, "close", payload_data)
end, debug.traceback)
_close_websocket(ws_obj)
if not ok then
skynet.error(err)
end
end
return M

View File

@@ -1,17 +1,27 @@
-- read https://github.com/cloudwu/skynet/wiki/FAQ for the module "skynet.core"
local c = require "skynet.core"
local tostring = tostring
local tonumber = tonumber
local coroutine = coroutine
local assert = assert
local pairs = pairs
local pcall = pcall
local table = table
local tremove = table.remove
local tinsert = table.insert
local traceback = debug.traceback
local profile = require "skynet.profile"
local coroutine_resume = profile.resume
local cresume = profile.resume
local running_thread = nil
local init_thread = nil
local function coroutine_resume(co, ...)
running_thread = co
return cresume(co, ...)
end
local coroutine_yield = profile.yield
local coroutine_create = coroutine.create
local proto = {}
local skynet = {
@@ -28,6 +38,7 @@ local skynet = {
PTYPE_DEBUG = 9,
PTYPE_LUA = 10,
PTYPE_SNAX = 11,
PTYPE_TRACE = 12, -- use for debug trace
}
-- code cache
@@ -45,29 +56,24 @@ end
local session_id_coroutine = {}
local session_coroutine_id = {}
local session_coroutine_address = {}
local session_response = {}
local session_coroutine_tracetag = {}
local unresponse = {}
local wakeup_queue = {}
local sleep_session = {}
local watching_service = {}
local watching_session = {}
local dead_service = {}
local error_queue = {}
local fork_queue = {}
-- suspend is function
local suspend
local function string_to_handle(str)
return tonumber("0x" .. string.sub(str , 2))
end
----- monitor exit
local function dispatch_error_queue()
local session = table.remove(error_queue,1)
local session = tremove(error_queue,1)
if session then
local co = session_id_coroutine[session]
session_id_coroutine[session] = nil
@@ -76,21 +82,23 @@ local function dispatch_error_queue()
end
local function _error_dispatch(error_session, error_source)
skynet.ignoreret() -- don't return for error
if error_session == 0 then
-- service is down
-- Don't remove from watching_service , because user may call dead service
if watching_service[error_source] then
dead_service[error_source] = true
-- error_source is down, clear unreponse set
for resp, address in pairs(unresponse) do
if error_source == address then
unresponse[resp] = nil
end
end
for session, srv in pairs(watching_session) do
if srv == error_source then
table.insert(error_queue, session)
tinsert(error_queue, session)
end
end
else
-- capture an error for error_session
if watching_session[error_session] then
table.insert(error_queue, error_session)
tinsert(error_queue, error_session)
end
end
end
@@ -100,179 +108,148 @@ end
local coroutine_pool = setmetatable({}, { __mode = "kv" })
local function co_create(f)
local co = table.remove(coroutine_pool)
local co = tremove(coroutine_pool)
if co == nil then
co = coroutine.create(function(...)
co = coroutine_create(function(...)
f(...)
while true do
local session = session_coroutine_id[co]
if session and session ~= 0 then
local source = debug.getinfo(f,"S")
skynet.error(string.format("Maybe forgot response session %s from %s : %s:%d",
session,
skynet.address(session_coroutine_address[co]),
source.source, source.linedefined))
end
-- coroutine exit
local tag = session_coroutine_tracetag[co]
if tag ~= nil then
if tag then c.trace(tag, "end") end
session_coroutine_tracetag[co] = nil
end
local address = session_coroutine_address[co]
if address then
session_coroutine_id[co] = nil
session_coroutine_address[co] = nil
end
-- recycle co into pool
f = nil
coroutine_pool[#coroutine_pool+1] = co
f = coroutine_yield "EXIT"
-- recv new main function f
f = coroutine_yield "SUSPEND"
f(coroutine_yield())
end
end)
else
-- pass the main function f to coroutine, and restore running thread
local running = running_thread
coroutine_resume(co, f)
running_thread = running
end
return co
end
local function dispatch_wakeup()
local co = table.remove(wakeup_queue,1)
if co then
local session = sleep_session[co]
local token = tremove(wakeup_queue,1)
if token then
local session = sleep_session[token]
if session then
local co = session_id_coroutine[session]
local tag = session_coroutine_tracetag[co]
if tag then c.trace(tag, "resume") end
session_id_coroutine[session] = "BREAK"
return suspend(co, coroutine_resume(co, false, "BREAK"))
end
end
end
local function release_watching(address)
local ref = watching_service[address]
if ref then
ref = ref - 1
if ref > 0 then
watching_service[address] = ref
else
watching_service[address] = nil
end
end
end
-- suspend is local function
function suspend(co, result, command, param, size)
function suspend(co, result, command)
if not result then
local session = session_coroutine_id[co]
if session then -- coroutine may fork by others (session is nil)
local addr = session_coroutine_address[co]
if session ~= 0 then
-- only call response error
local tag = session_coroutine_tracetag[co]
if tag then c.trace(tag, "error") end
c.send(addr, skynet.PTYPE_ERROR, session, "")
end
session_coroutine_id[co] = nil
session_coroutine_address[co] = nil
end
error(debug.traceback(co,tostring(command)))
session_coroutine_address[co] = nil
session_coroutine_tracetag[co] = nil
skynet.fork(function() end) -- trigger command "SUSPEND"
error(traceback(co,tostring(command)))
end
if command == "CALL" then
session_id_coroutine[param] = co
elseif command == "SLEEP" then
session_id_coroutine[param] = co
sleep_session[co] = param
elseif command == "RETURN" then
local co_session = session_coroutine_id[co]
if co_session == 0 then
if size ~= nil then
c.trash(param, size)
end
return suspend(co, coroutine_resume(co, false)) -- send don't need ret
end
local co_address = session_coroutine_address[co]
if param == nil or session_response[co] then
error(debug.traceback(co))
end
session_response[co] = true
local ret
if not dead_service[co_address] then
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, param, size) ~= nil
if not ret then
-- If the package is too large, returns nil. so we should report error back
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
end
elseif size ~= nil then
c.trash(param, size)
ret = false
end
return suspend(co, coroutine_resume(co, ret))
elseif command == "RESPONSE" then
local co_session = session_coroutine_id[co]
local co_address = session_coroutine_address[co]
if session_response[co] then
error(debug.traceback(co))
end
local f = param
local function response(ok, ...)
if ok == "TEST" then
if dead_service[co_address] then
release_watching(co_address)
unresponse[response] = nil
f = false
return false
else
return true
end
end
if not f then
if f == false then
f = nil
return false
end
error "Can't response more than once"
end
local ret
-- do not response when session == 0 (send)
if co_session ~= 0 and not dead_service[co_address] then
if ok then
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, f(...)) ~= nil
if not ret then
-- If the package is too large, returns false. so we should report error back
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
end
else
ret = c.send(co_address, skynet.PTYPE_ERROR, co_session, "") ~= nil
end
else
ret = false
end
release_watching(co_address)
unresponse[response] = nil
f = nil
return ret
end
watching_service[co_address] = watching_service[co_address] + 1
session_response[co] = true
unresponse[response] = true
return suspend(co, coroutine_resume(co, response))
elseif command == "EXIT" then
-- coroutine exit
local address = session_coroutine_address[co]
if address then
release_watching(address)
session_coroutine_id[co] = nil
session_coroutine_address[co] = nil
session_response[co] = nil
end
if command == "SUSPEND" then
dispatch_wakeup()
dispatch_error_queue()
elseif command == "QUIT" then
-- service exit
return
elseif command == "USER" then
-- See skynet.coutine for detail
error("Call skynet.coroutine.yield out of skynet.coroutine.resume\n" .. debug.traceback(co))
error("Call skynet.coroutine.yield out of skynet.coroutine.resume\n" .. traceback(co))
elseif command == nil then
-- debug trace
return
else
error("Unknown command : " .. command .. "\n" .. debug.traceback(co))
error("Unknown command : " .. command .. "\n" .. traceback(co))
end
dispatch_wakeup()
dispatch_error_queue()
end
local co_create_for_timeout
local timeout_traceback
function skynet.trace_timeout(on)
local function trace_coroutine(func, ti)
local co
co = co_create(function()
timeout_traceback[co] = nil
func()
end)
local info = string.format("TIMER %d+%d : ", skynet.now(), ti)
timeout_traceback[co] = traceback(info, 3)
return co
end
if on then
timeout_traceback = timeout_traceback or {}
co_create_for_timeout = trace_coroutine
else
timeout_traceback = nil
co_create_for_timeout = co_create
end
end
skynet.trace_timeout(false) -- turn off by default
function skynet.timeout(ti, func)
local session = c.intcommand("TIMEOUT",ti)
assert(session)
local co = co_create(func)
local co = co_create_for_timeout(func, ti)
assert(session_id_coroutine[session] == nil)
session_id_coroutine[session] = co
return co -- for debug
end
function skynet.sleep(ti)
local function suspend_sleep(session, token)
local tag = session_coroutine_tracetag[running_thread]
if tag then c.trace(tag, "sleep", 2) end
session_id_coroutine[session] = running_thread
assert(sleep_session[token] == nil, "token duplicative")
sleep_session[token] = session
return coroutine_yield "SUSPEND"
end
function skynet.sleep(ti, token)
local session = c.intcommand("TIMEOUT",ti)
assert(session)
local succ, ret = coroutine_yield("SLEEP", session)
sleep_session[coroutine.running()] = nil
token = token or coroutine.running()
local succ, ret = suspend_sleep(session, token)
sleep_session[token] = nil
if succ then
return
end
@@ -287,31 +264,46 @@ function skynet.yield()
return skynet.sleep(0)
end
function skynet.wait(co)
function skynet.wait(token)
local session = c.genid()
local ret, msg = coroutine_yield("SLEEP", session)
co = co or coroutine.running()
sleep_session[co] = nil
token = token or coroutine.running()
local ret, msg = suspend_sleep(session, token)
sleep_session[token] = nil
session_id_coroutine[session] = nil
end
local self_handle
function skynet.self()
if self_handle then
return self_handle
end
self_handle = string_to_handle(c.command("REG"))
return self_handle
return c.addresscommand "REG"
end
function skynet.localname(name)
local addr = c.command("QUERY", name)
if addr then
return string_to_handle(addr)
end
return c.addresscommand("QUERY", name)
end
skynet.now = c.now
skynet.hpc = c.hpc -- high performance counter
local traceid = 0
function skynet.trace(info)
skynet.error("TRACE", session_coroutine_tracetag[running_thread])
if session_coroutine_tracetag[running_thread] == false then
-- force off trace log
return
end
traceid = traceid + 1
local tag = string.format(":%08x-%d",skynet.self(), traceid)
session_coroutine_tracetag[running_thread] = tag
if info then
c.trace(tag, "trace " .. info)
else
c.trace(tag, "trace")
end
end
function skynet.tracetag()
return session_coroutine_tracetag[running_thread]
end
local starttime
@@ -385,7 +377,8 @@ skynet.trash = assert(c.trash)
local function yield_call(service, session)
watching_session[session] = service
local succ, msg, sz = coroutine_yield("CALL", session)
session_id_coroutine[session] = running_thread
local succ, msg, sz = coroutine_yield "SUSPEND"
watching_session[session] = nil
if not succ then
error "call failed"
@@ -394,6 +387,12 @@ local function yield_call(service, session)
end
function skynet.call(addr, typename, ...)
local tag = session_coroutine_tracetag[running_thread]
if tag then
c.trace(tag, "call", 2)
c.send(addr, skynet.PTYPE_TRACE, 0, tag)
end
local p = proto[typename]
local session = c.send(addr, p.id , nil , p.pack(...))
if session == nil then
@@ -403,28 +402,112 @@ function skynet.call(addr, typename, ...)
end
function skynet.rawcall(addr, typename, msg, sz)
local tag = session_coroutine_tracetag[running_thread]
if tag then
c.trace(tag, "call", 2)
c.send(addr, skynet.PTYPE_TRACE, 0, tag)
end
local p = proto[typename]
local session = assert(c.send(addr, p.id , nil , msg, sz), "call to invalid address")
return yield_call(addr, session)
end
function skynet.tracecall(tag, addr, typename, msg, sz)
c.trace(tag, "tracecall begin")
c.send(addr, skynet.PTYPE_TRACE, 0, tag)
local p = proto[typename]
local session = assert(c.send(addr, p.id , nil , msg, sz), "call to invalid address")
local msg, sz = yield_call(addr, session)
c.trace(tag, "tracecall end")
return msg, sz
end
function skynet.ret(msg, sz)
msg = msg or ""
return coroutine_yield("RETURN", msg, sz)
local tag = session_coroutine_tracetag[running_thread]
if tag then c.trace(tag, "response") end
local co_session = session_coroutine_id[running_thread]
session_coroutine_id[running_thread] = nil
if co_session == 0 then
if sz ~= nil then
c.trash(msg, sz)
end
return false -- send don't need ret
end
local co_address = session_coroutine_address[running_thread]
if not co_session then
error "No session"
end
local ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, msg, sz)
if ret then
return true
elseif ret == false then
-- If the package is too large, returns false. so we should report error back
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
end
return false
end
function skynet.context()
local co_session = session_coroutine_id[running_thread]
local co_address = session_coroutine_address[running_thread]
return co_session, co_address
end
function skynet.ignoreret()
-- We use session for other uses
session_coroutine_id[running_thread] = nil
end
function skynet.response(pack)
pack = pack or skynet.pack
return coroutine_yield("RESPONSE", pack)
local co_session = assert(session_coroutine_id[running_thread], "no session")
session_coroutine_id[running_thread] = nil
local co_address = session_coroutine_address[running_thread]
if co_session == 0 then
-- do not response when session == 0 (send)
return function() end
end
local function response(ok, ...)
if ok == "TEST" then
return unresponse[response] ~= nil
end
if not pack then
error "Can't response more than once"
end
local ret
if unresponse[response] then
if ok then
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, pack(...))
if ret == false then
-- If the package is too large, returns false. so we should report error back
c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
end
else
ret = c.send(co_address, skynet.PTYPE_ERROR, co_session, "")
end
unresponse[response] = nil
ret = ret ~= nil
else
ret = false
end
pack = nil
return ret
end
unresponse[response] = co_address
return response
end
function skynet.retpack(...)
return skynet.ret(skynet.pack(...))
end
function skynet.wakeup(co)
if sleep_session[co] then
table.insert(wakeup_queue, co)
function skynet.wakeup(token)
if sleep_session[token] then
tinsert(wakeup_queue, token)
return true
end
end
@@ -463,14 +546,20 @@ function skynet.dispatch_unknown_response(unknown)
end
function skynet.fork(func,...)
local args = table.pack(...)
local co = co_create(function()
func(table.unpack(args,1,args.n))
end)
table.insert(fork_queue, co)
local n = select("#", ...)
local co
if n == 0 then
co = co_create(func)
else
local args = { ... }
co = co_create(function() func(table.unpack(args,1,n)) end)
end
tinsert(fork_queue, co)
return co
end
local trace_source = {}
local function raw_dispatch_message(prototype, msg, sz, session, source)
-- skynet.PTYPE_RESPONSE = 1, read skynet.h
if prototype == 1 then
@@ -480,35 +569,55 @@ local function raw_dispatch_message(prototype, msg, sz, session, source)
elseif co == nil then
unknown_response(session, source, msg, sz)
else
local tag = session_coroutine_tracetag[co]
if tag then c.trace(tag, "resume") end
session_id_coroutine[session] = nil
suspend(co, coroutine_resume(co, true, msg, sz))
end
else
local p = proto[prototype]
if p == nil then
if session ~= 0 then
if prototype == skynet.PTYPE_TRACE then
-- trace next request
trace_source[source] = c.tostring(msg,sz)
elseif session ~= 0 then
c.send(source, skynet.PTYPE_ERROR, session, "")
else
unknown_request(session, source, msg, sz, prototype)
end
return
end
local f = p.dispatch
if f then
local ref = watching_service[source]
if ref then
watching_service[source] = ref + 1
else
watching_service[source] = 1
end
local co = co_create(f)
session_coroutine_id[co] = session
session_coroutine_address[co] = source
local traceflag = p.trace
if traceflag == false then
-- force off
trace_source[source] = nil
session_coroutine_tracetag[co] = false
else
local tag = trace_source[source]
if tag then
trace_source[source] = nil
c.trace(tag, "request")
session_coroutine_tracetag[co] = tag
elseif traceflag then
-- set running_thread for trace
running_thread = co
skynet.trace()
end
end
suspend(co, coroutine_resume(co, session,source, p.unpack(msg,sz)))
elseif session ~= 0 then
c.send(source, skynet.PTYPE_ERROR, session, "")
else
unknown_request(session, source, msg, sz, proto[prototype].name)
trace_source[source] = nil
if session ~= 0 then
c.send(source, skynet.PTYPE_ERROR, session, "")
else
unknown_request(session, source, msg, sz, proto[prototype].name)
end
end
end
end
@@ -516,11 +625,10 @@ end
function skynet.dispatch_message(...)
local succ, err = pcall(raw_dispatch_message,...)
while true do
local key,co = next(fork_queue)
local co = tremove(fork_queue,1)
if co == nil then
break
end
fork_queue[key] = nil
local fork_succ, fork_err = pcall(suspend,co,coroutine_resume(co))
if not fork_succ then
if succ then
@@ -567,6 +675,15 @@ function skynet.harbor(addr)
end
skynet.error = c.error
skynet.tracelog = c.trace
-- true: force on
-- false: force off
-- nil: optional (use skynet.trace() to trace one message)
function skynet.traceproto(prototype, flag)
local p = assert(proto[prototype])
p.trace = flag
end
----- register protocol
do
@@ -599,7 +716,7 @@ function skynet.init(f, name)
if init_func == nil then
f()
else
table.insert(init_func, f)
tinsert(init_func, f)
if name then
assert(type(name) == "string")
assert(init_func[name] == nil)
@@ -630,7 +747,7 @@ local function init_template(start, ...)
end
function skynet.pcall(start, ...)
return xpcall(init_template, debug.traceback, start, ...)
return xpcall(init_template, traceback, start, ...)
end
function skynet.init_service(start)
@@ -646,8 +763,9 @@ end
function skynet.start(start_func)
c.callback(skynet.dispatch_message)
skynet.timeout(0, function()
init_thread = skynet.timeout(0, function()
skynet.init_service(start_func)
init_thread = nil
end)
end
@@ -664,14 +782,69 @@ function skynet.stat(what)
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)
if ret == nil then
local t = 0
for session,co in pairs(session_id_coroutine) do
t = t + 1
end
t = t + 1
return t
end
return t
if ret == "init" then
if init_thread then
return traceback(init_thread)
else
return
end
end
local tt = type(ret)
if tt == "table" then
for session,co in pairs(session_id_coroutine) do
if timeout_traceback and timeout_traceback[co] then
ret[session] = timeout_traceback[co]
else
ret[session] = traceback(co)
end
end
return
elseif tt == "number" then
local co = session_id_coroutine[ret]
if co then
return traceback(co)
else
return "No session"
end
elseif tt == "thread" then
for session, co in pairs(session_id_coroutine) do
if co == ret then
return session
end
end
return
end
end
function skynet.uniqtask()
local stacks = {}
for session, co in pairs(session_id_coroutine) do
local stack = traceback(co)
local info = stacks[stack] or {count = 0, sessions = {}}
info.count = info.count + 1
if info.count < 10 then
info.sessions[#info.sessions+1] = session
end
stacks[stack] = info
end
local ret = {}
for stack, info in pairs(stacks) do
local count = info.count
local sessions = table.concat(info.sessions, ",")
if count > 10 then
sessions = sessions .. "..."
end
local head_line = string.format("%d\tsessions:[%s]\n", count, sessions)
ret[head_line] = stack
end
return ret
end
function skynet.term(service)

View File

@@ -2,15 +2,68 @@ local skynet = require "skynet"
local clusterd
local cluster = {}
local sender = {}
local task_queue = {}
local function request_sender(q, node)
local ok, c = pcall(skynet.call, clusterd, "lua", "sender", node)
if not ok then
skynet.error(c)
c = nil
end
-- run tasks in queue
local confirm = coroutine.running()
q.confirm = confirm
q.sender = c
for _, task in ipairs(q) do
if type(task) == "table" then
if c then
skynet.send(c, "lua", "push", task[1], skynet.pack(table.unpack(task,2,task.n)))
end
else
skynet.wakeup(task)
skynet.wait(confirm)
end
end
task_queue[node] = nil
sender[node] = c
end
local function get_queue(t, node)
local q = {}
t[node] = q
skynet.fork(request_sender, q, node)
return q
end
setmetatable(task_queue, { __index = get_queue } )
local function get_sender(node)
local s = sender[node]
if not s then
local q = task_queue[node]
local task = coroutine.running()
table.insert(q, task)
skynet.wait(task)
skynet.wakeup(q.confirm)
return q.sender
end
return s
end
function cluster.call(node, address, ...)
-- skynet.pack(...) will free by cluster.core.packrequest
return skynet.call(clusterd, "lua", "req", node, address, skynet.pack(...))
return skynet.call(get_sender(node), "lua", "req", address, skynet.pack(...))
end
function cluster.send(node, address, ...)
-- push is the same with req, but no response
skynet.send(clusterd, "lua", "push", node, address, skynet.pack(...))
local s = sender[node]
if not s then
table.insert(task_queue[node], table.pack(address, ...))
else
skynet.send(sender[node], "lua", "push", address, skynet.pack(...))
end
end
function cluster.open(port)
@@ -45,7 +98,7 @@ function cluster.register(name, addr)
end
function cluster.query(node, name)
return skynet.call(clusterd, "lua", "req", node, 0, skynet.pack(name))
return skynet.call(get_sender(node), "lua", "req", 0, skynet.pack(name))
end
skynet.init(function()

View File

@@ -69,8 +69,15 @@ local skynet = require "skynet"
local datasheet = {}
local handles = {} -- handle:{ ref:count , name:name , collect:resp }
local dataset = {} -- name:{ handle:handle, monitor:{monitors queue} }
local customers = {} -- source: { handle:true }
local function releasehandle(handle)
setmetatable(customers, { __index = function(c, source)
local v = {}
c[source] = v
return v
end } )
local function releasehandle(source, handle)
local h = handles[handle]
h.ref = h.ref - 1
if h.ref == 0 and h.collect then
@@ -78,10 +85,12 @@ local function releasehandle(handle)
h.collect = nil
handles[handle] = nil
end
local t=dataset[h.name]
t.monitor[source]=nil
end
-- from builder, create or update handle
function datasheet.update(name, handle)
function datasheet.update(source, name, handle)
local t = dataset[name]
if not t then
-- new datasheet
@@ -89,11 +98,11 @@ function datasheet.update(name, handle)
dataset[name] = t
handles[handle] = { ref = 1, name = name }
else
t.handle = handle
-- report update to customers
handles[handle] = { ref = 1 + #t.monitor, name = name }
handles[handle] = { ref = handles[t.handle].ref, name = name }
t.handle = handle
for k,v in ipairs(t.monitor) do
for k,v in pairs(t.monitor) do
v(true, handle)
t.monitor[k] = nil
end
@@ -102,34 +111,51 @@ function datasheet.update(name, handle)
end
-- from customers
function datasheet.query(name)
function datasheet.query(source, name)
local t = assert(dataset[name], "create data first")
local handle = t.handle
local h = handles[handle]
h.ref = h.ref + 1
customers[source][handle] = true
skynet.ret(skynet.pack(handle))
end
-- from customers, monitor handle change
function datasheet.monitor(handle)
function datasheet.monitor(source, handle)
local h = assert(handles[handle], "Invalid data handle")
local t = dataset[h.name]
if t.handle ~= handle then -- already changes
customers[source][t.handle] = true
skynet.ret(skynet.pack(t.handle))
else
h.ref = h.ref + 1
table.insert(t.monitor, skynet.response())
assert(not t.monitor[source])
local resp = skynet.response()
t.monitor[source]= function(ok, handle)
if ok then
customers[source][handle] = true
end
resp(ok, handle)
end
end
end
-- from customers, release handle , ref count - 1
function datasheet.release(handle)
function datasheet.release(source, handle)
-- send message, don't ret
releasehandle(handle)
customers[source][handle] = nil
releasehandle(source, handle)
end
-- customer closed, clear all handles it queried
function datasheet.close(source)
for handle in pairs(customers[source]) do
releasehandle(source, handle)
end
customers[source] = nil
end
-- from builder, monitor handle release
function datasheet.collect(handle)
function datasheet.collect(source, handle)
local h = assert(handles[handle], "Invalid data handle")
if h.ref == 0 then
handles[handle] = nil
@@ -140,8 +166,8 @@ function datasheet.collect(handle)
end
end
skynet.dispatch("lua", function(_,_,cmd,...)
datasheet[cmd](...)
skynet.dispatch("lua", function(_,source,cmd,...)
datasheet[cmd](source,...)
end)
skynet.info_func(function()
@@ -155,7 +181,7 @@ skynet.info_func(function()
tmp[v.handle] = nil
info[k] = {
handle = v.handle,
monitors = #v.monitor,
monitors = h.ref,
}
end
for k,v in pairs(tmp) do

View File

@@ -59,7 +59,7 @@ function ctd.dump(root)
local index = dump_table(v)
return '\4', string.pack("<i4", index-1)
elseif t == "number" then
if math.tointeger(v) then
if math.tointeger(v) and v <= 0x7FFFFFFF and v >= -(0x7FFFFFFF+1) then
return '\1', string.pack("<i4", v)
else
return '\2', string.pack("<f",v)

View File

@@ -11,9 +11,7 @@ end)
local datasheet = {}
local sheets = setmetatable({}, {
__gc = function(t)
for _,v in pairs(t) do
skynet.send(datasheet_svr, "lua", "release", v.handle)
end
skynet.send(datasheet_svr, "lua", "close")
end,
})
@@ -32,7 +30,7 @@ local function updateobject(name)
core.update(t.object, newhandle)
t.handle = newhandle
skynet.send(datasheet_svr, "lua", "release", handle)
skynet.fork(monitor)
return monitor()
end
skynet.fork(monitor)
end

View File

@@ -82,18 +82,24 @@ local function __parse_addr(addr)
return host, tonumber(port)
end
local auth_method = {}
local function mongo_auth(mongoc)
local user = rawget(mongoc, "username")
local pass = rawget(mongoc, "password")
local authmod = rawget(mongoc, "authmod") or "scram_sha1"
authmod = "auth_" .. authmod
local authdb = rawget(mongoc, "authdb")
if authdb then
authdb = mongo_client.getDB(mongoc, authdb) -- mongoc has not set metatable yet
end
return function()
if user ~= nil and pass ~= nil then
-- autmod can be "mongodb_cr" or "scram_sha1"
local auth_func = mongoc[authmod]
local auth_func = auth_method[authmod]
assert(auth_func , "Invalid authmod")
assert(auth_func(mongoc,user, pass))
assert(auth_func(authdb or mongoc, user, pass))
end
local rs_data = mongoc:runCommand("ismaster")
if rs_data.ok == 1 then
@@ -156,6 +162,7 @@ function mongo.client( conf )
username = first.username,
password = first.password,
authmod = first.authmod,
authdb = first.authdb,
}
obj.__id = 0
@@ -166,6 +173,7 @@ function mongo.client( conf )
auth = mongo_auth(obj),
backup = backup,
nodelay = true,
overload = conf.overload,
}
setmetatable(obj, client_meta)
obj.__sock:connect(true) -- try connect only once
@@ -206,7 +214,7 @@ function mongo_client:runCommand(...)
return self.admin:runCommand(...)
end
function mongo_client:auth_mongodb_cr(user,password)
function auth_method:auth_mongodb_cr(user,password)
local password = md5.sumhexa(string.format("%s:mongo:%s",user,password))
local result= self:runCommand "getnonce"
if result.ok ~=1 then
@@ -229,7 +237,7 @@ local function salt_password(password, salt, iter)
return output
end
function mongo_client:auth_scram_sha1(username,password)
function auth_method:auth_scram_sha1(username,password)
local user = string.gsub(string.gsub(username, '=', '=3D'), ',' , '=2C')
local nonce = crypt.base64encode(crypt.randomkey())
local first_bare = "n=" .. user .. ",r=" .. nonce
@@ -300,6 +308,13 @@ function mongo_client:logout()
return result.ok == 1
end
function mongo_db:auth(user, pass)
local authmod = rawget(self.connection, "authmod") or "scram_sha1"
local auth_func = auth_method["auth_" .. authmod]
assert(auth_func , "Invalid authmod")
return auth_func(self, user, pass)
end
function mongo_db:runCommand(cmd,cmd_v,...)
local conn = self.connection
local request_id = conn:genId()
@@ -340,8 +355,23 @@ function mongo_collection:insert(doc)
sock:request(pack)
end
local function werror(r)
local ok = (r.ok == 1 and not r.writeErrors and not r.writeConcernError)
local err
if not ok then
if r.writeErrors then
err = r.writeErrors[1].errmsg
else
err = r.writeConcernError.errmsg
end
end
return ok, err, r
end
function mongo_collection:safe_insert(doc)
return self.database:runCommand("insert", self.name, "documents", {bson_encode(doc)})
local r = self.database:runCommand("insert", self.name, "documents", {bson_encode(doc)})
return werror(r)
end
function mongo_collection:batch_insert(docs)
@@ -363,12 +393,30 @@ function mongo_collection:update(selector,update,upsert,multi)
sock:request(pack)
end
function mongo_collection:safe_update(selector, update, upsert, multi)
local r = self.database:runCommand("update", self.name, "updates", {bson_encode({
q = selector,
u = update,
upsert = upsert,
multi = multi,
})})
return werror(r)
end
function mongo_collection:delete(selector, single)
local sock = self.connection.__sock
local pack = driver.delete(self.full_name, single, bson_encode(selector))
sock:request(pack)
end
function mongo_collection:safe_delete(selector, single)
local r = self.database:runCommand("delete", self.name, "deletes", {bson_encode({
q = selector,
limit = single and 1 or 0,
})})
return werror(r)
end
function mongo_collection:findOne(query, selector)
local conn = self.connection
local request_id = conn:genId()
@@ -574,10 +622,20 @@ function mongo_cursor:hasNext()
if ok then
if doc then
self.__document = result.result
local doc = result.result
self.__document = doc
self.__data = result.data
self.__ptr = 1
self.__cursor = cursor
local limit = self.__limit
if cursor and limit > 0 then
limit = limit - #doc
if limit <= 0 then
-- reach limit
self:close()
end
self.__limit = limit
end
return true
else
self.__document = nil
@@ -615,11 +673,11 @@ function mongo_cursor:next()
end
function mongo_cursor:close()
-- todo: warning hasNext after close
if self.__cursor then
local sock = self.__collection.connection.__sock
local pack = driver.kill(self.__cursor)
sock:request(pack)
self.__cursor = nil
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -143,6 +143,7 @@ function redis.connect(db_conf)
port = db_conf.port or 6379,
auth = redis_login(db_conf.auth, db_conf.db),
nodelay = true,
overload = db_conf.overload,
}
-- try connect first only once
channel:connect(true)

View File

@@ -8,24 +8,60 @@ local crc16 = require "skynet.db.redis.crc16"
local RedisClusterHashSlots = 16384
local RedisClusterRequestTTL = 16
local sync = {
once = {
tasks = {},
}
}
function sync.once.Do(id,func,...)
local tasks = sync.once.tasks
local task = tasks[id]
if not task then
task = {
waiting = {},
result = nil,
}
tasks[id] = task
local rettbl = table.pack(xpcall(func,debug.traceback,...))
task.result = rettbl
local waiting = task.waiting
tasks[id] = nil
if next(waiting) then
for i,co in ipairs(waiting) do
skynet.wakeup(co)
end
end
return table.unpack(task.result,1,task.result.n)
else
local co = coroutine.running()
table.insert(task.waiting,co)
skynet.wait(co)
return table.unpack(task.result,1,task.result.n)
end
end
local _M = {}
local rediscluster = {}
rediscluster.__index = rediscluster
_M.rediscluster = rediscluster
function _M.new(startup_nodes,opt)
function _M.new(startup_nodes,opt,onmessage)
if #startup_nodes == 0 then
startup_nodes = {startup_nodes,}
end
opt = opt or {}
local self = {
startup_nodes = startup_nodes,
max_connections = opt.max_connections or 16,
connections = setmetatable({},{__mode = "kv"}),
max_connections = opt.max_connections or 256,
connections = {},
opt = opt,
refresh_table_asap = false,
-- for subscribe/publish
__onmessage = onmessage,
__watching = {},
}
setmetatable(self,rediscluster)
self:initialize_slots_cache()
@@ -53,13 +89,6 @@ function rediscluster:set_node_name(node)
if not node.name then
node.name = nodename(node)
end
if not node.slaves then
local oldnode = self.name_node[node.name]
if oldnode then
node.slaves = oldnode.slaves
end
end
self.name_node[node.name] = node
end
-- Contact the startup nodes and try to fetch the hash slots -> instances
@@ -67,11 +96,9 @@ end
function rediscluster:initialize_slots_cache()
self.slots = {}
self.nodes = {}
self.name_node = {}
for _,startup_node in ipairs(self.startup_nodes) do
local ok = pcall(function ()
local name = nodename(startup_node)
local conn = self.connections[name] or self:get_redis_link(startup_node)
local conn = self:get_connection(startup_node)
local list = conn:cluster("slots")
for _,result in ipairs(list) do
local ip,port = table.unpack(result[3])
@@ -100,9 +127,6 @@ function rediscluster:initialize_slots_cache()
end
end
self.refresh_table_asap = false
if not self.connections[name] then
self.connections[name] = conn
end
end)
-- Exit the loop as long as the first node replies
if ok then
@@ -154,6 +178,21 @@ function rediscluster:get_key_from_command(argv)
cmd == "shutdown" then
return nil
end
if cmd == "eval" or cmd == "evalsha" then
-- eval script numkeys key [key...] arg [arg...]
local numkeys = argv[3]
local firstkey_slot = nil
for i=4,4+numkeys-1 do
local slot = self:keyslot(argv[i])
if not firstkey_slot then
firstkey_slot = slot
elseif firstkey_slot ~= slot then
error(string.format("%s - all keys must map to the same key slot",cmd))
end
end
-- numkeys <=0 will return nil
return argv[4]
end
-- Unknown commands, and all the commands having the key
-- as first argument are handled here:
-- set, get, ...
@@ -179,21 +218,28 @@ end
function rediscluster:close_all_connection()
local connections = self.connections
self.connections = setmetatable({},{__mode = "kv"})
self.connections = {}
for name,conn in pairs(connections) do
pcall(conn.disconnect,conn)
end
end
function rediscluster:get_connection(node)
node.port = assert(tonumber(node.port))
local name = node.name or nodename(node)
local conn = self.connections[name]
if not conn then
conn = self:get_redis_link(node)
self.connections[name] = conn
if not node.name then
node.name = nodename(node)
end
return self.connections[name]
local name = node.name
local ok,conn = sync.once.Do(name,function ()
local conn = self.connections[name]
if not conn then
self:close_existing_connection()
conn = self:get_redis_link(node)
self.connections[name] = conn
end
return conn
end)
assert(ok,conn)
return conn
end
-- Return a link to a random node, or raise an error if no node can be
@@ -219,25 +265,15 @@ function rediscluster:get_random_connection()
for i,idx in ipairs(shuffle_idx) do
local ok,conn = pcall(function ()
local node = self.nodes[idx]
local conn = self.connections[node.name]
if not conn then
-- Connect the node if it is not connected
conn = self:get_redis_link(node)
if conn:ping() == "PONG" then
self:close_existing_connection()
self.connections[node.name] = conn
return conn
else
-- If the connection is not good close it ASAP in order
-- to avoid waiting for the GC finalizer. File
-- descriptors are a rare resource.
conn:disconnect()
end
local conn = self:get_connection(node)
if conn:ping() == "PONG" then
return conn
else
-- The node was already connected, test the connection.
if conn:ping() == "PONG" then
return conn
end
-- If the connection is not good close it ASAP in order
-- to avoid waiting for the GC finalizer. File
-- descriptors are a rare resource.
self.connetions[node.name] = nil
conn:disconnect()
end
end)
if ok and conn then
@@ -256,33 +292,40 @@ function rediscluster:get_connection_by_slot(slot)
if not node then
return self:get_random_connection()
end
if not self.connections[node.name] then
local ok = pcall(function ()
self:close_existing_connection()
self.connections[node.name] = self:get_redis_link(node)
end)
if not ok then
if self.opt.read_slave and node.slaves and #node.slaves > 0 then
local slave_node = node.slaves[math.random(1,#node.slaves)]
local ok2,conn = pcall(self.get_connection,self,slave_node)
if ok2 then
conn:readonly() -- allow this connection read-slave
return conn
end
local ok,conn = pcall(self.get_connection,self,node)
if not ok then
if self.opt.read_slave and node.slaves and #node.slaves > 0 then
local slave_node = node.slaves[math.random(1,#node.slaves)]
local ok2,conn = pcall(self.get_connection,self,slave_node)
if ok2 then
conn:readonly() -- allow this connection read-slave
return conn
end
-- This will probably never happen with recent redis-rb
-- versions because the connection is enstablished in a lazy
-- way only when a command is called. However it is wise to
-- handle an instance creation error of some kind.
return self:get_random_connection()
end
-- This will probably never happen with recent redis-rb
-- versions because the connection is enstablished in a lazy
-- way only when a command is called. However it is wise to
-- handle an instance creation error of some kind.
return self:get_random_connection()
end
return self.connections[node.name]
return conn
end
-- Dispatch commands.
function rediscluster:call(...)
local argv = table.pack(...)
local cmd = argv[1]
local key = self:get_key_from_command(argv)
if not key then
error("No way to dispatch this command to Redis Cluster: " .. tostring(argv[1]))
end
if cmd == "subscribe" or cmd == "unsubscribe" or cmd == "psubscribe" or cmd == "punsubscribe" then
local slot = self:keyslot(key)
local conn = self:get_watch_connection_by_slot(slot)
local func = conn[cmd]
return func(conn,table.unpack(argv,2))
end
if self.refresh_table_asap then
self:initialize_slots_cache()
end
@@ -292,10 +335,6 @@ function rediscluster:call(...)
local try_random_node = false
while ttl > 0 do
ttl = ttl - 1
local key = self:get_key_from_command(argv)
if not key then
error("No way to dispatch this command to Redis Cluster: " .. tostring(argv[1]))
end
local conn
local slot = self:keyslot(key)
if asking then
@@ -312,7 +351,6 @@ function rediscluster:call(...)
conn:asking()
end
asking = false
local cmd = argv[1]
local func = conn[cmd]
return func(conn,table.unpack(argv,2))
end)}
@@ -321,7 +359,7 @@ function rediscluster:call(...)
err = table.unpack(result,2)
err = tostring(err)
if err == "[Error: socket]" then
-- may be nerver come here?
-- may be never come here?
try_random_node = true
if ttl < RedisClusterRequestTTL/2 then
skynet.sleep(10)
@@ -351,6 +389,10 @@ function rediscluster:call(...)
port = node_port,
}
if not asking then
local oldnode = self.slots[newslot]
if oldnode then
node.slaves = oldnode.slaves
end
self:set_node_name(node)
self.slots[newslot] = node
else
@@ -365,6 +407,44 @@ function rediscluster:call(...)
error(string.format("Too many Cluster redirections?,maybe node is disconnected (last error: %q)",err))
end
function rediscluster:get_watch_connection_by_slot(slot)
if not self.slots[slot] then
self:initialize_slots_cache()
end
local node = assert(self.slots[slot])
return self:get_watch_connection(node)
end
function rediscluster:get_watch_connection(node)
local name = node.name
local ok,conn = sync.once.Do(name,function ()
if not self.__watching[name] then
local conf = {
host = node.host,
port = node.port,
auth = self.opt.auth,
db = self.opt.db or 0,
}
local db = redis.watch(conf)
self.__watching[name] = db
local onmessage = rawget(self,"__onmessage")
skynet.fork(function ()
while true do
local ok,data,channel,pchannel = pcall(db.message,db)
if ok then
if data and onmessage then
pcall(onmessage,data,channel,pchannel)
end
end
end
end)
end
return self.__watching[name]
end)
assert(ok,conn)
return conn
end
-- Currently we handle all the commands using method_missing for
-- simplicity. For a Cluster client actually it will be better to have
-- every single command as a method with the right arity and possibly
@@ -379,5 +459,4 @@ setmetatable(rediscluster,{
end,
})
return _M

View File

@@ -14,8 +14,8 @@ local function init(skynet, export)
dbgcmd = {}
function dbgcmd.MEM()
local kb, bytes = collectgarbage "count"
skynet.ret(skynet.pack(kb,bytes))
local kb = collectgarbage "count"
skynet.ret(skynet.pack(kb))
end
function dbgcmd.GC()
@@ -32,10 +32,18 @@ local function init(skynet, export)
skynet.ret(skynet.pack(stat))
end
function dbgcmd.TASK()
local task = {}
skynet.task(task)
skynet.ret(skynet.pack(task))
function dbgcmd.TASK(session)
if session then
skynet.ret(skynet.pack(skynet.task(session)))
else
local task = {}
skynet.task(task)
skynet.ret(skynet.pack(task))
end
end
function dbgcmd.UNIQTASK()
skynet.ret(skynet.pack(skynet.uniqtask()))
end
function dbgcmd.INFO(...)
@@ -50,9 +58,10 @@ local function init(skynet, export)
skynet.exit()
end
function dbgcmd.RUN(source, filename)
function dbgcmd.RUN(source, filename, ...)
local inject = require "skynet.inject"
local ok, output = inject(skynet, source, filename , export.dispatch, skynet.register_protocol)
local args = table.pack(...)
local ok, output = inject(skynet, source, filename, args, export.dispatch, skynet.register_protocol)
collectgarbage "collect"
skynet.ret(skynet.pack(ok, table.concat(output, "\n")))
end
@@ -78,6 +87,16 @@ local function init(skynet, export)
skynet.response() -- get response , but not return. raise error when exit
end
function dbgcmd.TRACELOG(proto, flag)
if type(proto) ~= "string" then
flag = proto
proto = "lua"
end
skynet.error(string.format("Turn trace log %s for %s", flag, proto))
skynet.traceproto(proto, flag)
skynet.ret()
end
return dbgcmd
end -- function init_dbgcmd

View File

@@ -88,6 +88,87 @@ local CACHE = {}
local dns = {}
local request_pool = {}
local local_hosts -- local static table lookup for hostnames
dns.DEFAULT_HOSTS = "/etc/hosts"
dns.DEFAULT_RESOLV_CONF = "/etc/resolv.conf"
-- return name type: 'ipv4', 'ipv6', or 'hostname'
local function guess_name_type(name)
if name:match("^[%d%.]+$") then
return "ipv4"
end
if name:find(":") then
return "ipv6"
end
return "hostname"
end
-- http://man7.org/linux/man-pages/man5/hosts.5.html
local function parse_hosts()
if not dns.DEFAULT_HOSTS then
return
end
local f = io.open(dns.DEFAULT_HOSTS)
if not f then
return
end
local rts = {}
for line in f:lines() do
local ip, hosts = string.match(line, "^%s*([%[%]%x%.%:]+)%s+([^#;]+)")
if not ip or not hosts then
goto continue
end
local family = guess_name_type(ip)
if family == "hostname" then
goto continue
end
for host in hosts:gmatch("%S+") do
host = host:lower()
local rt = rts[host]
if not rt then
rt = {}
rts[host] = rt
end
if not rt[family] then
rt[family] = {}
end
table.insert(rt[family], ip)
end
::continue::
end
return rts
end
-- http://man7.org/linux/man-pages/man5/resolv.conf.5.html
local function parse_resolv_conf()
if not dns.DEFAULT_RESOLV_CONF then
return
end
local f = io.open(dns.DEFAULT_RESOLV_CONF)
if not f then
return
end
local server
for line in f:lines() do
server = line:match("%s*nameserver%s+([^#;%s]+)")
if server then
break
end
end
f:close()
return server
end
function dns.flush()
CACHE[QTYPE.A] = setmetatable({},weak)
@@ -219,7 +300,12 @@ local function unpack_rdata(qtype, chunk)
end
end
local dns_server
local dns_server = {
fd = nil,
address = nil,
port = nil,
retire = nil,
}
local function resolve(content)
if #content < DNS_HEADER_LEN then
@@ -281,23 +367,56 @@ local function resolve(content)
skynet.wakeup(resp.co)
end
function dns.server(server, port)
if not server then
local f = assert(io.open "/etc/resolv.conf")
for line in f:lines() do
server = line:match("%s*nameserver%s+([^%s]+)")
if server then
break
end
end
f:close()
assert(server, "Can't get nameserver")
end
dns_server = socket.udp(function(str, from)
local function connect_server()
local fd = socket.udp(function(str, from)
resolve(str)
end)
socket.udp_connect(dns_server, server, port or 53)
return server
if not dns_server.address then
dns_server.address = parse_resolv_conf()
dns_server.port = 53
end
assert(dns_server.address, "Call dns.server first")
local ok, err = pcall(socket.udp_connect,fd, dns_server.address, dns_server.port)
if not ok then
socket.close(fd)
error(err)
end
dns_server.fd = fd
skynet.error(string.format("Udp server open %s:%s (%d)", dns_server.address, dns_server.port, fd))
end
local DNS_SERVER_RETIRE = 60 * 100
local function touch_server()
dns_server.retire = skynet.now()
if dns_server.fd then
return
end
connect_server()
local function check_alive()
if skynet.now() > dns_server.retire + DNS_SERVER_RETIRE then
local fd = dns_server.fd
if fd then
dns_server.fd = nil
socket.close(fd)
skynet.error(string.format("Udp server close %s:%s (%d)", dns_server.address, dns_server.port, fd))
end
else
skynet.timeout( 2 * DNS_SERVER_RETIRE, check_alive)
end
end
skynet.timeout( 2 * DNS_SERVER_RETIRE, check_alive)
end
function dns.server(server, port)
dns_server.address = server
dns_server.port = port or 53
end
local function lookup_cache(name, qtype, ignorettl)
@@ -328,7 +447,6 @@ local function suspend(tid, name, qtype)
end
end)
skynet.wait(req.co)
local answers = req.answers
request_pool[tid] = nil
if not req.answers then
local answers = lookup_cache(name, qtype, true)
@@ -340,10 +458,30 @@ local function suspend(tid, name, qtype)
return req.answers[1], req.answers
end
function dns.resolve(name, ipv6)
-- lookup local static table
local function local_resolve(name, ipv6)
if not local_hosts then
local_hosts = parse_hosts()
end
if not local_hosts then
return
end
local family = ipv6 and "ipv6" or "ipv4"
local t = local_hosts[name]
if t then
local answers = t[family]
if answers then
return answers[1], answers
end
end
return nil
end
-- lookup dns server
local function remote_resolve(name, ipv6)
local qtype = ipv6 and QTYPE.AAAA or QTYPE.A
local name = name:lower()
assert(verify_domain_name(name) , "illegal name")
local answers = lookup_cache(name, qtype)
if answers then
return answers[1], answers
@@ -354,9 +492,31 @@ function dns.resolve(name, ipv6)
qdcount = 1,
}
local req = pack_header(question_header) .. pack_question(name, qtype, QCLASS.IN)
assert(dns_server, "Call dns.server first")
socket.write(dns_server, req)
touch_server()
socket.write(dns_server.fd, req)
return suspend(question_header.tid, name, qtype)
end
function dns.resolve(name, ipv6)
local name = name:lower()
local ntype = guess_name_type(name)
if ntype ~= "hostname" then
if (ipv6 and name == "ipv4") or (not ipv6 and name == "ipv6") then
return nil, "illegal ip address"
end
return name
end
if not verify_domain_name(name) then
return nil, "illegal name"
end
local answer, answers = local_resolve(name, ipv6)
if answer then
return answer, answers
end
return remote_resolve(name, ipv6)
end
return dns

Some files were not shown because too many files have changed in this diff Show More