实际上类似于 TeamsACS 对于 PERIODIC Event 的处理逻辑 的处理逻辑, 只不过多了一个 UpdateManagementAuthInfo 的处理流程。
UpdateManagementAuthInfo 的调用参数
err = cpe.UpdateManagementAuthInfo("bootstrap-session-"+common.UUID(), 1000, false)
UpdateManagementAuthInfo 的定义
主要逻辑就是由 ACS 向 CPE 发送 auth 用的 username / password。
- username 直接使用了 sn. 并没有使用 tr069 协议规定的格式
- password 的生成,需要看一下具体逻辑
func (c *CwmpCpe) UpdateManagementAuthInfo(session string, timeout int, hp bool) error {
return c.SendCwmpEventData(models.CwmpEventData{
Session: session,
Sn: c.Sn,
Message: &cwmp.SetParameterValues{
ID: session,
Name: "",
NoMore: 0,
Params: map[string]cwmp.ValueStruct{
"Device.ManagementServer.ConnectionRequestUsername": {
Type: "xsd:string",
Value: c.Sn,
},
"Device.ManagementServer.ConnectionRequestPassword": {
Type: "xsd:string",
Value: app.GetTr069SettingsStringValue("CpeConnectionRequestPassword"),
},
},
},
}, timeout, hp)
}
SendCwmpEventData
// SendCwmpEventData 发送一个 Cwmp 事件,
func (c *CwmpCpe) SendCwmpEventData(data models.CwmpEventData, timeoutMsec int, hp bool) error {
select {
case c.getQueue(hp) <- data:
return nil
case <-time.After(time.Millisecond * time.Duration(timeoutMsec)):
return errors.New("cwmp event channel full, write timeout")
}
}
func (c *CwmpCpe) getQueue(hp bool) chan models.CwmpEventData {
var que = c.cwmpQueueMap
if hp {
que = c.cwmpHPQueueMap
}
return que
}
type CwmpCpe struct {
Sn string `json:"sn"`
OUI string `json:"oui"`
taskTags []string
SoftwareVersion string `json:"software_version"`
Manufacturer string `json:"manufacturer"`
ProductClass string `json:"product_class"`
cwmpQueueMap chan models.CwmpEventData
cwmpHPQueueMap chan models.CwmpEventData
LastInform *cwmp.Inform `json:"latest_message"`
LastUpdate time.Time `json:"last_update"`
LastDataNotify time.Time `json:"last_data_notify"`
IsRegister bool `json:"is_register"`
}
// RecvCwmpEventData 接收一个 Cwmp 事件
func (c *CwmpCpe) RecvCwmpEventData(timeoutMsec int, hp bool) (data *models.CwmpEventData, err error) {
select {
case _data := <-c.getQueue(hp):
return &_data, nil
case <-time.After(time.Millisecond * time.Duration(timeoutMsec)):
return nil, errors.New("read cwmp event channel timeout")
}
}
消息接收/处理
至于调用 RecvCwmpEventData 则是在 tr069/handlers.go 中
// 当 CPE 发送空消息时检测 CPE任务队列
lastestSn := s.GetLatestCookieSn(c)
if lastestSn == "" {
return noContentResp(c)
}
cpe := app.GApp().CwmpTable().GetCwmpCpe(lastestSn)
// 首先处理预设任务
ptask, err := cpe.GetLatestCwmpPresetTask()
if err == nil && ptask != nil && len(ptask.Request) > 0 {
return xmlCwmpMessage(c, []byte(ptask.Request))
}
// 获取队列任务
msg, err := cpe.RecvCwmpEventData(1000, true)
if err != nil {
msg, _ = cpe.RecvCwmpEventData(1000, false)
}
if msg != nil {
if msg.Session != "" {
events.PubEventCwmpSuperviseStatus(lastestSn, msg.Session, "info",
fmt.Sprintf("Send Cwmp %s Message %s", msg.Message.GetName(), common.ToJson(msg.Message)))
}
return xmlCwmpMessage(c, msg.Message.CreateXML())
}
密码的生成
// GetTr069SettingsStringValue Get tr069 settings string value
func (a *Application) GetTr069SettingsStringValue(name string) string {
return a.GetSettingsStringValue("tr069", name)
}
搜索 CpeConnectionRequestPassword 来看看有哪些地方会生成密码:
> grep CpeConnectionRequestPassword -r ./
./app/constant.go: ConfigCpeConnectionRequestPassword = "CpeConnectionRequestPassword"
./app/constant.go: ConfigCpeConnectionRequestPassword,
./app/cwmp.go: Value: app.GetTr069SettingsStringValue("CpeConnectionRequestPassword"),
./app/cwmp.go: ConfigCpeConnectionRequestPassword: a.GetTr069SettingsStringValue(ConfigCpeConnectionRequestPassword),
./app/initdb.go: case ConfigCpeConnectionRequestPassword:
./app/initdb.go: checkConfig(sortid, "tr069", ConfigCpeConnectionRequestPassword, "teamsacscpepassword", "CPE Connection authentication password, It is provided to TeamsACS to access CPE")
./assets/static/views/settings.js: name: "CpeConnectionRequestPassword",
./assets/static/views/settings.min.js:name:"TR069AccessPassword",labelPosition:"top",label:tr("settings","TR069 access password"),bottomLabel:tr("settings","Teamsacs TR069 access password, It is provided to CPE to access TeamsACS")},{view:"text",name:"CpeConnectionRequestPassword",labelPosition:"top",label:tr("settings","CPE Connection authentication password"),bottomLabel:tr("settings","tr069 The authentication password used when the server connects to cpe")},{view:"template",css:"form-desc",height:200,borderless:!0,src:"/admin/settings/tr069/quickset"}]}]}};
./controllers/supervise/cwmp.go: isok, err := cwmp.ConnectionRequestAuth(dev.Sn, app.GApp().GetTr069SettingsStringValue("CpeConnectionRequestPassword"), dev.CwmpUrl)
疑问
但是此处有几个疑问:
- 为何只有当 ACS 收到空消息时才检查消息队列。为何不是立即/异步处理
- 这里使用 golang channel 的好处是什么?相对于普通的消息队列服务
- 密码的生成机制是啥
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式