TeamsACS 对于 BootStrap Event 的处理逻辑

更新日期: 2023-05-02 阅读次数: 1406 字数: 628 分类: 物联网

实际上类似于 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 聊聊, 查看更多联系方式

tags: tr069