码迷,mamicode.com
首页 > 其他好文 > 详细

Jump The Great Firewall【step14 嵌入lua】

时间:2015-04-26 22:37:56      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:

首先这里需要宣传一下,qtun的网站已经开张了,功能正在逐步添加中。

一、嵌入lua的原因

由于qtun的可配置参数不断增多,因此有必要将参数写入到配置文件之中。又由于C语言并不擅长做字符串的处理,因此加入了轻量级的lua脚本语言,同时嵌入lua更有助于加入第三方插件的支持。

二、代码的修改

  1. 包装初始化函数
    extern int init_path(char* cmd);
    extern int init_lua();
    extern void show_logo();
    extern void conf_init(library_conf_t* conf);
    
    1. init_path中传入qtun程序所在路径,将其转换为realpath后记录到qtun->this_path中
    2. init_lua中创建出一个lua_State对象,并调用scripts/qtun.lua脚本进行初始化,最后调用script_global_init函数初始化lua环境
    3. show_logo中调用scripts/logo.lua脚本打印出qtun的logo ^o^
    4. conf_init中对传入的conf变量设置初值如默认端口为6687等
  2. script_global_init函数 script_global_init函数在init_lua过程中被调用,用于初始化lua环境
    int script_global_init(lua_State* lua)
    {
        load_lib(lua, "_G", luaopen_base);
        load_lib(lua, LUA_TABLIBNAME, luaopen_table);
        load_lib(lua, LUA_STRLIBNAME, luaopen_string);
        load_lib(lua, LUA_IOLIBNAME, luaopen_io);
        
        lua_pushcfunction(lua, _syslog);
        lua_setglobal(lua, "_syslog");
        
        init_qtun_state(lua);
        init_qtun_conf(lua);
        init_qtun_log(lua);
        return 1;
    }
    
      1. 这里首先载入基础的lua库
      2. 然后加入自定义函数_syslog
      3. 创建qtun.state、qtun.conf和qtun.log对象,通过lua.md文档可知qtun.state中所有的属性均是只读的,qtun.conf.conf_file属性是只读的,其他均为可读写的,qtun.log中包含了syslog的一些log等级定义。
      4. 下面我们来看一下这三个函数的实现
        static void init_qtun_state(lua_State* lua)
        {
            get_qtun_obj(lua);
            lua_pushstring(lua, "state");
            lua_newtable(lua);
            lua_newtable(lua);
            lua_pushstring(lua, "__index");
            lua_pushcfunction(lua, state_get);
            lua_settable(lua, -3);
            lua_setmetatable(lua, -2);
            
            lua_settable(lua, -3);
            lua_pop(lua, 1);
        }
        
        static void init_qtun_conf(lua_State* lua)
        {
            get_qtun_obj(lua);
            lua_pushstring(lua, "conf");
            lua_newtable(lua);
            
            lua_newtable(lua);
            lua_pushstring(lua, "__index");
            lua_pushcfunction(lua, conf_get);
            lua_settable(lua, -3);
            lua_pushstring(lua, "__newindex");
            lua_pushcfunction(lua, conf_set);
            lua_settable(lua, -3);
            lua_setmetatable(lua, -2);
            
            lua_settable(lua, -3);
            lua_pop(lua, 1);
        }
        
        static void init_qtun_log(lua_State* lua)
        {
            int new_log = 0;
            
            get_qtun_obj(lua);
            lua_pushstring(lua, "log");
            lua_gettable(lua, -2);
            if (lua_isnil(lua, -1))
            {
                lua_pop(lua, 1);
                lua_pushstring(lua, "log");
                lua_newtable(lua);
                new_log = 1;
            }
            push_log_level(lua, "LOG_EMERG"  , 0);
            push_log_level(lua, "LOG_ALERT"  , 1);
            push_log_level(lua, "LOG_CRIT"   , 2);
            push_log_level(lua, "LOG_ERR"    , 3);
            push_log_level(lua, "LOG_WARNING", 4);
            push_log_level(lua, "LOG_NOTICE" , 5);
            push_log_level(lua, "LOG_INFO"   , 6);
            push_log_level(lua, "LOG_DEBUG"  , 7);
            if (new_log)
                lua_settable(lua, -3);
            lua_pop(lua, 1);
            
        }
        
    从代码中可知:qtun.state和qtun.conf通过metatable将C对象映射到lua中,qtun.log中只定义了log等级的常量
  3. script_load_config函数 script_load_config函数通过调用scripts/load_config.lua脚本来载入配置文件
    int script_load_config(lua_State* lua, library_conf_t* conf, const char* file_path)
    {
        char path[MAX_PATH];
        lua_pushlightuserdata(lua, conf);
        lua_setglobal(lua, "__conf__");
        
        strcpy(path, qtun->this_path);
        strcat(path, "scripts/load_config.lua");
        if (luaL_dofile(lua, path) != 0)
        {
            fprintf(stderr, "%s\n", lua_tostring(qtun->lua, -1));
            lua_close(qtun->lua);
            exit(1);
        }
        return 1;
    }
    
  4. 下面我们来看一下main函数的整个流程

