lua entry thread aborted: runtime error: attempt to yield across C-call boundary

180 views
Skip to first unread message

密思刘

unread,
Dec 16, 2016, 2:28:16 AM12/16/16
to open...@googlegroups.com
本人初学openresty ,现在用一个开源项目修改练手. https://github.com/sumory/openresty-china.

我在上面添加我自已的路由处理.中间要用到redis 与postgresql. postgresql 连接问题已经解决.redis 一直不行.


~/workspace/openresty-china$ cat app/routes/iot.lua
local pairs = pairs
local ipairs = ipairs
local smatch = string.match
local slower = string.lower
local ssub = string.sub
local slen = string.len
local pbkdf2 = require "resty.nettle.pbkdf2"
local base64 = require "resty.nettle.base64"
local hmac = require "resty.nettle.hmac"
local gsub = string.gsub
local byte = string.byte
local format = string.format
local cjson = require("cjson")
local utils = require("app.libs.utils")
local pwd_secret = require("app.config.config").pwd_secret
local lor = require("lor.index")
local user_model = require("app.model.user")
local iot_router = lor:Router()
local config  = require("app.config.config")



--- 加了一段代码会报错 
local redis = require("resty.redis")
local red = redis:new()
red:set_timeout(1000)
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
    ngx.log(ngx.ERR ,"connect redis error")
end
ok , err = red:auth("f4e4821080c")
if not ok then
    ngx.say("auth is failed  ",err)
    return ok,err
end
red:select(1)
----                      
            
local UnkownSignMethod = {err="UnkownSignMethod", msg="未知签名方法", ok=false}
local SignError = {err="SignError", msg="签名错误", ok=false}
local DataMiss = {err="DataMiss", msg="信息不完整", ok=false}
local UserNotExists = {err= "UserNotExists", msg="用户不存在", ok=false}
local UnAuth = {err= "UnAuth", msg="无权访问", ok=false}
local TargetNotExists = {err= "TargetNotExists", msg="目标不存在", ok=false}
local TargetIsSelf = {err= "TargetIsSelf", msg="目标不能是自已", ok=false}
local UnkownAction = {err="UnkownAction", msg="未识别的操作", ok=false}
local BindError = {err="BindError", msg="已经绑定", ok=false}
local BindPWDError = {err="BindError", msg="无权绑定", ok=false}
local UserError = {err="UserError", msg="用户名已存在", ok=false}
local EmailError = {err="EmailError", msg="邮箱已存在", ok=false}
local PhoneError = {err="PhoneError", msg="手机号已存在", ok=false}
local PwdError = {err="PwdError", msg="密码或者用户错误", ok=false}
local ArgError = {err="ArgError", msg="参数错误", ok=false}
local CaptchaError = {err="CaptchaError", msg="验证码错误", ok=false}
local IpAddrError = {err="IpAddrError", msg="IP错误", ok=false}
local InternalError = {err="InternalError", msg="服务器内部错误", ok=false}
local SmsOverError = {err="SmsOverError", msg="该手机号已经超过发送次数", ok=false}
local SmsIntervalError = {err="SmsIntervalError", msg="发送间隔太短", ok=false}
local OtherError = {err="OtherError", msg="发送间隔太短", ok=false}
local PhoneInactive = {err="PhoneInactive", msg="该手机号没有验证激活", ok=false}
local FormatError = {err="FormatError", msg="格式错误", ok=false}
local DevActError = {err="DevActError", msg="设备未出厂", ok=false}




local function hex(str,spacer)
    return (gsub(str,"(.)",function (c)
        return format("%02X%s",byte(c),spacer or "")
    end))
end

local function checkuuid(uuid)
    local x = "%x"
    local t = {x:rep(8),x:rep(4),x:rep(4),x:rep(4),x:rep(12)}
    local t2 = x:rep(32)
    local pattern = table.concat(t,'%-')
    if string.match(uuid,pattern) or string.match(uuid,t2) then
        return true
    else
        return false
    end
end

