OpenWrt Luci流程分析

111 篇文章 10 订阅
87 篇文章 31 订阅

目录

1 页面请求:

1.0 代码结构

1.1 界面显示

1.1.1 /www/cgi-bin/luci

1.1.2 /usr/lib/lua/luci/sgi/cgi.lua

1.1.3 /usr/lib/lua/luci/dispatcher.lua

1.1.4 请求页面network

2 页面响应

2.1 Web请求

2.2 处理


1 页面请求:

1.0 代码结构

在openwrt文件系统中,lua语言的代码不要编译,类似一种脚本语言被执行,还有一些uhttpd服务器的主目录,它们是:

/www/index.html
cgi-bin/luci
luci-static/xxx/xx.css、js、gif

/usr/lib/lua/nixio.so、uci.so
luci/http.lua、dispatcher.lua、core…
controller/xxx.lua
model/xxx.lua
view/xxx.lua

1.1 界面显示

网页请求格式基本都如下所示:,说明处理都在服务器的默认网站下的/cgi-bin/luci文件进行处理。

1.1.1 /www/cgi-bin/luci

luci.dispatcher.indexcache = “/tmp/luci-indexcache”–缓存文件位置“/tmp/luci-indexcache”

luci.sgi.cgi.run()–cgi程序接下来执行程序,Luci的默认路径是/usr/lib/lua/luci,所以luci.sgi.cgi.run()是运行/usr/lib/lua/luci/sgi/cgi.lua文件中的run函数。

1.1.2 /usr/lib/lua/luci/sgi/cgi.lua

local r = luci.http.Request(…)--把web请求放于r中(包括环境变量,web请求,出错处理接口)
local x = coroutine.create(luci.dispatcher.httpdispatch)--创建一个协同程序
local res, id, data1, data2 = coroutine.resume(x, r)--运行上面创建的协同程序,即运行httpdispatch,参数为上面local r里的变量。

if active then
	if id == 1 then
				io.write("Status: " .. tostring(data1) .. " " .. data2 .. "\r\n")
     elseif id == 2 then
        hcache = hcache .. data1 .. ": " .. data2 .. "\r\n"—准备header
     elseif id == 3 then--写header、blank
        io.write(hcache)—默认到stdout
        io.write("\r\n")
     elseif id == 4 then
        io.write(tostring(data1 or ""))--写body
     elseif id == 5 then
        io.flush()
        io.close()--EOF
        active = false
     elseif id == 6 then
        data1:copyz(nixio.stdout, data2)
        data1:close()

1.1.3 /usr/lib/lua/luci/dispatcher.lua

httpdispatch:解析请求,获得请求节点,并调用dispatch处理请求节点,如:

Request : get: admin network firewall

dispatch:四个部分处理请求

A.节点树node-tree创立

​ if not c then

​ c = createtree()

​ B.需要显示的部分

​ if (c and c.index) or not track.notemplate then

​ C.认证

​ if track.sysauth then

​ D.显示/处理

​ ok, err = util.copcall(target, c.target, unpack(args))

1.1.4 请求页面network

1.2.3中D显示部分与entry()函数(形如entry(path,target,title,order))有关,其中定义的target方法或者target部分。在以上http请求中会根据请求路径去访问到/usr/lib/lua/luci/controller/admin/network.lua,调用顺序如下:

ok, err = util.copcall(target, unpack(args))-- dispatcher.luaà
page.target = firstchild() -- network.luaà
function firstchild()-- dispatcher.luaà
_firstchild()-- dispatcher.luaàdispatch(path)-- 自动链接到它的第一个子节点,
在network.lua中定义order,Interfaces是10,为第一个子节点:
page = entry({"admin", "network", "network"}, arcombine(cbi("admin_network/network"), cbi("admin_network/ifaces")), _("Interfaces"), 10)--通过cbi方法处理admin_network/ifaces.lua和admin_network/network.lua,生成html文件

2 页面响应

2.1 Web请求

当点击页面“Save & Apply”按钮时,浏览器会把每一个有name的web元素的对应值下传,下传form表格如下:

—————————–151563007122428

Content-Disposition: form-data; name=“cbi.submit” 1

—————————–151563007122428

Content-Disposition: form-data; name=“cbi.cbe.firewall.cfg02e63d.syn_flood” 1 —————————–151563007122428

Content-Disposition: form-data; name=“cbi.cbe.firewall.cfg02e63d.drop_invalid” 1

……

……

—————————–151563007122428

Content-Disposition: form-data; name=“cbi.apply” Save & Apply —————————–151563007122428—

2.2 处理

服务器处理过程和页面生成基本类似,也调用到/usr/lib/lua/luci/dispatcher.lua并走到部分,后继处理如下:

ok, err = util.copcall(target, c.target, unpack(args)) à(target在luci/controller/firewall中被赋值为arcombine(cbi(“firewall/zones”), cbi(“firewall/zone-details”)),即两个cbi函数的集合)

function cbi(model, config) à
local function _cbi(self, ...) à
local cstate = res:parse()à
function Map.parse(self, readinput, ...) à
Node.parse(self, ...)
Node.parse会调用Map中的每一个子元素自身的处理

EX:

如调用Flag的处理:function Flag.parse(self, section),他会通过遍历处理from传下来的每一个Flag,并通过本身的write/remove来启用和禁用这个选项。

当form保存下来cbid.firewall.cfg02e63d.syn_flood这个Network/Firewall/General Setting下的Flag标签的值时,处理函数就会调用Flag.parse处理:调用self:formvalue来匹配标签值,然后调用model/cbi/firewall/zones.lua的write或者remove来禁用或者启用这个选项所控制的开关。

由于Flag = class(AbstractValue),继承于AbstractValue类,所以其write/remove是调用的AbstractValue类的write/remove方法。

AbstractValue.write调用self.map:set即function Map.set(self, section, option, value),Map.set 再调用self.uci:set(self.config, section, option, value)来设置对应config文件,然后Map.parse 会调用self.uci:commit(config)对已修改的config逐一提交。

生效的两种方式

1、按照固定格式设置对应选项,系统自动调用来使各个参数生效,self.uci:apply(self.parsechain) (应用刚设置的config设置服务)àfunction Cursor.apply(self, configlist, command) àreturn { “/sbin/luci-reload”, unpack(configlist) };

2、self:_run_hooks(“on_apply”, “on_after_apply”),自己在对应的.lua文件中写m.on_apply来启动或者处理方式。

ps:openwrt个人理解加上前辈的blog来写的,基本是一路打log来了解流程,若有文中问题还请指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值