aboutsummaryrefslogtreecommitdiffstats
path: root/server/resty/openssl/stack.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server/resty/openssl/stack.lua')
-rw-r--r--server/resty/openssl/stack.lua159
1 files changed, 159 insertions, 0 deletions
diff --git a/server/resty/openssl/stack.lua b/server/resty/openssl/stack.lua
new file mode 100644
index 0000000..9bdc377
--- /dev/null
+++ b/server/resty/openssl/stack.lua
@@ -0,0 +1,159 @@
+
+--[[
+ The OpenSSL stack library. Note `safestack` is not usable here in ffi because
+ those symbols are eaten after preprocessing.
+ Instead, we should do a Lua land type checking by having a nested field indicating
+ which type of cdata its ctx holds.
+]]
+local ffi = require "ffi"
+local C = ffi.C
+local ffi_cast = ffi.cast
+local ffi_gc = ffi.gc
+
+local stack_macro = require "resty.openssl.include.stack"
+local format_error = require("resty.openssl.err").format_error
+
+local _M = {}
+
+local function gc_of(typ)
+ local f = C[typ .. "_free"]
+ return function (st)
+ stack_macro.OPENSSL_sk_pop_free(st, f)
+ end
+end
+
+_M.gc_of = gc_of
+
+_M.mt_of = function(typ, convert, index_tbl, no_gc)
+ if type(typ) ~= "string" then
+ error("expect a string at #1")
+ elseif type(convert) ~= "function" then
+ error("expect a function at #2")
+ end
+
+ local typ_ptr = typ .. "*"
+
+ -- starts from 0
+ local function value_at(ctx, i)
+ local elem = stack_macro.OPENSSL_sk_value(ctx, i)
+ if elem == nil then
+ error(format_error("OPENSSL_sk_value"))
+ end
+ local dup, err = convert(ffi_cast(typ_ptr, elem))
+ if err then
+ error(err)
+ end
+ return dup
+ end
+
+ local function iter(tbl)
+ if not tbl then error("instance is nil") end
+ local i = 0
+ local n = tonumber(stack_macro.OPENSSL_sk_num(tbl.ctx))
+ return function()
+ i = i + 1
+ if i <= n then
+ return i, value_at(tbl.ctx, i-1)
+ end
+ end
+ end
+
+ local ret = {
+ __pairs = iter,
+ __ipairs = iter,
+ __len = function(tbl)
+ if not tbl then error("instance is nil") end
+ return tonumber(stack_macro.OPENSSL_sk_num(tbl.ctx))
+ end,
+ __index = function(tbl, k)
+ if not tbl then error("instance is nil") end
+ local i = tonumber(k)
+ if not i then
+ return index_tbl[k]
+ end
+ local n = stack_macro.OPENSSL_sk_num(tbl.ctx)
+ if i <= 0 or i > n then
+ return nil
+ end
+ return value_at(tbl.ctx, i-1)
+ end,
+ }
+
+ if not no_gc then
+ ret.__gc = gc_of(typ)
+ end
+ return ret
+end
+
+_M.new_of = function(typ)
+ local gc = gc_of(typ)
+ return function()
+ local raw = stack_macro.OPENSSL_sk_new_null()
+ if raw == nil then
+ return nil, "stack.new_of: OPENSSL_sk_new_null() failed"
+ end
+ ffi_gc(raw, gc)
+ return raw
+ end
+end
+
+_M.add_of = function(typ)
+ local ptr = ffi.typeof(typ .. "*")
+ return function(stack, ctx)
+ if not stack then error("instance is nil") end
+ if ctx == nil or not ffi.istype(ptr, ctx) then
+ return false, "stack.add_of: expect a " .. typ .. "* at #1"
+ end
+ local code = stack_macro.OPENSSL_sk_push(stack, ctx)
+ if code == 0 then
+ return false, "stack.add_of: OPENSSL_sk_push() failed"
+ end
+ return true
+ end
+end
+
+local stack_ptr_ct = ffi.typeof("OPENSSL_STACK*")
+_M.dup_of = function(_)
+ return function(ctx)
+ if ctx == nil or not ffi.istype(stack_ptr_ct, ctx) then
+ return nil, "stack.dup_of: expect a stack ctx at #1"
+ end
+ local ctx = stack_macro.OPENSSL_sk_dup(ctx)
+ if ctx == nil then
+ return nil, "stack.dup_of: OPENSSL_sk_dup() failed"
+ end
+ -- if the stack is duplicated: since we don't copy the elements
+ -- then we only control gc of the stack itself here
+ ffi_gc(ctx, stack_macro.OPENSSL_sk_free)
+ return ctx
+ end
+end
+
+-- fallback function to iterate if LUAJIT_ENABLE_LUA52COMPAT not enabled
+_M.all_func = function(mt)
+ return function(stack)
+ if not stack then error("stack is nil") end
+ local ret = {}
+ local _next = mt.__pairs(stack)
+ while true do
+ local i, elem = _next()
+ if elem then
+ ret[i] = elem
+ else
+ break
+ end
+ end
+ return ret
+ end
+end
+
+_M.deep_copy_of = function(typ)
+ local dup = C[typ .. "_dup"]
+ local free = C[typ .. "_free"]
+
+ return function(ctx)
+ return stack_macro.OPENSSL_sk_deep_copy(ctx, dup, free)
+ end
+end
+
+return _M \ No newline at end of file