-- 这里是为了兼django插入的加密认证方式, key = "<algorithm>$<iterations>$<salt>$<hash>"
local function check_password(oldpwd,newpwd)
    -- a1,a2,a3,a4= string.match(oldpwd,"(%w+_%w+)%$(%d+)%$(%w+)%$([A-Za-z0-9+/]+)")
    -- ngx.log(ngx.ERR,"match is ",a1,"||",a2,"||",a3,"||",a4)
    local algorithm,iterations,salt,hash = string.match(oldpwd,"(%w+_%w+)%$(%d+)%$(%w+)%$([A-Za-z0-9+/=]+)")
    -- ngx.log(ngx.ERR,"split pass ",oldpwd," ",algorithm,iterations,salt,hash)
    if not algorithm or not iterations or not salt  or not hash then
        return false
    end

    local hmac
    if algorithm == "pbkdf2_sha256" then
        hmac = pbkdf2.hmac_sha256(newpwd,tonumber(iterations),salt,32)
        -- ngx.log(ngx.ERR,"algoritm  is ",algorithm)
    elseif algorithm == "pbkdf2_sha1" then
        --    ngx.log(ngx.ERR,"algoritm  is ",algorithm, "new pwd is ", newpwd)
        hmac = pbkdf2.hmac_sha1(newpwd,tonumber(iterations),salt,20)
    end

    -- ngx.log(ngx.ERR,"hash is ",hash, " new hash ",base64.encode(hmac))
    if hash == base64.encode(hmac) then
        -- ngx.log(ngx.ERR,"check password is true")
        return true
    end

    return false
end



iot_router:get("/app",function(req,res,next)

    local args = ngx.req.get_uri_args()
    local usertoken = args.uuid
    local userpass =  args.key
   
    if not usertoken or not userpass or usertoken == "" or userpass == "" then
        return res:json(DataMiss)
    end

   
    local result,err = user_model:query_by_iot_login(usertoken)
    -- ngx.log(ngx.ERR,"query sql error  ",err)

    if err then
        return res:json(PwdError)
    end
    -- ngx.log(ngx.ERR,"uuid  ",result.uuid," key ",result.key, " active ",result.phone_active)
    local uuid,key,phone_active

    if #result == 3 then
        uuid = result[1]
        key = result[2]
        phone_active = result[3]
    else
        uuid = result.uuid
        key = result.key
        phone_active  = result.phone_active
    end

    if not phone_active then
        return res:json(PhoneInactive)
    end

    if result and not err then
        if check_password(key,tostring(userpass)) then
            -- 登录成功
            local srvres ,err = user_model:query_by_mqtt_srv()
            local servers = nil
            if srvres and not err then
                    if #srvres == 2 then
                        servers = srvres[1] .. ":" .. srvres[2]
                    else
                        servers = srvres.ipaddr  .. ":" .. srvres.port
                    end
            end

            local timestamp = string.format("%d",os.time())
            local hash = hmac.sha1.new(timestamp)
            hash:update(key)
            local signid = hex(hash:digest())
            -- ngx.log(ngx.ERR,"sigin id is ",signid)


            local hash256 = hmac.sha256.new(timestamp)
            hash256:update(uuid)
            -- ngx.log(ngx.ERR, "hash256 is ",type(hash256))
            ngx.log(ngx.ERR,"search redis path ",package.searchpath('resty.redis',package.path))
            ngx.log(ngx.ERR,"search postgres path ",package.searchpath('resty.postgres',package.path))

  
            -- red:hset(signid,"password",hex(hash256:digest()))
            -- red:hset(signid,"uuid",result.uuid)
            -- red:expire(signid,config.settings.SESSION_COOKIE_AGE)

            retable = {}
            retable.ok= true
            retable.sign =  signid
            retable.time = timestamp
            retable.expire = config.settings.SESSION_COOKIE_AGE
            if servers then
                    retable.servers = servers
            end

            return res:json(retable)
        else
            return res:json(PwdError)
        end
    end

    return res:json(UserNotExists)
end)
       

return iot_router

--------------------------------------------------------------------------------------

如果是这样写必定会出错,nginx 报错如下:

2016/12/16 15:14:46 [error] 10248#0: *34 lua entry thread aborted: runtime error: attempt to yield across C-call boundary
stack traceback:
coroutine 0:
    [C]: in function 'require'
    /home/yjdwbj/workspace/openresty-china/./app/main.lua:9: in function </home/yjdwbj/workspace/openresty-china/./app/main.lua:1>, client: 192.168.8.31, server: , request: "GET /iot/app?uuid=abc&key=123456 HTTP/1.1", host: "127.0.0.1:8888"

---------------------------------------------------------------------------------------------------

如果去掉开头那些连接redis的代码就能正常运行.问题代码如下:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
local redis = require("resty.redis")
local red = redis:new()
red:set_timeout(1000)
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
    ngx.log(ngx.ERR ,"connect redis error")
end
ok , err = red:auth("f4e4821080c")
if not ok then
    ngx.say("auth is failed  ",err)
    return ok,err
end
red:select(1)

>>>>>>>>>>>>>>>>>>>>>>
但是如果把上面这段代码放在 iot_router:get("/app",function(req,res,next))  函数里面,运行又是正常的.请大家指教.如何通过openresty 连接到postgresql pool 与 redis pool . 不胜感激.
Reply all
Reply to author
Forward
0 new messages