func (c *Client) packBody(msgId uint16, otherBody []byte) []byte { frameHeader := make([]byte, 24) frameHeader[0] = (frameHeader[0] &^ 0x7) | 0x2 c.Sidx++ binary.LittleEndian.PutUint16(frameHeader[2:4], c.Sidx) dataHeader := make([]byte, 12) binary.LittleEndian.PutUint16(dataHeader[4:6], msgId) binary.LittleEndian.PutUint16(dataHeader[6:8], uint16(len(otherBody))) output := append(frameHeader, dataHeader...) output = append(output, otherBody...) // sum header output[24+8] = msgs.ChecksumHeader(output, 24+8) output[24+9] = msgs.ChecksumHeader(output[24+10:], 2+len(otherBody)) // TODO sum body return output }
func (h *Handler) handle(t *UdpMsg) error { // TODO need decryption later mlen := len(t.Msg) if mlen < FrameHeaderLen { return fmt.Errorf("[protocol] invalid message length for device proxy,reason: mlen < FrameHeaderLen | %v < %v.", mlen, FrameHeaderLen) } // check opcode op := (0x7 & t.Msg[0]) if op != 0x2 && op != 0x3 { return fmt.Errorf("[protocol] reason: wrong opcode, op!=2&&op!=3, op=", op) } if op == 0x2 { if mlen < FrameHeaderLen+DataHeaderLen { return fmt.Errorf("[protocol] invalid message length for protocol, mlen < FrameHeaderLen+DataHeaderLen ,%v < %v", mlen, FrameHeaderLen+DataHeaderLen) } packNum := binary.LittleEndian.Uint16(t.Msg[2:4]) bodyLen := int(binary.LittleEndian.Uint16(t.Msg[FrameHeaderLen+6:])) // discard msg if found checking error if t.Msg[FrameHeaderLen+8] != msgs.ChecksumHeader(t.Msg, FrameHeaderLen+8) { return fmt.Errorf("checksum header error %v!=%v", t.Msg[FrameHeaderLen+8], msgs.ChecksumHeader(t.Msg, FrameHeaderLen+8)) } // check body if t.Msg[FrameHeaderLen+9] != msgs.ChecksumHeader(t.Msg[FrameHeaderLen+10:], 2+bodyLen) { return fmt.Errorf("checksum body error %v!=%v", t.Msg[FrameHeaderLen+9], msgs.ChecksumHeader(t.Msg[FrameHeaderLen+10:], 2+bodyLen)) } var ( sess *UdpSession sid *uuid.UUID err error locker Locker body []byte bodyIndex int ) bodyIndex = FrameHeaderLen + DataHeaderLen if bodyLen != len(t.Msg[bodyIndex:]) { return fmt.Errorf("wrong body length in data header: %d != %d", bodyLen, len(t.Msg[bodyIndex:])) } body = t.Msg[bodyIndex : bodyIndex+bodyLen] // parse data(udp) // 28 = FrameHeaderLen + 4 c := binary.LittleEndian.Uint16(t.Msg[28:30]) if c == CmdSyncState { glog.Infoln("执行设备状态同步") GMsgBusManager.Push2Bus(0, nil, t.Msg) return nil } else if c == 0x31 { glog.Infoln("执行报警信息同步") GMsgBusManager.Push2Bus(0, nil, t.Msg) return nil //TODO alarm msg synchronization } else if c != CmdGetToken { sid, err = uuid.Parse(t.Msg[bodyIndex : bodyIndex+16]) if err != nil { return fmt.Errorf("parse session id error: %v", err) } locker = NewDeviceSessionLocker(sid.String()) err = locker.Lock() if err != nil { return fmt.Errorf("lock session id [%s] failed: %v", sid, err) } sess, err = gUdpSessions.GetSession(sid) if err != nil { locker.Unlock() return fmt.Errorf("cmd: %X, sid: [%v], error: %v", c, sid, err) } err = sess.VerifySession(packNum) if err != nil { locker.Unlock() return fmt.Errorf("cmd: %X, verify session error: %v", c, err) } } output := make([]byte, bodyIndex) // copy same packNum into this ACK response copy(output[:bodyIndex], t.Msg[:bodyIndex]) var res []byte switch c { case CmdGetToken: t.CmdType = c res, err = h.onGetToken(t, body) case CmdRegister: t.CmdType = c t.Url = h.kApiUrls[c] res, err = h.onRegister(t, sess, body) case CmdLogin: t.CmdType = c t.Url = h.kApiUrls[c] res, err = h.onLogin(t, sess, body) case CmdRename: t.CmdType = c t.Url = h.kApiUrls[c] res, err = h.onRename(t, sess, body) //case CmdDoBind: // t.CmdType = c // t.Url = h.kApiUrls[c] // res, err = h.onDoBind(t, sess, body) case CmdHeartBeat: t.CmdType = c res, err = h.onHearBeat(t, sess, body) case CmdSubDeviceOffline: t.CmdType = c res, err = h.onSubDeviceOffline(t, sess, body) // case CmdSyncState: // GMsgBusManager.Push2Bus(0, nil, t.Msg) default: glog.Warningf("invalid command type %v", c) if sess != nil { locker.Unlock() } // don't reply on wrong msgid //b := make([]byte, 4) //binary.LittleEndian.PutUint32(b, uint32(DAckBadCmd)) //output = append(output, b...) //err = computeCheck(output) //if err == nil { // h.Server.Send(t.Peer, output) //} else { // if glog.V(1) { // glog.Warningf("[handle] check message failed: %v", err) // } //} return nil } if sess != nil { gUdpSessions.SaveSession(sid, sess) locker.Unlock() } if err != nil { if glog.V(1) { glog.Errorf("[handle] cmd: %X, error: %v", c, err) } } if c != CmdGetToken { copy(res[4:20], t.Msg[bodyIndex:bodyIndex+16]) copy(res[4:20], sid[:]) } if res != nil { output = append(output, res...) } output[FrameHeaderLen] |= (msgs.FlagAck | msgs.FlagRead) binary.LittleEndian.PutUint16(output[FrameHeaderLen+6:], uint16(len(res))) output[FrameHeaderLen+8] = msgs.ChecksumHeader(output, FrameHeaderLen+8) output[FrameHeaderLen+9] = msgs.ChecksumHeader(output[FrameHeaderLen+10:], 2+len(res)) h.Server.Send(t.Peer, output) } else if op == 0x3 { if mlen < FrameHeaderLen+kSidLen+FrameHeaderLen+DataHeaderLen { return fmt.Errorf("[protocol] invalid message length for protocol") } packNum := binary.LittleEndian.Uint16(t.Msg[2:4]) // bodyLen := int(binary.LittleEndian.Uint16(t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+6:])) // discard msg if found checking error // if t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+8] != msgs.ChecksumHeader(t.Msg, FrameHeaderLen+kSidLen+FrameHeaderLen+8) { // return fmt.Errorf("checksum header error") // } // check data body // if t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+9] != msgs.ChecksumHeader(t.Msg[FrameHeaderLen+kSidLen+FrameHeaderLen+10:], 2+bodyLen) { // return fmt.Errorf("checksum data error") // } var ( sess *UdpSession sid *uuid.UUID err error locker Locker ) //bodyIndex = FrameHeaderLen + DataHeaderLen //if bodyLen != len(t.Msg[bodyIndex:]) { // return fmt.Errorf("wrong body length in data header: %d != %d", bodyLen, len(t.Msg[bodyIndex:])) //} // body = t.Msg[bodyIndex : bodyIndex+bodyLen] sid, err = uuid.Parse(t.Msg[FrameHeaderLen : FrameHeaderLen+kSidLen]) if err != nil { return fmt.Errorf("parse session id error: %v", err) } locker = NewDeviceSessionLocker(sid.String()) err = locker.Lock() if err != nil { return fmt.Errorf("lock session id [%s] failed: %v", sid, err) } sess, err = gUdpSessions.GetSession(sid) if err != nil { locker.Unlock() return fmt.Errorf("[ForwardMsg] sid: [%v], error: %v", sid, err) } err = sess.VerifySession(packNum) if err != nil { locker.Unlock() return fmt.Errorf("[ForwardMsg] verify session error: %v", err) } toId := int64(binary.LittleEndian.Uint64(t.Msg[8:16])) srcId := int64(binary.LittleEndian.Uint64(t.Msg[16:24])) // check binded ids destIds := sess.CalcDestIds(toId) locker.Unlock() if glog.V(3) { glog.Infof("[udp|received] %d -> %d udp, calc to: %v, data: (len: %d)%v...", srcId, toId, destIds, len(t.Msg), t.Msg) } else if glog.V(2) { glog.Infof("[udp|received] %d -> %d udp, calc to: %v, data: (len: %d)%v...", srcId, toId, sess.BindedUsers, destIds, len(t.Msg), t.Msg[0:kDstIdEnd]) } GMsgBusManager.Push2Bus(srcId, destIds, t.Msg) } return nil }