diff --git a/device.go b/device.go index 116bbf9..6087814 100644 --- a/device.go +++ b/device.go @@ -41,6 +41,17 @@ const ( msgTypeFileAbort ) +const ( + msgRegAttrHeartbeat = iota + msgRegAttrDevid + msgRegAttrDescription + msgRegAttrToken +) + +const ( + msgHeartbeatAttrUptime = iota +) + // Minimum protocol version requirements of rtty const rttyProtoRequired uint8 = 3 @@ -153,24 +164,36 @@ func (dev *device) Close() { } func parseDeviceInfo(dev *device, b []byte) bool { - if len(b) < 2 { + if len(b) < 1 { return false } dev.proto = b[0] if dev.proto > 4 { - if len(b) < 4 { + attrs := parseTLV(b[1:]) + if attrs == nil { return false } - dev.heartbeat = time.Duration(binary.BigEndian.Uint16(b[1:3])) * time.Second - b = b[3:] - } else { + for typ, val := range attrs { + switch typ { + case msgRegAttrHeartbeat: + dev.heartbeat = time.Duration(val[0]) * time.Second + case msgRegAttrDevid: + dev.id = string(val) + case msgRegAttrDescription: + dev.desc = string(val) + case msgRegAttrToken: + dev.token = string(val) + } + } - b = b[1:] + return true } + b = b[1:] + fields := bytes.Split(b, []byte{0}) if len(fields) < 3 { @@ -184,8 +207,27 @@ func parseDeviceInfo(dev *device, b []byte) bool { return true } -func parseHeartbeat(dev *device, b []byte) { - dev.uptime = binary.BigEndian.Uint32(b[:4]) +func parseHeartbeat(dev *device, b []byte) bool { + if dev.proto > 4 { + attrs := parseTLV(b) + if attrs == nil { + return false + } + + for typ, val := range attrs { + switch typ { + case msgHeartbeatAttrUptime: + dev.uptime = binary.BigEndian.Uint32(val) + } + } + } else { + if len(b) < 4 { + return false + } + dev.uptime = binary.BigEndian.Uint32(b[:4]) + } + + return true } func msgTypeName(typ byte) string { @@ -327,11 +369,10 @@ func (dev *device) readLoop() { dev.br.httpResp <- &httpResp{b, dev} case msgTypeHeartbeat: - if msgLen < 4 { + if !parseHeartbeat(dev, b) { log.Error().Msgf("%s: msgTypeHeartbeat: invalid", logPrefix) return } - parseHeartbeat(dev, b) dev.br.heartbeat <- dev.id default: log.Error().Msgf("%s: invalid msg type: %d", logPrefix, typ) diff --git a/tlv.go b/tlv.go new file mode 100644 index 0000000..4b61150 --- /dev/null +++ b/tlv.go @@ -0,0 +1,38 @@ +package main + +import ( + "bytes" + "encoding/binary" + "io" +) + +func parseTLV(data []byte) map[uint8][]byte { + if len(data) < 3 { + return nil + } + + tlvs := map[uint8][]byte{} + + reader := bytes.NewReader(data) + + for reader.Len() > 0 { + typ, _ := reader.ReadByte() + + var length uint16 + err := binary.Read(reader, binary.BigEndian, &length) + if err != nil { + return nil + } + + value := make([]byte, length) + + _, err = io.ReadFull(reader, value) + if err != nil { + return nil + } + + tlvs[typ] = value + } + + return tlvs +}