Ejemplo n.º 1
0
 public CoapMessage(Int32 version, CoapType type, CoapCode code, Int32 messageID, byte[] token, List <CoapOption> options, byte[] payload)
 {
     this._version   = version;
     this._type      = type;
     this._code      = code;
     this._messageID = messageID;
     this._token     = token;
     this._options   = options;
     this._payload   = payload;
 }
        public static CoapMessage decode(IByteBuffer buf)
        {
            byte firstByte = buf.ReadByte();

            int version = firstByte >> 6;

            if (version != 1)
            {
                throw new ArgumentException("Invalid version:" + version);
            }

            int      typeValue = (firstByte >> 4) & 2;
            CoapType type      = (CoapType)typeValue;

            int tokenLength = firstByte & 0xf;

            if (tokenLength < 0 || tokenLength > 8)
            {
                throw new ArgumentException("Invalid token length:" + tokenLength);
            }

            int codeByte  = buf.ReadByte();
            int codeValue = (codeByte >> 5) * 100;

            codeValue += codeByte & 0x1F;
            CoapCode code = (CoapCode)codeValue;

            int messageID = buf.ReadShort();

            if (messageID < 0 || messageID > 65535)
            {
                throw new ArgumentException("Invalid messageID value:" + messageID);
            }

            byte[] token = new byte[tokenLength];
            if (tokenLength > 0)
            {
                buf.ReadBytes(token, 0, tokenLength);
            }
            int number = 0;

            List <CoapOption> options = new List <CoapOption>();

            while (buf.IsReadable())
            {
                byte nextByte = buf.ReadByte();
                if (nextByte == 0xFF)
                {
                    break;
                }

                int delta = ((nextByte >> 4) & 15);
                if (delta == 13)
                {
                    delta = (delta << 8 | buf.ReadByte()) - 13;
                }
                else if (delta == 14)
                {
                    delta = (delta << 16 | buf.ReadByte() << 8 | buf.ReadByte()) - 269;
                }
                else if (delta < 0 || delta > 14)
                {
                    throw new ArgumentException("invalid option delta value:" + delta);
                }

                number += delta;
                if (number < 0)
                {
                    throw new ArgumentException("invalid negative option number:" + number + ", delta:" + delta);
                }

                int optionLength = nextByte & 15;
                if (optionLength == 13)
                {
                    optionLength = buf.ReadByte() + 13;
                }
                else if (optionLength == 14)
                {
                    optionLength = buf.ReadByte() + 269;
                }
                else if (optionLength < 0 || optionLength > 14)
                {
                    throw new ArgumentException("invalid option length");
                }

                byte[] optionValue = new byte[optionLength];
                if (optionLength > 0)
                {
                    buf.ReadBytes(optionValue, 0, optionLength);
                }

                options.Add(new CoapOption(number, optionLength, optionValue));
            }

            byte[] payload = null;
            if (buf.IsReadable())
            {
                payload = new byte[buf.ReadableBytes];
                buf.ReadBytes(payload);
            }

            return(new CoapMessage(version, type, code, messageID, token, options, payload));
        }
        public void PacketReceived(CoapMessage message)
        {
            CoapType type = message.CoapType;

            if ((message.CoapCode == CoapCode.POST || message.CoapCode == CoapCode.PUT) && type != CoapType.ACKNOWLEDGEMENT)
            {
                String topic = null;
                QOS    qos   = QOS.AT_MOST_ONCE;
                foreach (CoapOption option in message.Options)
                {
                    if (option.Number == (int)CoapOptionType.URI_PATH)
                    {
                        topic = Encoding.UTF8.GetString(option.Value);
                    }
                    else if (option.Number == (int)CoapOptionType.ACCEPT)
                    {
                        qos = (QOS)option.Value[option.Value.Length - 1];
                    }
                }

                if (topic == null)
                {
                    List <CoapOption> options   = new List <CoapOption>();
                    byte[]            textBytes = Encoding.UTF8.GetBytes("text/plain");
                    options.Add(new CoapOption((int)CoapOptionType.CONTENT_FORMAT, textBytes.Length, textBytes));
                    byte[] nodeIdBytes = Encoding.UTF8.GetBytes(_clientID);
                    options.Add(new CoapOption((int)CoapOptionType.NODE_ID, nodeIdBytes.Length, nodeIdBytes));
                    CoapMessage ack = new CoapMessage(VERSION, CoapType.ACKNOWLEDGEMENT, CoapCode.BAD_OPTION, message.MessageID, message.Token, options, new byte[0]);
                    _client.Send(ack);
                    return;
                }

                byte[] content = message.Payload;
                _dbInterface.StoreMessage(topic, content, 0);

                if (_listener != null)
                {
                    _listener.MessageReceived(MessageType.PUBLISH);
                }
            }

            switch (type)
            {
            case CoapType.CONFIRMABLE:
            {
                List <CoapOption> options     = new List <CoapOption>();
                byte[]            nodeIdBytes = Encoding.UTF8.GetBytes(_clientID);
                options.Add(new CoapOption((int)CoapOptionType.NODE_ID, nodeIdBytes.Length, nodeIdBytes));
                CoapMessage ack = new CoapMessage(message.Version, CoapType.ACKNOWLEDGEMENT, message.CoapCode, message.MessageID, message.Token, options, new byte[0]);
                _client.Send(ack);
            }
            break;

            case CoapType.NON_CONFIRMABLE:
            {
                _timers.Remove(message.Token);
            }
            break;

            case CoapType.ACKNOWLEDGEMENT:
            {
                if (message.CoapCode == CoapCode.GET)
                {
                    Boolean?observe = null;
                    QOS     qos     = QOS.AT_MOST_ONCE;
                    foreach (CoapOption option in message.Options)
                    {
                        if (option.Number == (int)CoapOptionType.OBSERVE && option.Value.Length > 0)
                        {
                            if (option.Value[option.Value.Length - 1] == 0x00)
                            {
                                observe = false;
                            }
                            else
                            {
                                observe = true;
                            }
                        }
                        else if (option.Number == (int)CoapOptionType.ACCEPT)
                        {
                            if (option.Value[option.Value.Length - 1] == 0)
                            {
                                qos = QOS.AT_LEAST_ONCE;
                            }
                        }
                    }

                    if (observe.HasValue)
                    {
                        if (!observe.Value)
                        {
                            CoapMessage originalMessage = _timers.Remove(message.Token);
                            if (originalMessage != null)
                            {
                                List <String> topics = new List <String>();
                                foreach (CoapOption option in originalMessage.Options)
                                {
                                    if (option.Number == (int)CoapOptionType.URI_PATH)
                                    {
                                        topics.Add(Encoding.UTF8.GetString(option.Value));
                                    }
                                }

                                for (int i = 0; i < topics.Count; i++)
                                {
                                    _dbInterface.StoreTopic(topics[i], qos);
                                }

                                if (_listener != null)
                                {
                                    _listener.MessageReceived(MessageType.SUBACK);
                                }
                            }
                        }
                        else
                        {
                            CoapMessage originalMessage = _timers.Remove(message.Token);
                            if (originalMessage != null)
                            {
                                List <String> topics = new List <String>();
                                foreach (CoapOption option in originalMessage.Options)
                                {
                                    if (option.Number == (int)CoapOptionType.URI_PATH)
                                    {
                                        topics.Add(Encoding.UTF8.GetString(option.Value));
                                    }
                                }

                                for (int i = 0; i < topics.Count; i++)
                                {
                                    _dbInterface.DeleteTopic(topics[i]);
                                }
                            }

                            if (_listener != null)
                            {
                                _listener.MessageReceived(MessageType.UNSUBACK);
                            }
                        }
                    }
                }
                else
                {
                    _timers.Remove(message.Token);
                    if (_listener != null)
                    {
                        _listener.MessageReceived(MessageType.PUBACK);
                    }
                }
            }
            break;

            case CoapType.RESET:
            {
                _timers.Remove(message.Token);
            }
            break;
            }
        }