Skip to content

Commit 4944f46

Browse files
committed
replace struct pack/unpack with bitops
1 parent f8dbe73 commit 4944f46

File tree

6 files changed

+134
-44
lines changed

6 files changed

+134
-44
lines changed

Dockerfile

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
FROM ubuntu:14.04
2+
# install autobahn tests suite (python)
3+
RUN apt-get update -y && apt-get install build-essential libffi-dev libssl-dev python-pip -y
4+
RUN apt-get install python-dev -y
5+
RUN pip -V
6+
RUN pip install autobahntestsuite
7+
# install lua
8+
ENV LUAROCKS_VERSION=2.0.13
9+
ENV LUAROCKS_BASE=luarocks-$LUAROCKS_VERSION
10+
ENV LUA luajit
11+
ENV LUA_DEV libluajit-5.1-dev
12+
ENV LUA_VER 5.1
13+
ENV LUA_SFX jit
14+
ENV LUA_INCDIR /usr/include/luajit-2.0
15+
16+
# - LUA=lua5.1 LUA_DEV=liblua5.1-dev LUA_VER=5.1 LUA_SFX=5.1 LUA_INCDIR=/usr/include/lua5.1
17+
# - LUA=lua5.2 LUA_DEV=liblua5.2-dev LUA_VER=5.2 LUA_SFX=5.2 LUA_INCDIR=/usr/include/lua5.2
18+
# - LUA=luajit LUA_DEV=libluajit-5.1-dev LUA_VER=5.1 LUA_SFX=jit LUA_INCDIR=/usr/include/luajit-2.0
19+
RUN apt-get install ${LUA} ${LUA_DEV} wget libev-dev git-core unzip -y
20+
RUN lua${LUA_SFX} -v
21+
RUN wget --quiet https://github.com/keplerproject/luarocks/archive/v$LUAROCKS_VERSION.tar.gz -O $LUAROCKS_BASE.tar.gz
22+
RUN tar zxpf $LUAROCKS_BASE.tar.gz
23+
RUN cd $LUAROCKS_BASE && ./configure --lua-version=$LUA_VER --lua-suffix=$LUA_SFX --with-lua-include="$LUA_INCDIR" && make install && cd ..
24+
RUN luarocks --version
25+
RUN git clone http://github.com/brimworks/lua-ev && cd lua-ev && luarocks make LIBEV_LIBDIR=/usr/lib/x86_64-linux-gnu/ rockspec/lua-ev-scm-1.rockspec && cd ..
26+
RUN luarocks install LuaCov
27+
RUN luarocks install lua_cliargs 2.3-3
28+
RUN luarocks install busted 1.10.0-1
29+
ADD . /lua-websockets
30+
WORKDIR /lua-websockets
31+
RUN luarocks make rockspecs/lua-websockets-scm-1.rockspec
32+
RUN ./test.sh
33+

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,7 @@ var echoWs = new WebSocket('ws://127.0.0.1:8002','echo');
115115
The client and server modules depend on:
116116

117117
- luasocket
118-
- struct
119118
- luabitop (if not using Lua 5.2 nor luajit)
120-
- luacrypto (optionally)
121119
- copas (optionally)
122120
- lua-ev (optionally)
123121

lua-websockets.rockspec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ description = {
1010
summary = "Websockets for Lua",
1111
homepage = "http://github.com/lipp/lua-websockets",
1212
license = "MIT/X11",
13-
detailed = "Provides sync and async clients and servers for copas."
13+
detailed = "Provides sync and async clients and servers for copas and lua-ev."
1414
}
1515

