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;
}
}