package axle_device import ( "fmt" "log/slog" "joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/udp" ) // 铁路信号安全通信协议实现 // HandleUserData 回调应用层 type HandleUserData func([]byte) // RsspChannel 实现rssp通信 type RsspChannel struct { //udp udpServer udp.UdpServer //udp udpClient udp.UdpClient //回调应用层 handleUserData HandleUserData //rssp安全通信配置 config *config.RsspConfig //rssp时钟 rsspTimer *RsspTimer //批次编号,发送序列号 sn *message.RsspSn //安全通道1时间戳 ch1Ts *message.RsspLFSR //安全通道2时间戳 ch2Ts *message.RsspLFSR //最近一次接收到的报文的安全通道1时间戳 rcvCh1Ts uint32 //最近一次接收到的报文的安全通道2时间戳 rcvCh2Ts uint32 //最近一次接收到的报文的序列号 rcvSn uint32 //时序校验请求发送记录 sendSseRecord *SseFireRecord } func (s *RsspChannel) SetRcvUserDataCallback(handleUserData HandleUserData) { s.handleUserData = handleUserData } func (s *RsspChannel) Init(config *config.RsspConfig) *RsspChannel { s.config = config s.rsspTimer = &RsspTimer{t: 0} s.sn = message.NewRsspSn(1) s.ch1Ts = message.NewRsspLFSR(message.RSSP_I_C1_TS, 32, s.config.SID1, false) s.ch2Ts = message.NewRsspLFSR(message.RSSP_I_C2_TS, 32, s.config.SID2, false) return s } // Start 启动安全通道 func (s *RsspChannel) Start() { // s.udpServer = udp.NewServer(fmt.Sprintf(":%d", s.config.LocalUdpPort), s.handleRsspMsg) s.udpServer.Listen() // s.udpClient = udp.NewClient(fmt.Sprintf("%s:%d", s.config.RemoteIp, s.config.RemoteUdpPort)) } // Stop 关闭安全通道 func (s *RsspChannel) Stop() { if s.udpServer != nil { s.udpServer.Close() } if s.udpClient != nil { s.udpClient.Close() } } // RsspTimer rssp时钟,每一个tick周期为config.SendingPeriod type RsspTimer struct { t uint64 } func (s *RsspTimer) tick() { s.t++ } func (s *RsspTimer) now() uint64 { return s.t } // SseFireRecord 发送时序校验请求的记录 type SseFireRecord struct { send *message.RsspSse //已经发送的时序校验请求 rsspTime uint64 //发送时序校验请求时的rssp时间 } func (s *SseFireRecord) record(send *message.RsspSse, rsspTime uint64) { s.send = send s.rsspTime = rsspTime } func (s *SseFireRecord) clear() { s.send = nil s.rsspTime = 0 } func (s *SseFireRecord) hasRecord() bool { return s.send != nil } // 处理接收到的rssp报文 // 注意本函数由udp socket 协程执行 func (s *RsspChannel) handleRsspMsg(pack []byte) { slog.Debug("接收到RSSP报文", "len", len(pack)) //报文头校验 head := &message.RsspHead{} if !head.Parse(pack) { //解析报文头失败 slog.Debug("丢弃接收的RSSP报文:解析报文头失败") return } if !message.RsspHeadMcCheck(head) { //报文类别检测未通过 slog.Debug("丢弃接收的RSSP报文:报文类别检测未通过") return } if !message.RsspHeadPicCheck(head) { //协议交互类别检测未通过 slog.Debug("丢弃接收的RSSP报文:协议交互类别检测未通过") return } if !s.config.CheckAddress(head.Sa, head.Da) { //校验报文头中源地址和目的地址是否包含在已配置列表中 slog.Debug("丢弃接收的RSSP报文:报文头中源地址或目的地址不在在已配置列表中") return } //报文尾校验 if !message.RsspPackCrc16Check(pack) { //整个报文crc16校验未通过 slog.Debug("丢弃接收的RSSP报文:报文尾CRC16校验未通过") return } //解析得到RSD、SSE或SRE rssp := message.ParseRsspPack(head, pack) if rssp == nil { //解析具体rssp包失败 slog.Debug("丢弃接收的RSSP报文:解析具体类别包失败") return } //处理接收到的具体类别RSSP包 switch rssp.Type() { case message.RSD_A: fallthrough case message.RSD_B: s.handleRsspRsd(rssp.(*message.RsspRsd)) case message.SSE: s.handleRsspSse(rssp.(*message.RsspSse)) case message.SSR: s.handleRsspSsr(rssp.(*message.RsspSsr)) } } // 处理接收到的实时安全数据 RSD func (s *RsspChannel) handleRsspRsd(rsd *message.RsspRsd) { //slog.Debug("接收到的实时安全数据 RSD") //如果为备机发送来的安全数据 if s.config.PicType == message.PIC_SLAVE { //备安全通道 slog.Debug("丢弃接收的RSSP-RSD报文:舍弃在备安全通道中接收到的安全数据") //备安全通道收到安全数据,表示该物理通道连接正常 return } //如果为主机发送来的安全数据 if s.config.PicType == message.PIC_MASTER { //主安全通道 if !rsd.IsMaster() { slog.Debug("丢弃接收的RSSP-RSD报文:舍弃在主安全通道中收到的非主机发送来的安全数据") return } } //序列号校验 //接收的序列号小于最近一次有效序列号,则触发SSE时序校验 if rsd.Sn < s.rcvSn { slog.Debug("丢弃接收的RSSP-RSD报文:当前接收RSD的序列号小于最近一次接收的RSD的序列号,触发SSE") s.fireSse(rsd) return } dSn := rsd.Sn - s.rcvSn if dSn > s.config.Mtv { slog.Debug("丢弃接收的RSSP-RSD报文:当前接收RSD的序列号与最近一次接收的RSD的序列号差值过大,触发SSE") s.fireSse(rsd) return } //SVC校验 c1Crc32 := message.Rssp_I_Crc32C1(rsd.Sad) c1SidTs := c1Crc32 ^ rsd.Svc1 ^ message.RSSP_I_C1_SCW //T(n) // c2Crc32 := message.Rssp_I_Crc32C2(rsd.Sad) c2SidTs := c2Crc32 ^ rsd.Svc2 ^ message.RSSP_I_C2_SCW //T(n) //todo ... SVC校验待完善 _ = c1SidTs _ = c2SidTs //校验通过 //记录本次接收RSD的序列号和安全校验通道时间戳 s.rcvSn = rsd.Sn s.rcvCh1Ts = c1SidTs ^ s.config.SID1 s.rcvCh2Ts = c2SidTs ^ s.config.SID2 //通知应用层接收应用数据 s.handleUserData(rsd.Sad) } // 触发时序校正请求 func (s *RsspChannel) fireSse(rsd *message.RsspRsd) { s.sendSseRecord = &SseFireRecord{send: s.sendSse(), rsspTime: s.rsspTimer.now()} } // 接收到时序校正请求 func (s *RsspChannel) handleRsspSse(sse *message.RsspSse) { if s.config.PicType != message.PIC_MASTER { slog.Debug("丢弃接收的RSSP-SSE报文:在非主安全通道中收到时序校正请求SSE") return } //发送时序校正响应 s.sendSsr(sse) } // 接收到时序校正应答 func (s *RsspChannel) handleRsspSsr(ssr *message.RsspSsr) { //SSR校验 if !s.sendSseRecord.hasRecord() { slog.Debug("丢弃接收的RSSP-SSR报文:未发起过SSE时序校正请求") return } if s.rsspTimer.t-s.sendSseRecord.rsspTime > uint64(s.config.SsrRsspTimeout) { slog.Debug("丢弃接收的RSSP-SSR报文:等待SSE响应超时") return } if ssr.SeSn != s.sendSseRecord.send.Sn { slog.Debug("丢弃接收的RSSP-SSR报文:SSR与SSE不对应") return } //恢复时序? s.rcvSn = ssr.SrSn s.rcvCh1Ts = ssr.Tic1 ^ s.sendSseRecord.send.SeqEnq1 ^ s.config.SID1 ^ s.config.DataVer1 s.rcvCh2Ts = ssr.Tic2 ^ s.sendSseRecord.send.SeqEnq2 ^ s.config.SID2 ^ s.config.DataVer2 } // NextPeriod 刷新与周期有关的:将序列号和时间戳更新到下一个值 func (s *RsspChannel) NextPeriod() { s.sn.GetAndAdd() s.ch1Ts.GetAndMove() s.ch2Ts.GetAndMove() s.rsspTimer.tick() } // 发送时序校正应答 func (s *RsspChannel) sendSsr(sse *message.RsspSse) { ssr := &message.RsspSsr{} // ssr.Pic = message.PIC_MASTER ssr.Mc = message.SSR ssr.Sa = s.config.SrcAddr ssr.Da = s.config.DstAddr ssr.SrSn = s.sn.Get() //当前序列号 ssr.SeSn = sse.Sn ssr.Tic1 = sse.SeqEnq1 ^ s.config.SID1 ^ s.ch1Ts.Get() ^ s.config.DataVer1 ssr.Tic2 = sse.SeqEnq2 ^ s.config.SID2 ^ s.ch2Ts.Get() ^ s.config.DataVer2 ssr.Dvn = 0x01 //预留固定值 // rsspPack := ssr.Encode() s.sendPack(rsspPack) } // 发送时序校正请求 func (s *RsspChannel) sendSse() *message.RsspSse { sse := &message.RsspSse{} // sse.Pic = message.PIC_MASTER sse.Mc = message.SSE sse.Sa = s.config.SrcAddr sse.Da = s.config.DstAddr //时序校正请求,把最近一次接收到的报文中的序列号时间戳发送给发送方 sse.Sn = s.rcvSn sse.SeqEnq1 = s.createSeqNeq(s.config.SID1, s.rcvCh1Ts) sse.SeqEnq2 = s.createSeqNeq(s.config.SID2, s.rcvCh2Ts) // rsspPack := sse.Encode() s.sendPack(rsspPack) // return sse } // SendUserData 发送用户数据,即通过rssp安全通道发送应用层数据,通过rssp的RSD报文发送 func (s *RsspChannel) SendUserData(userData []byte) { rsd := &message.RsspRsd{} rsd.Pic = s.config.PicType if s.config.DeviceA { rsd.Mc = message.RSD_A } else { rsd.Mc = message.RSD_B } rsd.Sa = s.config.SrcAddr rsd.Da = s.config.DstAddr // rsd.Sn = s.sn.Get() rsd.Sdl = uint16(len(userData) + 8) //安全校验通道SVC_1 crc_c1 := message.Rssp_I_Crc32C1(userData) rsd.Svc1 = s.createSvcCode(crc_c1, s.config.SID1, s.ch1Ts.Get(), message.RSSP_I_C1_SCW) //安全校验通道SVC_2 crc_c2 := message.Rssp_I_Crc32C2(userData) rsd.Svc1 = s.createSvcCode(crc_c2, s.config.SID2, s.ch2Ts.Get(), message.RSSP_I_C2_SCW) rsd.Sad = userData // rsspPack := rsd.Encode() s.sendPack(rsspPack) } func (s *RsspChannel) createSvcCode(crc32 uint32, sid uint32, ts uint32, scw uint32) uint32 { return crc32 ^ sid ^ ts ^ scw } func (s *RsspChannel) createSeqNeq(sid uint32, ts uint32) uint32 { return sid ^ ts } // 通过网络发送数据 func (s *RsspChannel) sendPack(rsspPack []byte) { s.udpClient.Send(rsspPack) }