技术分享

三、lua脚本

最后让我们来分别看一下这三个lua脚本长啥样

  1. logo.lua
    print(‘┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓‘)
    print(‘┃   ...   .....  .   .  .  .  ┃‘)
    print(‘┃  .   .    .    .   .  .. .  ┃‘)
    print(‘┃  .   .    .    .   .  . ..  ┃‘)
    print(‘┃   ... .   .     ...   .  .  ┃‘)
    print(‘┃                             ┃‘)
    print(‘┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛‘)
    
    这个logo是不是很有爱^_^
  2. qtun.lua
    qtun = {
        log = {
            syslog = function (level, fmt, ...)
                _syslog(level, string.format(fmt, ...))
            end
        }
    }
    
    function trim(s)
        return s:gsub(‘^%s*(.-)%s*$‘, ‘%1‘)
    end
    
    function is_numeric(s)
        return tonumber(s) ~= nil
    end
    
    function is_string(s)
        return not is_numeric(s)
    end
    
    这里包装了一些公共函数
  3. load_config.lua
    local function append_key_value(key, value)
        if value == ‘true‘ then
            value = true
        elseif value == ‘false‘ then
            value = false
        elseif is_numeric(value) then
            value = tonumber(value)
        elseif key == ‘log_level‘ then
            if is_string(value) then
                value = qtun.log[value]
            end
        end
        qtun.conf[key] = value
    end
    
    local function set_true(key)
        qtun.conf[key] = true
    end
    
    local file = io.open(qtun.conf.conf_file, ‘r‘)
    while true do
    ::start::
        local line = file:read(‘*line‘)
        if line == nil then break end
        
        local len = #line
        local key = ‘‘
        local first = ‘‘
        local start = 0
        local have_key = false
        local have_value = false
        local added = false
        local j = 0
        for i=0, len do
            j = i
            local ch = line:sub(i + 1, i + 1)
            if first == ‘‘ and ch ~= ‘ ‘ then
                first = ch
            end
            if ch == ‘#‘ then
                if trim(line:sub(start, i)) == ‘‘ then goto start end
                have_value = true
                if have_key then
                    append_key_value(key, trim(line:sub(start, i)))
                else
                    set_true(trim(line:sub(start, i)))
                end
                added = true
                break
            elseif ch == ‘=‘ then
                key = trim(line:sub(start, i))
                if key == ‘‘ then
                    error(‘missing key‘)
                end
                have_key = true
                start = i + 2
            end
        end
        if first == ‘#‘ then goto start end
        
        if not added then
            if not have_key then
                local key = trim(line:sub(start, j))
                if key == ‘‘ then goto start end
                set_true(key)
            else
                append_key_value(key, trim(line:sub(start, j)))
            end
        end
    end
    file:close()
    
    解析配置文件的主要逻辑都在这里了

四、完整代码

完整代码可到step14中查看

Jump The Great Firewall【step14 嵌入lua】

标签:

原文地址:http://www.cnblogs.com/lwch/p/4458414.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!