Example #1
0
        public void SendPost(IPEndPoint destination, Uri uri, bool reliable, string content)
        {
            CoapMessageType type = CoapMessageType.NonConfirmable;

            if (reliable)
            {
                type = CoapMessageType.Confirmable;
            }

            CoapMessage message = new CoapMessage(type, CoapMessageCode.POST);

            message.Destination = destination;
            message.Uri         = uri;
            message.Payload     = content == null ? null : System.Text.Encoding.UTF8.GetBytes(content);
            SendRequest(message);
        }
Example #2
0
        public async Task HandleMessage(CoapMessage message)
        {
            await Task.Run(() => {});

            Console.WriteLine("I'll do something at some point");
        }
Example #3
0
 public Task HandleRequest(CoapMessage message)
 {
     throw new System.NotImplementedException();
 }
Example #4
0
 public Task HandleResponse(CoapMessage response)
 {
     throw new System.NotImplementedException();
 }
Example #5
0
        // TODO: build this kind of mechanism into handling a queue of tasks:
        // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/start-multiple-async-tasks-and-process-them-as-they-complete
        // https://devblogs.microsoft.com/pfxteam/processing-tasks-as-they-complete/
        public SendMessageStatus SendMessage(CoapMessage message)
        {
            message.DecomposeUri(message.Uri);

            message.MessageID  = (ushort)(idhash[0] << 8);
            message.MessageID |= (ushort)idhash[1];

            // prepare hasher for next message ID
            idhash = hasher.ComputeHash(idhash);

            SendMessageStatus status = SendMessageStatus.BusyQueued;

            // TODO: move this to something that will check in the background - not as part of send! - check for any messages that are complete
            List <Task> toRemove = new List <Task>();

            foreach (Task t in messagesInProgress)
            {
                if (t.IsCompleted || t.IsCanceled || t.IsFaulted)
                {
                    // TODO: do a bit more than this, handle errors
                    toRemove.Add(t);
                }
            }
            foreach (Task t in toRemove)
            {
                messagesInProgress.Remove(t);
            }

            // TODO: if busy sending enqueue the message, make max configurable
            if (messagesInProgress.Count > 100)
            {
                // too busy, queue the message and move on
                outgoingQueue.Enqueue(message);
                status = SendMessageStatus.BusyQueued;
            }
            else
            {
                // TODO: generate tokens and whatever needed to fulfill the protocol

                // encode the message into a byte array
                byte[] datagram = message.ToByteArray();

                // attempt to send the message
                Task <int> t = null;

                t = endpoint.SendAsync(datagram, datagram.Length, message.Destination);

                if (t.IsCompleted)
                {
                    status = SendMessageStatus.SentImmediately;
                }
                else
                {
                    Console.WriteLine($"Didn't send immediately so putting on progress list to check");
                    status = SendMessageStatus.Sending;
                    messagesInProgress.Add(t);
                }
            }

            // TODO: kick queue

            return(status);
        }
Example #6
0
        public async Task HandleEmptyMessage(CoapMessage Request)
        {
            await Task.Run(() => {});

            Console.WriteLine("I received a response to a message");
        }
Example #7
0
        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);
        }