コード例 #1
0
ファイル: udp.go プロジェクト: ljvblfz/slot-golang
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
}
コード例 #2
0
ファイル: udp_handler.go プロジェクト: ljvblfz/slot-golang
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
}