internal void ProcessInPacket(MsMessage msg) { if(_statistic.value && msg.MsgTyp!=MsMessageType.EncapsulatedMessage && msg.MsgTyp!=MsMessageType.PUBLISH) { Stat(false, msg.MsgTyp); } switch(msg.MsgTyp) { case MsMessageType.WILLTOPIC: { var tmp=msg as MsWillTopic; if(state==State.WillTopic) { _willPath=tmp.Path; _willRetain=tmp.Retain; state=State.WillMsg; ProccessAcknoledge(msg); } } break; case MsMessageType.WILLMSG: { var tmp=msg as MsWillMsg; if(state==State.WillMsg) { _wilMsg=tmp.Payload; Log.Info("{0}.state {1} => WILLTOPICREQ", Owner.path, state); state=State.PreConnect; ProccessAcknoledge(msg); Send(new MsConnack(MsReturnCode.Accepted)); } } break; case MsMessageType.SUBSCRIBE: { var tmp=msg as MsSubscribe; SyncMsgId(msg.MessageId); Topic.Subscription s=null; ushort topicId=tmp.topicId; if(tmp.topicIdType!=TopicIdType.Normal || tmp.path.IndexOfAny(new[] { '+', '#' })<0) { TopicInfo ti=null; if(tmp.topicIdType==TopicIdType.Normal) { ti=GetTopicInfo(tmp.path, false); } else { ti=GetTopicInfo(tmp.topicId, tmp.topicIdType); } topicId=ti.TopicId; } Send(new MsSuback(tmp.qualityOfService, topicId, msg.MessageId, MsReturnCode.Accepted)); if(state==State.PreConnect) { state=State.Connected; } s=Owner.Subscribe(tmp.path, PublishTopic, tmp.qualityOfService); _subsscriptions.Add(s); } break; case MsMessageType.REGISTER: { var tmp=msg as MsRegister; ResetTimer(); try { TopicInfo ti = GetTopicInfo(tmp.TopicPath, false); if(ti.topic!=null) { if(ti.topic.valueType==typeof(SmartTwi)) { if(ti.topic.GetValue()==null) { ti.topic.SetValue(new SmartTwi(ti.topic), new TopicChanged(TopicChanged.ChangeArt.Value, Owner)); } else { (ti.topic as DVar<SmartTwi>).value.Reset(); } } else if(ti.topic.valueType==typeof(TWIDriver)) { if(ti.topic.GetValue()==null) { ti.topic.SetValue(new TWIDriver(ti.topic), new TopicChanged(TopicChanged.ChangeArt.Value, Owner)); } else { (ti.topic as DVar<TWIDriver>).value.Reset(); } } } Send(new MsRegAck(ti.TopicId, tmp.MessageId, MsReturnCode.Accepted)); } catch(Exception) { Send(new MsRegAck(0, tmp.MessageId, MsReturnCode.NotSupportes)); Log.Warning("Unknown variable type by register {0}, {1}", Owner.path, tmp.TopicPath); } } break; case MsMessageType.REGACK: { var tmp=msg as MsRegAck; ProccessAcknoledge(tmp); TopicInfo ti=_topics.FirstOrDefault(z => z.TopicId==tmp.TopicId); if(ti==null) { if(tmp.TopicId!=0xFFFF) { // 0xFFFF - remove variable Log.Warning("{0} RegAck({1:X4}) for unknown variable", Owner.path, tmp.TopicId); } return; } if(tmp.RetCode==MsReturnCode.Accepted) { ti.registred=true; if(ti.it!=TopicIdType.PreDefined) { Send(new MsPublish(ti.topic, ti.TopicId, QoS.AtLeastOnce)); } } else { Log.Warning("{0} registred failed: {1}", ti.path, tmp.RetCode.ToString()); _topics.Remove(ti); ti.topic.Remove(); } } break; case MsMessageType.PUBLISH: { var tmp=msg as MsPublish; if(_statistic.value) { Stat(false, msg.MsgTyp, tmp.Dup); } TopicInfo ti=_topics.Find(z => z.TopicId==tmp.TopicId && z.it==tmp.topicIdType); if(ti==null && tmp.topicIdType!=TopicIdType.Normal) { ti=GetTopicInfo(tmp.TopicId, tmp.topicIdType, false); } if(tmp.qualityOfService==QoS.AtMostOnce || (tmp.qualityOfService==QoS.MinusOne && (tmp.topicIdType==TopicIdType.PreDefined || tmp.topicIdType==TopicIdType.ShortName))) { ResetTimer(); } else if(tmp.qualityOfService==QoS.AtLeastOnce) { SyncMsgId(tmp.MessageId); Send(new MsPubAck(tmp.TopicId, tmp.MessageId, ti!=null?MsReturnCode.Accepted:MsReturnCode.InvalidTopicId)); } else if(tmp.qualityOfService==QoS.ExactlyOnce) { SyncMsgId(tmp.MessageId); // QoS2 not supported, use QoS1 Send(new MsPubAck(tmp.TopicId, tmp.MessageId, ti!=null?MsReturnCode.Accepted:MsReturnCode.InvalidTopicId)); } else { throw new NotSupportedException("QoS -1 not supported "+Owner.path); } if(tmp.topicIdType==TopicIdType.PreDefined && tmp.TopicId>=LOG_D_ID && tmp.TopicId<=LOG_E_ID) { string str=string.Format("{0} msgId={2:X4} msg={1}", this.Owner.name, tmp.Data==null?"null":(BitConverter.ToString(tmp.Data)+"["+ Encoding.ASCII.GetString(tmp.Data.Select(z => (z<0x20 || z>0x7E)?(byte)'.':z).ToArray())+"]"), tmp.MessageId); switch(tmp.TopicId) { case LOG_D_ID: Log.Debug("{0}", str); break; case LOG_I_ID: Log.Info("{0}", str); break; case LOG_W_ID: Log.Warning("{0}", str); break; case LOG_E_ID: Log.Error("{0}", str); break; } } else if(ti!=null) { if(tmp.Dup && _lastInPub!=null && tmp.MessageId==_lastInPub.MessageId) { // arready recieved } else { SetValue(ti, tmp.Data, tmp.Retained); } _lastInPub=tmp; } } break; case MsMessageType.PUBACK: { ProccessAcknoledge(msg); } break; case MsMessageType.PINGREQ: { var tmp=msg as MsPingReq; if(state==State.ASleep) { if(string.IsNullOrEmpty(tmp.ClientId) || tmp.ClientId==Owner.name) { state=State.AWake; ProccessAcknoledge(msg); // resume send proccess } else { SendGw(this, new MsDisconnect()); state=State.Lost; Log.Warning("{0} PingReq from unknown device: {1}", Owner.path, tmp.ClientId); } } else { ResetTimer(); if(_gate!=null) { _gate.SendGw(this, new MsMessage(MsMessageType.PINGRESP)); if(_statistic.value) { Stat(true, MsMessageType.PINGRESP, false); } } } } break; case MsMessageType.DISCONNECT: Disconnect((msg as MsDisconnect).Duration); break; case MsMessageType.CONNECT: Connect(msg as MsConnect); break; case MsMessageType.EncapsulatedMessage: { Topic devR=Topic.root.Get("/dev"); var fm=msg as MsForward; if(fm.msg==null) { if(_verbose.value) { Log.Warning("bad message {0}:{1}", _gate, fm.ToString()); } return; } if(fm.msg.MsgTyp==MsMessageType.SEARCHGW) { _gate.SendGw(this, new MsGwInfo(gwIdx)); } else if(fm.msg.MsgTyp==MsMessageType.DHCP_REQ) { var dr=fm.msg as MsDhcpReq; //****************************** List<byte> ackAddr=new List<byte>(); byte[] respPrev=null; foreach(byte hLen in dr.hLen) { if(hLen==0) { continue; } else if(hLen<=8) { byte[] resp; if(respPrev!=null && respPrev.Length==hLen) { resp=respPrev; } else { resp=new byte[hLen]; for(int i=0; i<5; i++) { for(int j=0; j<resp.Length; j++) { resp[j]=(byte)_rand.Next((i<3 && hLen==1)?32:1, (i<3 && hLen==1)?126:(j==0?254:255)); } if(devR.children.Select(z => z as DVar<MsDevice>).Where(z => z!=null && z.value!=null).All(z => !z.value.CheckAddr(resp))) { break; } else if(i==4) { for(int j=0; j<resp.Length; j++) { resp[j]=0xFF; } } } respPrev=resp; } ackAddr.AddRange(resp); } else { if(_verbose.value) { Log.Warning("{0}:{1} DhcpReq.hLen is too high", BitConverter.ToString(fm.addr), fm.msg.ToString()); } ackAddr=null; break; } } if(ackAddr!=null) { _gate.SendGw(this, new MsForward(fm.addr, new MsDhcpAck(gwIdx, dr.xId, ackAddr.ToArray()))); } //****************************** } else { if(fm.msg.MsgTyp==MsMessageType.CONNECT) { var cm=fm.msg as MsConnect; if(fm.addr!=null && fm.addr.Length==2 && fm.addr[1]==0xFF) { // DHCP V<0.3 _gate.SendGw(this, new MsForward(fm.addr, new MsConnack(MsReturnCode.Accepted))); byte[] nAddr=new byte[1]; do { nAddr[0]=(byte)(_rand.Next(32, 254)); } while(!devR.children.Select(z => z as DVar<MsDevice>).Where(z => z!=null && z.value!=null).All(z => !z.value.CheckAddr(nAddr))); Log.Info("{0} new addr={1:X2}", cm.ClientId, nAddr[0]); _gate.SendGw(this, new MsForward(fm.addr, new MsPublish(null, PredefinedTopics[".cfg/XD_DeviceAddr"], QoS.AtLeastOnce) { MessageId=1, Data=nAddr })); } else { DVar<MsDevice> dDev=devR.Get<MsDevice>(cm.ClientId); if(dDev.value==null) { dDev.value=new MsDevice(this, fm.addr); Thread.Sleep(0); dDev.value.Owner=dDev; } else { this.RemoveNode(dDev.value); dDev.value._gate=this; dDev.value.Addr=fm.addr; } this.AddNode(dDev.value); dDev.value.Connect(cm); foreach(var dub in devR.children.Select(z => z.GetValue() as MsDevice).Where(z => z!=null && z!=dDev.value && z.Addr!=null && z.Addr.SequenceEqual(fm.addr) && z._gate==this).ToArray()) { dub.Addr=null; dub._gate=null; dub.state=State.Disconnected; } } } else { MsDevice dev=devR.children.Select(z => z.GetValue() as MsDevice).FirstOrDefault(z => z!=null && z.Addr!=null && z.Addr.SequenceEqual(fm.addr) && z._gate==this); if(dev!=null && ((dev.state!=State.Disconnected && dev.state!=State.Lost) || fm.msg.MsgTyp==MsMessageType.CONNECT || (fm.msg.MsgTyp==MsMessageType.PUBLISH && (fm.msg as MsPublish).qualityOfService==QoS.MinusOne))) { dev.ProcessInPacket(fm.msg); } else if(fm.msg.MsgTyp==MsMessageType.PUBLISH && (fm.msg as MsPublish).qualityOfService==QoS.MinusOne) { var tmp=fm.msg as MsPublish; if(tmp.topicIdType==TopicIdType.PreDefined && tmp.TopicId>=LOG_D_ID && tmp.TopicId<=LOG_E_ID) { string str=string.Format("{0}: msgId={2:X4} msg={1}", BitConverter.ToString(this.Addr), tmp.Data==null?"null":(BitConverter.ToString(tmp.Data)+"["+ Encoding.ASCII.GetString(tmp.Data.Select(z => (z<0x20 || z>0x7E)?(byte)'.':z).ToArray())+"]"), tmp.MessageId); switch(tmp.TopicId) { case LOG_D_ID: Log.Debug(str); break; case LOG_I_ID: Log.Info(str); break; case LOG_W_ID: Log.Warning(str); break; case LOG_E_ID: Log.Error(str); break; } } } else { if(dev==null || dev.Owner==null) { if(_verbose.value) { Log.Debug("{0} via {1} unknown device", BitConverter.ToString(fm.addr), this.name); } } else { if(_verbose.value) { Log.Debug("{0} via {1} inactive", dev.Owner.name, this.name); } } _gate.SendGw(this, new MsForward(fm.addr, new MsDisconnect())); } } } } break; } }
private void ParseInPacket(byte[] buf) { var msgTyp=(MsMessageType)(buf[0]>1?buf[1]:buf[2]); switch(msgTyp) { case MsMessageType.WILLTOPIC: { var msg=new MsWillTopic(buf) { Addr=this.Addr }; Stat(false, msgTyp); PrintPacket(this, msg, buf); if(state==State.WillTopic) { _willPath=msg.Path; _willRetain=msg.Retain; state=State.WillMsg; ProccessAcknoledge(msg); } } break; case MsMessageType.WILLMSG: { Stat(false, msgTyp); var msg=new MsWillMsg(buf) { Addr=this.Addr }; PrintPacket(this, msg, buf); if(state==State.WillMsg) { _wilMsg=msg.Payload; state=State.PreConnect; ProccessAcknoledge(msg); Send(new MsConnack(MsReturnCode.Accepted)); Log.Info("{0} connected", Owner.path); } } break; case MsMessageType.SUBSCRIBE: { var msg=new MsSubscribe(buf) { Addr=this.Addr }; Stat(false, msgTyp, msg.dup); PrintPacket(this, msg, buf); SyncMsgId(msg.MessageId); Topic.Subscription s=null; ushort topicId=msg.topicId; if(msg.topicIdType!=TopicIdType.Normal || msg.path.IndexOfAny(new[] { '+', '#' })<0) { TopicInfo ti=null; if(msg.topicIdType==TopicIdType.Normal) { ti=GetTopicInfo(msg.path, false); } else { ti=GetTopicInfo(msg.topicId, msg.topicIdType); } topicId=ti.TopicId; } Send(new MsSuback(msg.qualityOfService, topicId, msg.MessageId, MsReturnCode.Accepted)); if(state==State.PreConnect) { state=State.Connected; } s=Owner.Subscribe(msg.path, PublishTopic, msg.qualityOfService); _subsscriptions.Add(s); } break; case MsMessageType.REGISTER: { var msg=new MsRegister(buf) { Addr=this.Addr }; Stat(false, msgTyp); PrintPacket(this, msg, buf); ResetTimer(); try { TopicInfo ti = GetTopicInfo(msg.TopicPath, false); if(ti.topic!=null && ti.topic.valueType==typeof(SmartTwi)) { if(ti.topic.GetValue()==null) { ti.topic.SetValue(new SmartTwi(ti.topic), new TopicChanged(TopicChanged.ChangeArt.Value, Owner)); } else { (ti.topic as DVar<SmartTwi>).value.Reset(); } } Send(new MsRegAck(ti.TopicId, msg.MessageId, MsReturnCode.Accepted)); } catch(Exception) { Send(new MsRegAck(0, msg.MessageId, MsReturnCode.NotSupportes)); Log.Warning("Unknown variable type by register {0}, {1}", Owner.path, msg.TopicPath); } } break; case MsMessageType.REGACK: { var msg=new MsRegAck(buf) { Addr=this.Addr }; Stat(false, msgTyp); PrintPacket(this, msg, buf); ProccessAcknoledge(msg); TopicInfo ti=_topics.FirstOrDefault(z => z.TopicId==msg.TopicId); if(ti==null) { if(msg.TopicId!=0) { Log.Warning("{0} RegAck({1:X4}) for unknown variable", Owner.path, msg.TopicId); } return; } if(msg.RetCode==MsReturnCode.Accepted) { ti.registred=true; if(ti.it!=TopicIdType.PreDefined) { Send(new MsPublish(ti.topic, ti.TopicId, QoS.AtLeastOnce)); } } else { Log.Warning("{0} registred failed: {1}", ti.path, msg.RetCode.ToString()); ti.it=TopicIdType.NotUsed; //_topics.Remove(ti); //ti.topic.Remove(); } } break; case MsMessageType.PUBLISH: { var msg=new MsPublish(buf) { Addr=this.Addr }; Stat(false, msgTyp, msg.Dup); PrintPacket(this, msg, buf); TopicInfo ti=_topics.Find(z => z.TopicId==msg.TopicId && z.it==msg.topicIdType); if(ti==null && msg.topicIdType!=TopicIdType.Normal) { ti=GetTopicInfo(msg.TopicId, msg.topicIdType, false); } if(msg.qualityOfService==QoS.AtMostOnce) { ResetTimer(); } else if(msg.qualityOfService==QoS.AtLeastOnce) { SyncMsgId(msg.MessageId); Send(new MsPubAck(msg.TopicId, msg.MessageId, ti!=null?MsReturnCode.Accepted:MsReturnCode.InvalidTopicId)); } else if(msg.qualityOfService==QoS.ExactlyOnce) { SyncMsgId(msg.MessageId); // QoS2 not supported, use QoS1 Send(new MsPubAck(msg.TopicId, msg.MessageId, ti!=null?MsReturnCode.Accepted:MsReturnCode.InvalidTopicId)); } else { throw new NotSupportedException("QoS -1 not supported "+Owner.path); } if(msg.topicIdType==TopicIdType.PreDefined && msg.TopicId>=LOG_D_ID && msg.TopicId<=LOG_E_ID) { string str=string.Format("{0}:{1} msg={2} msgId={3} ", this.Owner.path, BitConverter.ToString(msg.Addr), msg.Data==null?"null":BitConverter.ToString(msg.Data), msg.MessageId); switch(msg.TopicId) { case LOG_D_ID: Log.Debug(str); break; case LOG_I_ID: Log.Info(str); break; case LOG_W_ID: Log.Warning(str); break; case LOG_E_ID: Log.Error(str); break; } } else if(ti!=null) { SetValue(ti, msg.Data); } } break; case MsMessageType.PUBACK: { var msg=new MsPubAck(buf) { Addr=this.Addr }; Stat(false, msgTyp); PrintPacket(this, msg, buf); ProccessAcknoledge(msg); } break; case MsMessageType.PINGREQ: { var msg=new MsPingReq(buf) { Addr=this.Addr }; Stat(false, msgTyp); PrintPacket(this, msg, buf); if(state==State.ASleep) { if(string.IsNullOrEmpty(msg.ClientId) || msg.ClientId==Owner.name) { //if(++_reconnectCnt>1024) { // _reconnectCnt=0; // Send(new MsDisconnect()); // state=State.Disconnected; // Log.Info("{0} refresh connection", Owner.path); //} else { state=State.AWake; ProccessAcknoledge(msg); // resume send proccess //} } else { Send(new MsDisconnect()); state=State.Lost; Log.Warning("{0} PingReq from unknown device: {1}", Owner.path, msg.ClientId); } } else { ResetTimer(); if(_gate!=null) { _gate.Send(new MsMessage(MsMessageType.PINGRESP) { Addr=this.Addr }); Stat(true, MsMessageType.PINGRESP, false); } } } break; case MsMessageType.DISCONNECT: { var msg=new MsDisconnect(buf) { Addr=this.Addr }; Stat(false, msgTyp); PrintPacket(this, msg, buf); Disconnect(msg.Duration); } break; default: Log.Warning("{0} unknown packet: {1}", Owner!=null?Owner.path:"null", BitConverter.ToString(buf)); break; } }
private void ParseInPacket(byte[] addr, byte[] buf) { if(addr[0]==0) { Log.Warning("Packet with broadcast address via {0}:{1:X2}:{2}", _port.PortName, BitConverter.ToString(addr), BitConverter.ToString(buf)); return; } Topic devR=Topic.root.Get("/dev"); var msgTyp=(MsMessageType)(buf[0]>1?buf[1]:buf[3]); if(msgTyp==MsMessageType.SEARCHGW) { PrintPacket(null, new MsSearchGW(buf) { Addr=addr }, buf); this.Send(new MsGwInfo(_gwAddr) { Addr=new byte[] { 0 } }); } else if(msgTyp==MsMessageType.CONNECT) { var msg=new MsConnect(buf) { Addr=addr }; if(addr[0]==_gwAddr) { _advTick=DateTime.Now.AddSeconds(2.6); // Send Advertise in 2.6 sec. } if(addr[0]==0xFF) { PrintPacket(null, msg, buf); Send(new MsConnack(MsReturnCode.Accepted) { Addr=msg.Addr }); byte[] nAddr=new byte[1]; var r=new Random(DateTime.Now.Millisecond); do { nAddr[0]=(byte)(8+r.Next(0xF6)); //0x08 .. 0xFE } while(devR.children.Select(z => z.GetValue() as MsDevice).Any(z => z!=null && nAddr.SequenceEqual(z.Addr))); Log.Info("{0} new addr={1}", msg.ClientId, BitConverter.ToString(nAddr)); var pm=new MsPublish(null, PredefinedTopics[".cfg/XD_DeviceAddr"], QoS.AtLeastOnce) { Addr=msg.Addr, MessageId=1, Data=nAddr }; Send(pm); } else { // msg.Addr!=0xFF DVar<MsDevice> dev=devR.Get<MsDevice>(msg.ClientId); // if(!msg.CleanSession && (dev.value==null || !dev.value.Addr.SequenceEqual(msg.Addr) || dev.value.state==State.Disconnected || dev.value.state==State.Lost)) { PrintPacket(dev, msg, buf); Send(new MsConnack(MsReturnCode.InvalidTopicId) { Addr=msg.Addr }); return; } if(dev.value==null) { dev.value=new MsDevice(); } dev.value._gate=this; if(dev.value.Addr==null || !msg.Addr.SequenceEqual(dev.value.Addr)) { dev.value.Addr=msg.Addr; } PrintPacket(dev, msg, buf); Thread.Sleep(0); dev.value.Connect(msg); if(msg.Addr[0]==_gwAddr) { dev.value.via=_port.PortName; _gwTopic=dev; } else { dev.value.via= _gwTopic==null?string.Empty:_gwTopic.name; } } // msg.Addr!=0xFF } else { // msgType==Connect MsDevice dev=devR.children.Select(z => z.GetValue() as MsDevice).FirstOrDefault(z => z!=null && z.Addr!=null && addr.SequenceEqual(z.Addr) && z._gate==this); if(dev!=null && dev.state!=State.Disconnected && dev.state!=State.Lost) { dev.ParseInPacket(buf); } else { if(dev==null || dev.Owner==null) { Log.Debug("unknown device: [{0:X2}:{1}]", addr[0], BitConverter.ToString(buf)); } else { Log.Debug("inactive device: [{0}:{1}]", dev.Owner.name, BitConverter.ToString(buf)); } Send(new MsDisconnect() { Addr=addr }); } } }