package xlog import ( "bytes" "encoding/binary" "errors" "fmt" "fwh-toolbox-server/logger" "strings" ) const ( // Magic word _MAGIC_XLOG_SYSTEM_ uint32 = 0x99A3B417 // ARM的日志发送给PC // CmdType 命令类型 mainCmd(8bit) + subCmd(8bit) // mainCmd _XLOG_CMD_LOG_TO_PC_ uint8 = 0 // 心跳内容, 内容为"[x]\n" _XLOG_CMD_REPORT_BASICINFO_ uint8 = 1 // 上报sn + mac, 结构为 XlogSiteBaseInfo _XLOG_CMD_REPLY_BASICINFO_ uint8 = 2 // 回复sn + mac,暂不回复 _XLOG_P2P_EXEC_BASH_CMD_ uint8 = 64 // pc -> SERNAME_UB_SERVER -> xlogv3, 执行远程命令 _XLOG_P2P_BASH_CMD_RESULT_ uint8 = 65 // xlogv3-> SERNAME_UB_SERVER -> pc 返回远程命令执行结果 ) func NewXlogPackageParser(ctx *ConnectContext) *XlogPackageParser { return &XlogPackageParser{ crypt: NewXlogEncrypt(), ctx: ctx, cmdResultStr: "", Handshake: false, Buffer: make([]byte, 0), } } // 解析设备握手包 func (parser *XlogPackageParser) ParseXlogHandshakePackage(raw []byte) (*XlogHandshakePackageData, error) { reader := bytes.NewReader(raw) // 数据长度校验 if len(raw) != 72 { return nil, fmt.Errorf("invalid handshake packet: data length error, expected 72, got %d", len(raw)) } // 解析数据结构 var p XlogHandshakePackage if err := binary.Read(reader, binary.LittleEndian, &p); err != nil { return nil, err } // 校验数据头 if p.MagicWord != _MAGIC_XLOG_SYSTEM_ { return nil, errors.New("invalid magic") } if p.CmdLen != uint32(len(raw)-8) { return nil, fmt.Errorf("invalid handshake packet: data length error, CmdLen: %d", p.CmdLen) } // 解密数据 handshakeData, err := parser.crypt.DecryptData(p.EncryptData[:]) if err != nil { return nil, err } // 数据长度校验 if len(handshakeData) != (16 + 36) { return nil, fmt.Errorf("invalid handshake packet: data length error, expected 52, got %d", len(handshakeData)) } // 解析握手数据结构 var h XlogHandshakePackageData reader = bytes.NewReader(handshakeData) if err := binary.Read(reader, binary.LittleEndian, &h); err != nil { return nil, err } // 更新IV if err := parser.crypt.SetNewIv(h.NewIv[:]); err != nil { return nil, err } return &h, nil } // 预解析数据包,数据提取,提取一个完整数据包 func (parser *XlogPackageParser) PreparserXlogPackage(raw []byte) { // 累积数据 parser.Buffer = append(parser.Buffer, raw...) buffer := parser.Buffer for { // 不够一个包头和长度字段,继续收 if len(buffer) < 8 { return } // 查找合法包头 header := binary.LittleEndian.Uint32(buffer[:4]) if header != _MAGIC_XLOG_SYSTEM_ { // 丢掉 1 字节,继续找包头 buffer = buffer[1:] continue } // 读取长度 length := binary.LittleEndian.Uint32(buffer[4:8]) totalLen := 8 + int(length) // 数据是否完整 if len(buffer) < totalLen { break } // 提取完整包 packet := buffer[:totalLen] // 异步处理 go parser.ParseXlogPackage(packet) // 移除已处理的数据 parser.Buffer = buffer[totalLen:] buffer = parser.Buffer } } // 处理设备心跳信息 func (parser XlogPackageParser) handleHeartbeat(raw []byte) { logger.Std.Printf("%s - 接收到心跳:%s", parser.ctx.UUID, string(raw)) } // 处理设备基本信息 func (parser XlogPackageParser) handleSiteBaseInfo(raw []byte) { // 解析基本信息 infoReader := bytes.NewReader(raw) var info XlogSiteBaseInfo if err := binary.Read(infoReader, binary.LittleEndian, &info); err != nil { logger.Std.Printf("handleSiteBaseInfo failed: %s\n", err) return } // 更新SN parser.ctx.SN = string(bytes.TrimRight(info.SN[:], "\x00")) logger.Std.Printf("update SN: %s\n", parser.ctx.SN) logger.Std.Println("握手成功") } // 处理命令执行结果 func (parser *XlogPackageParser) handleCmdResult(raw []byte) { resStr := string(raw[:]) if strings.HasPrefix(resStr, "\n***above is result of:") { parser.cmdResultStr = parser.cmdResultStr + resStr select { case parser.ctx.DoneChan <- parser.cmdResultStr: // 成功写入结果 logger.Std.Printf("%s - 回传结果:%s\n", parser.ctx.UUID, parser.cmdResultStr) default: // channel 已经满(说明调用方可能已经超时退出了) logger.Std.Printf("%s - DoneChan已满或超时。\n", parser.ctx.UUID) } } else { parser.cmdResultStr = resStr } } // 解析设备数据包 func (parser *XlogPackageParser) ParseXlogPackage(raw []byte) { // 数据长度校验 headerPackageSize := binary.Size(XlogPackageHeader{}) if len(raw) < headerPackageSize { logger.Std.Printf("invalid packet: data length error, expected >= %d, got %d\n", headerPackageSize, len(raw)) return } headerRaw := raw[:headerPackageSize] // 非加密头部 headerReader := bytes.NewReader(headerRaw) // 解析头部 var h XlogPackageHeader if err := binary.Read(headerReader, binary.LittleEndian, &h); err != nil { logger.Std.Printf("XlogPackage header parsing error: %s\n", err.Error()) return } if len(raw) > headerPackageSize { encryptRaw := raw[headerPackageSize:] // 加密数据 // 解密Payload bodyRaw, err := parser.crypt.DecryptData(encryptRaw) if err != nil { logger.Std.Println("DecryptData error: " + err.Error()) return } // 判断包类型 switch h.MainCmd { case _XLOG_CMD_LOG_TO_PC_: parser.handleHeartbeat(bodyRaw) case _XLOG_CMD_REPORT_BASICINFO_: parser.handleSiteBaseInfo(bodyRaw) case _XLOG_P2P_BASH_CMD_RESULT_: parser.handleCmdResult(bodyRaw) } } } // 创建握手响应包 func (parser XlogPackageParser) CreateXlogHandshakePackage() ([]byte, error) { encryptData, err := parser.crypt.EncryptData([]byte("0123456789abcdef")) if err != nil { return nil, err } buf := new(bytes.Buffer) // 按小端序写入,先写头部 if err := binary.Write(buf, binary.LittleEndian, _MAGIC_XLOG_SYSTEM_); err != nil { return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage magic word: %w", err) } if err := binary.Write(buf, binary.LittleEndian, uint32(32)); err != nil { return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage magic word: %w", err) } // 再写 EncryptData if _, err := buf.Write(encryptData); err != nil { return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage EncryptData: %w", err) } return buf.Bytes(), nil } // 创建发送命令数据包 func (parser XlogPackageParser) CreateXlogCmdPackage(payload []byte) ([]byte, error) { var dstServiceName [12]byte copy(dstServiceName[:], "Xlog") h := XlogPackageHeader{ MagicWord: _MAGIC_XLOG_SYSTEM_, CmdLen: 0, MainCmd: _XLOG_P2P_EXEC_BASH_CMD_, SubCmd: 0, ControlBitData: 0, DstServiceName: dstServiceName, ToBeSendLen: 0, IgnoredLen: 0, UpTime: 0, } encryptData := []byte{} if len(payload) > 0 { encrypted, err := parser.crypt.EncryptData(payload) if err != nil { return nil, err } encryptData = encrypted } // 36是XlogPackageHeader字节数,8是MagicWord + CmdLen字节数 h.CmdLen = uint32(36 + len(encryptData) - 8) p := XlogPackage{ Header: h, EncryptPayload: encryptData, } buf := new(bytes.Buffer) // 按小端序写入,先写头部 if err := binary.Write(buf, binary.LittleEndian, p.Header); err != nil { return nil, fmt.Errorf("failed to write XlogPackage header: %w", err) } // 再写 payload if _, err := buf.Write(p.EncryptPayload); err != nil { return nil, fmt.Errorf("failed to write XlogPackage payload: %w", err) } return buf.Bytes(), nil }