/// <summary> /// Start the server /// </summary> /// <param name="host">Hostname to use for this server (DNS/IP)</param> /// <param name="port">The port number to listen on</param> public override void Initialize(string host, int port) { this._host = (host == null || host.Trim().Length == 0) ? "unknown" : host; if (port <= 0) { this._port = AbstractNetworkUtils.GetDefaultCoAPPort(); } else { this._port = port; } Shutdown(); //close all previous connections //Create the wait q this._msgPendingAckQ = new TimedQueue((uint)AbstractCoAPChannel.DEFAULT_ACK_TIMEOUT_SECS); this._msgPendingAckQ.OnResponseTimeout += new TimedQueue.TimedOutWaitingForResponse(OnTimedOutWaitingForResponse); //Create the separate response q this._separateResponseQ = new SeparateResponseQueue(); //Create the observers list this._observers = new ObserversList(); // Create a socket, bind it to the server's port and listen for client connections this._isDone = false; this.ReInitSocket(); Thread waitForClientThread = new Thread(new ThreadStart(WaitForConnections)); waitForClientThread.Start(); }
//public bool ExcludePort //{ // get { return __ExcludePort; } // set { __ExcludePort = true; } //} #endregion #region Lifetime Management /// <summary> /// Initialize all basic aspects of the client channel /// </summary> /// <param name="host">The IP host</param> /// <param name="port">The port number</param> public override void Initialize(string host, int port) { Shutdown(); //Connect to host IPAddress ipAddr = AbstractNetworkUtils.GetIPAddressFromHostname(host); //ipAddr = IPAddress.IPv6Loopback; this._remoteEP = new IPEndPoint(ipAddr, port); /*Socket serverSocket = * new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); * ? * * Note: There's a shortcut to obtain the IP address of localhost: You can simply use IPAddress.Loopback (127.0.0.1) or IPAddress.IPv6Loopback (::1). */ this._clientSocket = new Socket(CoAPSettings.Instance.AddressFamily, SocketType.Dgram, ProtocolType.Udp); Console.WriteLine("NEW SOCKET - handle = " + _clientSocket.Handle.ToString()); ////this._clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); <==== added by Mike this._clientSocket.Connect(this._remoteEP); //Initialize ACK Q this._msgPendingAckQ = new TimedQueue((UInt16)this.AckTimeout); this._msgPendingAckQ.OnResponseTimeout += new TimedQueue.TimedOutWaitingForResponse(OnTimedOutWaitingForResponse); //Start message processing thread this._isDone = false; Thread waitForClientThread = new Thread(new ThreadStart(ProcessReceivedMessages)); waitForClientThread.Start(); }
/// <summary> /// Parse the CoAP message stream and extract details of the token /// </summary> /// <param name="coapMsgStream">The CoAP message stream that contains the token length and value</param> /// <param name="startIndex">The index to start looking for the value</param> /// <param name="extraInfo">Not used</param> /// <returns>The next index from where next set of information can be extracted from the message stream</returns> public int Parse(byte[] coapMsgStream, int startIndex, UInt16 extraInfo) { if (coapMsgStream == null || coapMsgStream.Length == 0 || startIndex < 0) { return(startIndex); //do nothing } if (coapMsgStream.Length < AbstractCoAPMessage.HEADER_LENGTH) { throw new CoAPFormatException("Invalid CoAP message stream"); } if (startIndex >= coapMsgStream.Length) { throw new ArgumentException("Start index beyond message stream length"); } //First get the token length...its there in bits 4-7 starting from left of first byte this.Length = (byte)(coapMsgStream[startIndex] & 0x0F); if (this.Length > 0) { //Search for token value int tokenValueStartIndex = 4; //Token value follows after first 4 bytes if (coapMsgStream.Length < (4 + this.Length)) { throw new CoAPFormatException("Invalid message stream. Token not present in the stream despite non-zero length"); } byte[] tokenValue = new byte[this.Length]; Array.Copy(coapMsgStream, tokenValueStartIndex, tokenValue, 0, this.Length); tokenValue = AbstractNetworkUtils.FromNetworkByteOrder(tokenValue); this.Value = tokenValue; } //We have parsed the token length...this finishes the byte...the index should move to next byte return(startIndex + 1); }
/// <summary> /// Send a CoAP message to the server. Please note, you must handle all exceptions /// and no event is raised. /// </summary> /// <param name="coapMsg">The CoAP message to send to server</param> /// <returns>Number of bytes sent</returns> public override int Send(AbstractCoAPMessage coapMsg) { if (coapMsg == null) { throw new ArgumentNullException("Message is NULL"); } if (this._clientSocket == null) { throw new InvalidOperationException("CoAP client not yet started"); } int bytesSent = 0; byte[] coapBytes = coapMsg.ToByteStream(); if (coapBytes.Length > AbstractNetworkUtils.GetMaxMessageSize()) { throw new UnsupportedException("Message size too large. Not supported. Try block option"); } bytesSent = this._clientSocket.Send(coapBytes); if (coapMsg.MessageType.Value == CoAPMessageType.CON) { //confirmable message...need to wait for a response coapMsg.DispatchDateTime = DateTime.Now; } return(bytesSent); }
public byte[] ToBytes(AbstractCoAPMessage coapMsg) { byte[] coapBytes = coapMsg.ToByteStream(); if (coapBytes.Length > AbstractNetworkUtils.GetMaxMessageSize()) { throw new UnsupportedException("Message size too large. Not supported. Try block option"); } return(coapBytes); }
/// <summary> /// Perform a session request (acquire or terminate). /// </summary> /// <param name="messageCode">CoAPMessageCode.POST for establishing a session or oAPMessageCode.DELETE for terminating a session</param> /// <returns>a boolean indicating success or failure of the request</returns> private bool SessionCall(byte messageCode) { __TimedOut = true; __SessionRequestSucceeded = false; string token = GatewaySettings.Instance.SfdpToken; //api.coap-test.developer.ssni.com string serverIP = AbstractNetworkUtils.GetIPAddressFromHostname(GatewaySettings.Instance.GatewayURI).ToString(); __coapClient.Initialize(GatewaySettings.Instance.GatewayURI, __ServerPort); __coapClient.AckTimeout = __Timeout; __coapClient.CoAPResponseReceived += new CoAPResponseReceivedHandler(OnCoAPSessionResponseReceived); __coapClient.CoAPError += new CoAPErrorHandler(OnCoAPError); coapReq = new CoAPRequest(this.ConfirmableMessageType, messageCode, HdkUtils.MessageId()); string uriToCall = "coap://" + GatewaySettings.Instance.GatewayURI + ":" + __ServerPort + "/sessions?security=none";//?token=" //+ GatewaySettings.Instance.SfdpToken; //+ "&security=none"; coapReq.SetURL(uriToCall); byte[] zero = { 0x00 }; coapReq.AddOption(CoAPHeaderOption.CONTENT_FORMAT, zero); if (messageCode != CoAPMessageCode.DELETE) { coapReq.Payload = new CoAPPayload(GatewaySettings.Instance.SfdpToken); } SetToken(); coapReq.Options.RemoveOption(CoAPHeaderOption.URI_QUERY); // JJK - Change in v2.0.7 FileLogger.Write("About to send session request"); try { FileLogger.Write(coapReq.ToString()); } catch (Exception flErr) { FileLogger.Write(flErr.Message); } __coapClient.Send(coapReq); __Done.WaitOne(GatewaySettings.Instance.RequestTimeout); __Done.Reset(); if (__TimedOut) { this.ErrorResult = "Request timed out"; FileLogger.Write(this.ErrorResult); } __coapClient.CoAPResponseReceived -= new CoAPResponseReceivedHandler(OnCoAPSessionResponseReceived); return(__SessionRequestSucceeded); }
/// <summary> /// Initialize all basic aspects of the client channel /// </summary> /// <param name="host">The IP host</param> /// <param name="port">The port number</param> public override void Initialize(string host, int port) { Shutdown(); //Connect to host IPAddress ipAddr = AbstractNetworkUtils.GetIPAddressFromHostname(host); this._remoteEP = new IPEndPoint(ipAddr, port); this._clientSocket = new Socket(CoAPSettings.Instance.AddressFamily, SocketType.Dgram, ProtocolType.Udp); this._clientSocket.Connect(this._remoteEP); }
/// <summary> /// Creates a payload with byte stream /// </summary> /// <param name="payloadData">Payload as byte stream</param> public CoAPPayload(byte[] payloadData) { if (payloadData == null || payloadData.Length == 0) { throw new ArgumentNullException("Payload data cannot be NULL or empty byte stream"); } if (payloadData.Length > AbstractNetworkUtils.GetMaxMessageSize() / 2) { throw new ArgumentException("Payload size cannot be more than " + AbstractNetworkUtils.GetMaxMessageSize() / 2); } this.Value = payloadData; }
/// <summary> /// Creates a payload with string data /// </summary> /// <param name="payloadData">Payload data as string</param> public CoAPPayload(string payloadData) { if (payloadData == null || payloadData.Trim().Length == 0) { throw new ArgumentNullException("Payload data cannot be NULL or empty string"); } if (payloadData.Trim().Length > AbstractNetworkUtils.GetMaxMessageSize() / 2) { throw new ArgumentException("Payload size cannot be more than " + AbstractNetworkUtils.GetMaxMessageSize() / 2); } this.Value = AbstractByteUtils.StringToByteUTF8(payloadData.Trim()); }
/// <summary> /// Convert this object into a byte stream. The zero-th element contains the token length /// Subsequent elements contain the token value in network byte order /// </summary> /// <param name="reserved">Not used now</param> /// <returns>byte array</returns> public byte[] ToStream(UInt16 reserved) { byte[] token = new byte[1 + this.Length]; token[0] = this.Length; if (this.Length > 0) { byte[] tokenValue = new byte[this.Length]; Array.Copy(this.Value, tokenValue, this.Length); tokenValue = AbstractNetworkUtils.ToNetworkByteOrder(tokenValue); Array.Copy(tokenValue, 0, token, 1, this.Length); } return(token); }
/// <summary> /// Initialize all basic aspects of the client channel /// </summary> /// <param name="host">The IP host</param> /// <param name="port">The port number</param> public override void Initialize(string host, int port) { Shutdown(); //Connect to host IPAddress ipAddr = AbstractNetworkUtils.GetIPAddressFromHostname(host); this._remoteEP = new IPEndPoint(ipAddr, port); this._clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); this._clientSocket.Connect(this._remoteEP); //Initialize ACK Q this._msgPendingAckQ = new TimedQueue((UInt16)this.AckTimeout); this._msgPendingAckQ.OnResponseTimeout += new TimedQueue.TimedOutWaitingForResponse(OnTimedOutWaitingForResponse); //Start message processing thread this._isDone = false; Thread waitForClientThread = new Thread(new ThreadStart(ProcessReceivedMessages)); waitForClientThread.Start(); }
/// <summary> /// Send a CoAP message to the server /// </summary> /// <param name="coapMsg">The CoAP message to send to server</param> /// <returns>Number of bytes sent</returns> public override int Send(AbstractCoAPMessage coapMsg) { if (coapMsg == null) { throw new ArgumentNullException("Message is NULL"); } if (this._clientSocket == null) { throw new InvalidOperationException("CoAP client not yet started"); } int bytesSent = 0; try { byte[] coapBytes = coapMsg.ToByteStream(); if (coapBytes.Length > AbstractNetworkUtils.GetMaxMessageSize()) { throw new UnsupportedException("Message size too large. Not supported. Try block option"); } bytesSent = this._clientSocket.Send(coapBytes); if (coapMsg.MessageType.Value == CoAPMessageType.CON) { //confirmable message...need to wait for a response if (coapMsg.Timeout <= 0) { coapMsg.Timeout = AbstractCoAPChannel.DEFAULT_ACK_TIMEOUT_SECS; } coapMsg.DispatchDateTime = DateTime.Now; this._msgPendingAckQ.AddToWaitQ(coapMsg); } } catch (Exception e) { this._msgPendingAckQ.RemoveFromWaitQ(coapMsg.ID.Value); this.HandleError(e, coapMsg); } return(bytesSent); }
/// <summary> /// Parse the CoAP message stream and extract message Id (in network byte order) /// </summary> /// <param name="coapMsgStream">The CoAP message stream that contains the token length and value</param> /// <param name="startIndex">The index to start looking for the value</param> /// <param name="extraInfo">Not used</param> /// <returns>The next index from where next set of information can be extracted from the message stream</returns> public int Parse(byte[] coapMsgStream, int startIndex, UInt16 extraInfo) { if (coapMsgStream == null || coapMsgStream.Length == 0 || startIndex < 0) { return(startIndex); //do nothing } if (coapMsgStream.Length < AbstractCoAPMessage.HEADER_LENGTH) { throw new CoAPFormatException("Invalid CoAP message stream"); } if (startIndex >= coapMsgStream.Length) { throw new ArgumentException("Start index beyond message stream length"); } //We read two bytes... byte[] mid = { coapMsgStream[startIndex], coapMsgStream[startIndex + 1] }; //We received them in network byte order...fix the order based on the platform mid = AbstractNetworkUtils.FromNetworkByteOrder(mid); Value = AbstractByteUtils.ToUInt16(mid); return(startIndex + 2); }
/// <summary> /// Convert this option into a byte stream int network byte order /// </summary> /// <param name="previousOptionNumber">The previous option number in the sequence of options</param> /// <returns>byte array</returns> public byte[] ToStream(UInt16 previousOptionNumber) { //The option format is given below /********************************************* | 4 bits option delta | 4 bits length | | ---------------------------------------------- | 0-2 bytes option delta extended | | ---------------------------------------------- | 0-2 bytes option length extended | | ---------------------------------------------- | 0-* bytes option value | *********************************************/ int streamLength = 1; //Get Option delta byte optionDelta = 0; UInt16 derivedOptionNumber = (UInt16)(this.Number - previousOptionNumber); byte[] optionDeltaEx = null; if (derivedOptionNumber <= 12) { optionDelta = (byte)derivedOptionNumber; } else if (derivedOptionNumber > 12 && derivedOptionNumber <= 255 /*Option number is single byte*/) { optionDeltaEx = new byte[1] { (byte)(derivedOptionNumber - 13) }; optionDelta = 13; streamLength++;//1 additional byte } else /*Option number is double byte*/ { optionDelta = 14; optionDeltaEx = AbstractByteUtils.GetBytes((UInt16)(derivedOptionNumber - 269)); optionDeltaEx = AbstractNetworkUtils.ToNetworkByteOrder(optionDeltaEx); streamLength += 2; //two additional bytes } //Get option length byte optionLength = 0; byte[] optionLengthEx = null; if (this.Value != null) { if (this.Value.Length > 0 && this.Value.Length < 13) { optionLength = (byte)this.Value.Length; } else if (this.Value.Length > 12 && this.Value.Length <= 255) { optionLength = 13; optionLengthEx = new byte[1] { (byte)(this.Value.Length - 13) }; streamLength++;//1 additional byte } else if (this.Value.Length > 255) { optionLength = 14; optionLengthEx = AbstractByteUtils.GetBytes((UInt16)(this.Value.Length - 269)); optionLengthEx = AbstractNetworkUtils.ToNetworkByteOrder(optionLengthEx); streamLength += 2; //two additional bytes } } streamLength += ((this.Value != null && !this.IsEmpty()) ? this.Value.Length : 0); byte[] optionStream = new byte[streamLength]; int count = 0; optionStream[count++] = (byte)((optionDelta << 4) | (optionLength)); //header + length if (optionDelta == 13) //delta extended { optionStream[count++] = optionDeltaEx[0]; } else if (optionDelta == 14) { optionStream[count++] = optionDeltaEx[0]; optionStream[count++] = optionDeltaEx[1]; } if (optionLength == 13) { optionStream[count++] = optionLengthEx[0]; } else if (optionLength == 14) { optionStream[count++] = optionLengthEx[0]; optionStream[count++] = optionLengthEx[1]; } if (this.Value != null && this.Value.Length > 0 && !this.IsEmpty()) { byte[] optionValue = new byte[this.Value.Length]; Array.Copy(this.Value, optionValue, this.Value.Length); if (this.NeedsByteOrdering(this.Number)) { optionValue = AbstractNetworkUtils.ToNetworkByteOrder(optionValue); } Array.Copy(optionValue, 0, optionStream, count, optionValue.Length); } return(optionStream); }
/// <summary> /// This thread continuously looks for messages on the socket /// Once available, it will post them for handling downstream /// </summary> protected void ProcessReceivedMessages() { byte[] buffer = null; int maxSize = AbstractNetworkUtils.GetMaxMessageSize(); while (!this._isDone) { Thread.Sleep(1000); try { if (this._clientSocket.Available >= 4 /*Min size of CoAP block*/) { buffer = new byte[maxSize * 2]; int bytesRead = this._clientSocket.Receive(buffer); byte[] udpMsg = new byte[bytesRead]; Array.Copy(buffer, udpMsg, bytesRead); byte mType = AbstractCoAPMessage.PeekMessageType(udpMsg); if ((mType == CoAPMessageType.CON || mType == CoAPMessageType.NON) && AbstractCoAPMessage.PeekIfMessageCodeIsRequestCode(udpMsg)) { //This is a request CoAPRequest coapReq = new CoAPRequest(); coapReq.FromByteStream(udpMsg); coapReq.RemoteSender = this._remoteEP;//Setup who sent this message string uriHost = ((IPEndPoint)this._remoteEP).Address.ToString(); UInt16 uriPort = (UInt16)((IPEndPoint)this._remoteEP).Port; //setup the default values of host and port //setup the default values of host and port if (!coapReq.Options.HasOption(CoAPHeaderOption.URI_HOST)) { coapReq.Options.AddOption(CoAPHeaderOption.URI_HOST, AbstractByteUtils.StringToByteUTF8(uriHost)); } if (!coapReq.Options.HasOption(CoAPHeaderOption.URI_PORT)) { coapReq.Options.AddOption(CoAPHeaderOption.URI_PORT, AbstractByteUtils.GetBytes(uriPort)); } this.HandleRequestReceived(coapReq); } else { //This is a response CoAPResponse coapResp = new CoAPResponse(); coapResp.FromByteStream(udpMsg); coapResp.RemoteSender = this._remoteEP;//Setup who sent this message //Remove the waiting confirmable message from the timeout queue if (coapResp.MessageType.Value == CoAPMessageType.ACK || coapResp.MessageType.Value == CoAPMessageType.RST) { this._msgPendingAckQ.RemoveFromWaitQ(coapResp.ID.Value); } this.HandleResponseReceived(coapResp); } } } catch (SocketException se) { //Close this client connection this._isDone = true; this.HandleError(se, null); } catch (ArgumentNullException argEx) { this.HandleError(argEx, null); } catch (ArgumentException argEx) { this.HandleError(argEx, null); } catch (CoAPFormatException fEx) { //Invalid message.. this.HandleError(fEx, null); } } }
/// <summary> /// Convert this object into a byte stream in network byte order /// </summary> /// <param name="reserved">Not used now</param> /// <returns>byte array</returns> public byte[] ToStream(UInt16 reserved) { byte[] mID = AbstractByteUtils.GetBytes(this.Value); mID = AbstractNetworkUtils.ToNetworkByteOrder(mID); return(mID); }
/// <summary> /// Receive a message from the server. This will block if there /// are no messages. Please note, you must handle all errors (except timeout) /// and no error is raised. /// </summary> /// <param name="rxTimeoutMillis"> /// The timeout value in milliseconds.The default value is 0, which indicates an infinite time-out period. /// Specifying -1 also indicates an infinite time-out period /// </param> /// <param name="timedOut">Is set to true on timeout</param> /// <returns>An instance of AbstractCoAPMessage on success, else null on error/timeout</returns> public AbstractCoAPMessage ReceiveMessage(int rxTimeoutMillis, ref bool timedOut) { byte[] buffer = null; int maxSize = AbstractNetworkUtils.GetMaxMessageSize(); CoAPRequest coapReq = null; CoAPResponse coapResp = null; try { this._clientSocket.ReceiveTimeout = rxTimeoutMillis; buffer = new byte[maxSize * 2]; int bytesRead = this._clientSocket.Receive(buffer); byte[] udpMsg = new byte[bytesRead]; Array.Copy(buffer, udpMsg, bytesRead); byte mType = AbstractCoAPMessage.PeekMessageType(udpMsg); if ((mType == CoAPMessageType.CON || mType == CoAPMessageType.NON) && AbstractCoAPMessage.PeekIfMessageCodeIsRequestCode(udpMsg)) { //This is a request coapReq = new CoAPRequest(); coapReq.FromByteStream(udpMsg); coapReq.RemoteSender = this._remoteEP;//Setup who sent this message string uriHost = ((IPEndPoint)this._remoteEP).Address.ToString(); UInt16 uriPort = (UInt16)((IPEndPoint)this._remoteEP).Port; //setup the default values of host and port //setup the default values of host and port if (!coapReq.Options.HasOption(CoAPHeaderOption.URI_HOST)) { coapReq.Options.AddOption(CoAPHeaderOption.URI_HOST, AbstractByteUtils.StringToByteUTF8(uriHost)); } if (!coapReq.Options.HasOption(CoAPHeaderOption.URI_PORT)) { coapReq.Options.AddOption(CoAPHeaderOption.URI_PORT, AbstractByteUtils.GetBytes(uriPort)); } return(coapReq); } else { //This is a response coapResp = new CoAPResponse(); coapResp.FromByteStream(udpMsg); coapResp.RemoteSender = this._remoteEP;//Setup who sent this message return(coapResp); } } catch (SocketException se) { if (se.ErrorCode == (int)SocketError.TimedOut) { timedOut = true; } else { throw se; } } return(null); }
/// <summary> /// This is the thread where the socket server will accept client connections and process /// </summary> protected void WaitForConnections() { EndPoint sender = null; byte[] buffer = null; ArrayList previousBytes = new ArrayList(); int bytesRead = 0; byte mType = 0; UInt16 mId = 0; byte[] udpMsg = null; int maxSize = AbstractNetworkUtils.GetMaxMessageSize(); while (!this._isDone) { try { if (this._socket.Available >= 4 /*Min size of CoAP block*/) { sender = new IPEndPoint(IPAddress.Any, 0); buffer = new byte[maxSize * 2]; bytesRead = this._socket.ReceiveFrom(buffer, ref sender); udpMsg = new byte[bytesRead]; Array.Copy(buffer, udpMsg, bytesRead); mType = AbstractCoAPMessage.PeekMessageType(udpMsg); mId = AbstractCoAPMessage.PeekMessageID(udpMsg); if ((mType == CoAPMessageType.CON || mType == CoAPMessageType.NON) && AbstractCoAPMessage.PeekIfMessageCodeIsRequestCode(udpMsg)) { this.ProcessRequestMessageReceived(udpMsg, ref sender); } else { this.ProcessResponseMessageReceived(udpMsg, ref sender); } } else { //Nothing on the socket...wait Thread.Sleep(5000); } } catch (SocketException se) { //Try to re-initialize socket, and proceed only when the socket //is successfully re-initialized this._isDone = !this.ReInitSocket(); this.HandleError(se, null); } catch (ArgumentNullException argEx) { if (mType == CoAPMessageType.CON) { this.RespondToBadCONRequest(mId); } this.HandleError(argEx, null); } catch (ArgumentException argEx) { if (mType == CoAPMessageType.CON) { this.RespondToBadCONRequest(mId); } this.HandleError(argEx, null); } catch (CoAPFormatException fEx) { //Invalid message.. if (mType == CoAPMessageType.CON) { this.RespondToBadCONRequest(mId); } this.HandleError(fEx, null); } } }
/// <summary> /// Create a header option by parsing the coap data stream /// </summary> /// <param name="coapStream">The CoAP message stream that contains the option</param> /// <param name="startIndex">The index to start looking for the option</param> /// <param name="previousOptionNumber">The previous option number in the sequence of options</param> /// <returns>The next index from where next set of information can be extracted from the message stream</returns> public int Parse(byte[] coapStream, int startIndex, UInt16 previousOptionNumber) { if (coapStream == null || coapStream.Length < startIndex || startIndex < AbstractCoAPMessage.HEADER_LENGTH) { throw new ArgumentNullException("CoAP stream is null or start index is invalid"); } int nextIndex = startIndex; byte optionDelta = (byte)((coapStream[nextIndex] & 0xF0) >> 4); byte optionLength = (byte)(coapStream[nextIndex] & 0x0F); UInt16 optionStreamSizeInBytes = 1; //Calculate option number if (optionDelta < 13) { this.Number = (UInt16)(optionDelta + previousOptionNumber); } else if (optionDelta == 13) { this.Number = (UInt16)((UInt16)coapStream[++nextIndex] + 13 + previousOptionNumber); optionStreamSizeInBytes += 1; } else if (optionDelta == 14) { byte[] optionDeltaEx = new byte[] { coapStream[++nextIndex], coapStream[++nextIndex] }; optionDeltaEx = AbstractNetworkUtils.FromNetworkByteOrder(optionDeltaEx); this.Number = (UInt16)(AbstractByteUtils.ToUInt16(optionDeltaEx) + (UInt16)269 + previousOptionNumber); optionStreamSizeInBytes += 2; } else if (optionDelta == 15) { throw new CoAPFormatException("Option delta cannot contain payload marker value"); } //Calculate option value length if (optionLength < 13) { ValueSizeInBytes = optionLength; } else if (optionLength == 13) { ValueSizeInBytes = (UInt16)(coapStream[++nextIndex] + 13); optionStreamSizeInBytes += 1; } else if (optionLength == 14) { byte[] optionLengthEx = new byte[] { coapStream[++nextIndex], coapStream[++nextIndex] }; optionLengthEx = AbstractNetworkUtils.FromNetworkByteOrder(optionLengthEx); ValueSizeInBytes = (UInt16)(AbstractByteUtils.ToUInt16(optionLengthEx) + (UInt16)269); optionStreamSizeInBytes += 2; } else if (optionLength == 15) { throw new CoAPFormatException("Option length cannot be 0x0F. This is a reserved value"); } //Check if option is of type uint or is empty if ((this.NeedsByteOrdering(this.Number) && optionLength == 0) || this.IsEmpty()) { //this means that the value of the option is zero or this is an empty option Value = null; } else if (ValueSizeInBytes > 0) //normal processing { //Get option Value Value = new byte[ValueSizeInBytes]; Array.Copy(coapStream, ++nextIndex, Value, 0, ValueSizeInBytes); if (this.NeedsByteOrdering(this.Number)) { Value = AbstractNetworkUtils.FromNetworkByteOrder(Value); } optionStreamSizeInBytes += ValueSizeInBytes; } return(startIndex + optionStreamSizeInBytes); }