private void AddOption(CoapOptionNumber number, CoapOption option) { if (Options == null) { Options = new SortedDictionary <CoapOptionNumber, List <CoapOption> >(); } if (Options.ContainsKey(number) == false) { Options[number] = new List <CoapOption>(); } Options[number].Add(option); }
public void AddOption(CoapOptionNumber type, int value) { CoapOption option = new CoapOption((int)type, value); AddOption(type, option); }
public static CoapMessage FromByteArray(byte[] bytes, IPEndPoint remoteEndpoint) { int pos = 0; if (bytes.Length < 4) { throw new CoapMessageFormatException("Not enough data to form a valid header"); } // header processing CoapMessage message = new CoapMessage(); // need to do this now because we might need the endpoint and port for the url message.Source = remoteEndpoint; byte b = bytes[pos++]; message.Version = (byte)((b & 0xc0) >> 6); message.Type = (CoapMessageType)((b & 0x30000000) >> 4); message.TokenLength = (byte)((b & 0x0f000000)); if (message.TokenLength > 8) { throw new CoapMessageFormatException("Token length must be 0-8 bytes in length."); } b = bytes[pos++]; message.Code = (CoapMessageCode)b; b = bytes[pos++]; message.MessageID = (UInt16)(b << 8); b = bytes[pos++]; message.MessageID |= b; if (message.TokenLength > 0) { message.TokenValue = new byte[message.TokenLength]; Array.Copy(bytes, pos, message.TokenValue, 0, message.TokenLength); pos += message.TokenLength; } bool processingOptions = true; int optionNumber = 0; int optionLength = 0; while (pos < bytes.Length && processingOptions) { if (bytes[pos] == 0xff) { pos++; processingOptions = false; // process payload int payloadLength = bytes.Length - pos; if (payloadLength == 0) { throw new CoapMessageFormatException("Payload marker cannot be followed by no payload"); } if (payloadLength > 0) { message.Payload = new byte[payloadLength]; Array.Copy(bytes, pos, message.Payload, 0, payloadLength); } } if (processingOptions) { int delta = (char)((bytes[pos] & 0xf0) >> 4); optionLength = (char)(bytes[pos] & 0x0f); pos++; switch (delta) { case 13: { byte extendedDelta = bytes[pos++]; optionNumber += (extendedDelta + 13); } break; case 14: { UInt16 extendedDelta = (UInt16)bytes[pos++]; extendedDelta <<= 8; extendedDelta |= bytes[pos++]; optionNumber += (extendedDelta + 269); } break; case 15: if (bytes[pos] == 0xff) { processingOptions = false; } else { throw new CoapMessageFormatException("Malformed payload marker or invalid option"); } break; default: optionNumber += delta; break; } switch (optionLength) { case 13: { byte extendedLength = bytes[pos++]; optionLength = (extendedLength + 13); } break; case 14: { UInt16 extendedLength = (UInt16)bytes[pos++]; extendedLength <<= 8; extendedLength |= bytes[pos++]; optionLength = (extendedLength + 269); } break; case 15: { } break; } // TODO: based on table in 5.10 process options according to format and store in subclasses according to type // switch (optionNumber) // { // case 1: // { // If-Match - opaque - 0-8 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 3: // { // Uri-Host - string - 1-255 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 4: // { // ETag - opaque - 1-8 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 5: // { // If-None-Match - empty - 0 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 7: // { // Uri-Port - uint - 0-2 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 8: // { // Location-Path - string - 0-255 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 11: // { // Uri-Path - string - 0-255 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 12: // { // Content-Format - uint - 0-2 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 14: // { // Max-Age - uint - 0-4 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 15: // { // Uri-Query - string - 0-255 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 17: // { // Accept - uint - 0-2 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 20: // { // Location-Query - string - 0-255 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 35: // { // Proxy-Uri - string - 1-1034 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 39: // { // Proxy-Scheme - string - 1-255 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // case 60: // { // Size1 - uint - 0-4 // byte[] value = new byte[optionLength]; // Array.Copy(bytes, pos, value, 0, optionLength); // } // break; // } byte[] value = new byte[optionLength]; Array.Copy(bytes, pos, value, 0, optionLength); pos += optionLength; // add value as option if (message.Options == null) { message.Options = new SortedDictionary <CoapOptionNumber, List <CoapOption> >(); } if (!message.Options.ContainsKey((CoapOptionNumber)optionNumber)) { message.Options[(CoapOptionNumber)optionNumber] = new List <CoapOption>(); } CoapOption option = new CoapOption(); option.Number = optionNumber; option.Length = optionLength; option.Value = value; message.Options[(CoapOptionNumber)optionNumber].Add(option); } } // construct URL for easier processing by consumers message.Uri = message.ComposeUri(); return(message); }