1616
dependencies = {
1717
"lua >= 5.1",
18-
"struct",
1918
"luasocket",
2019
"luabitop",
2120
"copas"

rockspecs/lua-websockets-scm-1.rockspec

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ description = {
1414

1515
dependencies = {
1616
"lua >= 5.1",
17-
"struct",
1817
"luasocket",
1918
"luabitop",
2019
"lua-ev",

src/websocket/frame.lua

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
-- Following Websocket RFC: http://tools.ietf.org/html/rfc6455
2-
local struct = require'struct'
32
local bit = require'websocket.bit'
43
local band = bit.band
54
local bxor = bit.bxor
@@ -12,11 +11,16 @@ local schar = string.char
1211
local tinsert = table.insert
1312
local tconcat = table.concat
1413
local mmin = math.min
15-
local strpack = struct.pack
16-
local strunpack = struct.unpack
1714
local mfloor = math.floor
1815
local mrandom = math.random
1916
local unpack = unpack or table.unpack
17+
local tools = require'websocket.tools'
18+
local write_int8 = tools.write_int8
19+
local write_int16 = tools.write_int16
20+
local write_int32 = tools.write_int32
21+
local read_int8 = tools.read_int8
22+
local read_int16 = tools.read_int16
23+
local read_int32 = tools.read_int32
2024

2125
local bits = function(...)
2226
local n = 0
@@ -30,6 +34,7 @@ local bit_7 = bits(7)
3034
local bit_0_3 = bits(0,1,2,3)
3135
local bit_0_6 = bits(0,1,2,3,4,5,6)
3236

37+
-- TODO: improve performance
3338
local xor_mask = function(encoded,mask,payload)
3439
local transformed,transformed_arr = {},{}
3540
-- xor chunk-wise to prevent stack overflow.
@@ -49,7 +54,6 @@ local xor_mask = function(encoded,mask,payload)
4954
end
5055

5156
local encode = function(data,opcode,masked,fin)
52-
local encoded
5357
local header = opcode or 1-- TEXT is default opcode
5458
if fin == nil or fin == true then
5559
header = bor(header,bit_7)
@@ -59,41 +63,44 @@ local encode = function(data,opcode,masked,fin)
5963
payload = bor(payload,bit_7)
6064
end
6165
local len = #data
66+
local chunks = {}
6267
if len < 126 then
6368
payload = bor(payload,len)
64-
encoded = strpack('bb',header,payload)
69+
tinsert(chunks,write_int8(header,payload))
6570
elseif len <= 0xffff then
6671
payload = bor(payload,126)
67-
encoded = strpack('bb>H',header,payload,len)
72+
tinsert(chunks,write_int8(header,payload))
73+
tinsert(chunks,write_int16(len))
6874
elseif len < 2^53 then
6975
local high = mfloor(len/2^32)
7076
local low = len - high*2^32
7177
payload = bor(payload,127)
72-
encoded = strpack('bb>I>I',header,payload,high,low)
78+
tinsert(chunks,write_int8(header,payload))
79+
tinsert(chunks,write_int32(high))
80+
tinsert(chunks,write_int32(low))
7381
end
7482
if not masked then
75-
encoded = encoded..data
83+
tinsert(chunks,data)
7684
else
7785
local m1 = mrandom(0,0xff)
7886
local m2 = mrandom(0,0xff)
7987
local m3 = mrandom(0,0xff)
8088
local m4 = mrandom(0,0xff)
8189
local mask = {m1,m2,m3,m4}
82-
encoded = tconcat({
83-
encoded,
84-
strpack('BBBB',m1,m2,m3,m4),
85-
xor_mask(data,mask,#data)
86-
})
90+
tinsert(chunks,write_int8(m1,m2,m3,m4))
91+
tinsert(chunks,xor_mask(data,mask,#data))
8792
end
88-
return encoded
93+
return tconcat(chunks)
8994
end
9095

9196
local decode = function(encoded)
9297
local encoded_bak = encoded
9398
if #encoded < 2 then
9499
return nil,2-#encoded
95100
end
96-
local header,payload,pos = strunpack('bb',encoded)
101+
local pos,header,payload
102+
pos,header = read_int8(encoded,1)
103+
pos,payload = read_int8(encoded,pos)
97104
local high,low
98105
encoded = ssub(encoded,pos)
99106
local bytes = 2
@@ -106,12 +113,13 @@ local decode = function(encoded)
106113
if #encoded < 2 then
107114
return nil,2-#encoded
108115
end
109-
payload,pos = strunpack('>H',encoded)
116+
pos,payload = read_int16(encoded,1)
110117
elseif payload == 127 then
111118
if #encoded < 8 then
112119
return nil,8-#encoded
113120
end
114-
high,low,pos = strunpack('>I>I',encoded)
121+
pos,high = read_int32(encoded,1)
122+
pos,low = read_int32(encoded,pos)
115123
payload = high*2^32 + low
116124
if payload < 0xffff or payload > 2^53 then
117125
assert(false,'INVALID PAYLOAD '..payload)
@@ -128,7 +136,11 @@ local decode = function(encoded)
128136
if bytes_short > 0 then
129137
return nil,bytes_short
130138
end
131-
local m1,m2,m3,m4,pos = strunpack('BBBB',encoded)
139+
local m1,m2,m3,m4
140+
pos,m1 = read_int8(encoded,1)
141+
pos,m2 = read_int8(encoded,pos)
142+
pos,m3 = read_int8(encoded,pos)
143+
pos,m4 = read_int8(encoded,pos)
132144
encoded = ssub(encoded,pos)
133145
local mask = {
134146
m1,m2,m3,m4
@@ -152,7 +164,7 @@ end
152164

153165
local encode_close = function(code,reason)
154166
if code then
155-
local data = strpack('>H',code)
167+
local data = write_int16(code)
156168
if reason then
157169
data = data..tostring(reason)
158170
end
@@ -165,7 +177,7 @@ local decode_close = function(data)
165177
local _,code,reason
166178
if data then
167179
if #data > 1 then
168-
code = strunpack('>H',data)
180+
_,code = read_int16(data,1)
169181
end
170182
if #data > 2 then
171183
reason = data:sub(3)

src/websocket/tools.lua

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
local struct = require'struct'
21
local bit = require'websocket.bit'
32
local rol = bit.rol
43
local bxor = bit.bxor
@@ -15,6 +14,46 @@ local tinsert = table.insert
1514
local tconcat = table.concat
1615
local mrandom = math.random
1716

17+
local read_n_bytes = function(str, pos, n)
18+
pos = pos or 1
19+
return pos+n, string.byte(str, pos, pos + n - 1)
20+
end
21+
22+
local read_int8 = function(str, pos)
23+
return read_n_bytes(str, pos, 1)
24+
end
25+
26+
local read_int16 = function(str, pos)
27+
local new_pos,a,b = read_n_bytes(str, pos, 2)
28+
return new_pos, lshift(a, 8) + b
29+
end
30+
31+
local read_int32 = function(str, pos)
32+
local new_pos,a,b,c,d = read_n_bytes(str, pos, 4)
33+
return new_pos,
34+
lshift(a, 24) +
35+
lshift(b, 16) +
36+
lshift(c, 8 ) +
37+
d
38+
end
39+
40+
local pack_bytes = string.char
41+
42+
local write_int8 = pack_bytes
43+
44+
local write_int16 = function(v)
45+
return pack_bytes(rshift(v, 8), band(v, 0xFF))
46+
end
47+
48+
local write_int32 = function(v)
49+
return pack_bytes(
50+
band(rshift(v, 24), 0xFF),
51+
band(rshift(v, 16), 0xFF),
52+
band(rshift(v, 8), 0xFF),
53+
band(v, 0xFF)
54+
)
55+
end
56+
1857
-- used for generate key random ops
1958
math.randomseed(os.time())
2059

@@ -34,33 +73,37 @@ local sha1_wiki = function(msg)
3473
local h2 = 0x98BADCFE
3574
local h3 = 0x10325476
3675
local h4 = 0xC3D2E1F0
37-
76+
3877
local bits = #msg * 8
3978
-- append b10000000
4079
msg = msg..schar(0x80)
41-
80+
4281
-- 64 bit length will be appended
4382
local bytes = #msg + 8
44-
83+
4584
-- 512 bit append stuff
4685
local fill_bytes = 64 - (bytes % 64)
4786
if fill_bytes ~= 64 then
4887
msg = msg..srep(schar(0),fill_bytes)
4988
end
50-
89+
5190
-- append 64 big endian length
5291
local high = math.floor(bits/2^32)
5392
local low = bits - high*2^32
54-
msg = msg..struct.pack('>I>I',high,low)
55-
93+
msg = msg..write_int32(high)..write_int32(low)
94+
5695
assert(#msg % 64 == 0,#msg % 64)
57-
96+
5897
for j=1,#msg,64 do
5998
local chunk = msg:sub(j,j+63)
6099
assert(#chunk==64,#chunk)
61-
local words = {struct.unpack(srep('>I',16),chunk)}
62-
-- last item contains the index in chunk where it stopped reading
63-
tremove(words,17)
100+
local words = {}
101+
local next = 1
102+
local word
103+
repeat
104+
next,word = read_int32(chunk, next)
105+
tinsert(words, word)
106+
until next > 64
64107
assert(#words==16)
65108
for i=17,80 do
66109
words[i] = bxor(words[i-3],words[i-8],words[i-14],words[i-16])
@@ -71,7 +114,7 @@ local sha1_wiki = function(msg)
71114
local c = h2
72115
local d = h3
73116
local e = h4
74-
117+
75118
for i=1,80 do
76119
local k,f
77120
if i > 0 and i < 21 then
@@ -87,31 +130,31 @@ local sha1_wiki = function(msg)
87130
f = bxor(b,c,d)
88131
k = 0xCA62C1D6
89132
end
90-
133+
91134
local temp = rol(a,5) + f + e + k + words[i]
92135
e = d
93136
d = c
94137
c = rol(b,30)
95138
b = a
96139
a = temp
97140
end
98-
141+
99142
h0 = h0 + a
100143
h1 = h1 + b
101144
h2 = h2 + c
102145
h3 = h3 + d
103146
h4 = h4 + e
104-
147+
105148
end
106-
149+
107150
-- necessary on sizeof(int) == 32 machines
108151
h0 = band(h0,0xffffffff)
109152
h1 = band(h1,0xffffffff)
110153
h2 = band(h2,0xffffffff)
111154
h3 = band(h3,0xffffffff)
112155
h4 = band(h4,0xffffffff)
113-
114-
return struct.pack('>i>i>i>i>i',h0,h1,h2,h3,h4)
156+
157+
return write_int32(h0)..write_int32(h1)..write_int32(h2)..write_int32(h3)..write_int32(h4)
115158
end
116159

117160
local base64_encode = function(data)
@@ -139,7 +182,7 @@ local generate_key = function()
139182
local r2 = mrandom(0,0xfffffff)
140183
local r3 = mrandom(0,0xfffffff)
141184
local r4 = mrandom(0,0xfffffff)
142-
local key = struct.pack('IIII',r1,r2,r3,r4)
185+
local key = write_int32(r1)..write_int32(r2)..write_int32(r3)..write_int32(r4)
143186
assert(#key==16,#key)
144187
return base64_encode(key)
145188
end
@@ -151,4 +194,10 @@ return {
151194
},
152195
parse_url = parse_url,
153196
generate_key = generate_key,
197+
read_int8 = read_int8,
198+
read_int16 = read_int16,
199+
read_int32 = read_int32,
200+
write_int8 = write_int8,
201+
write_int16 = write_int16,
202+
write_int32 = write_int32,
154203
}

0 commit comments

Comments
 (0)