Пример #1
0
        private void ReceiveData(DataReceivedEventArgs e)
        {
            IMessageDecoder decoder = Spec.NewMessageDecoder(e.Data);

            if (decoder.IsRequest)
            {
                Request request;
                try
                {
                    request = decoder.DecodeRequest();
                }
                catch (Exception)
                {
                    if (decoder.IsReply)
                    {
                        if (log.IsWarnEnabled)
                        {
                            log.Warn("Message format error caused by " + e.EndPoint);
                        }
                    }
                    else
                    {
                        // manually build RST from raw information
                        EmptyMessage rst = new EmptyMessage(MessageType.RST);
                        rst.Destination = e.EndPoint;
                        rst.ID          = decoder.ID;
                        _channel.Send(Serialize(rst), rst.Destination);

                        if (log.IsWarnEnabled)
                        {
                            log.Warn("Message format error caused by " + e.EndPoint + " and reseted.");
                        }
                    }
                    return;
                }

                request.Source = e.EndPoint;
                Exchange exchange = _matcher.ReceiveRequest(request);
                if (exchange != null)
                {
                    exchange.EndPoint = this;
                    _coapStack.ReceiveRequest(exchange, request);
                }
            }
            else if (decoder.IsResponse)
            {
                Response response = decoder.DecodeResponse();
                response.Source = e.EndPoint;

                Exchange exchange = _matcher.ReceiveResponse(response);
                if (exchange != null)
                {
                    response.RTT      = (DateTime.Now - exchange.Timestamp).TotalMilliseconds;
                    exchange.EndPoint = this;
                    _coapStack.ReceiveResponse(exchange, response);
                }
                else if (response.Type != MessageType.ACK)
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Rejecting unmatchable response from " + e.EndPoint);
                    }
                    Reject(response);
                }
            }
            else if (decoder.IsEmpty)
            {
                EmptyMessage message = decoder.DecodeEmptyMessage();
                message.Source = e.EndPoint;

                // CoAP Ping
                if (message.Type == MessageType.CON || message.Type == MessageType.NON)
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Responding to ping by " + e.EndPoint);
                    }
                    Reject(message);
                }
                else
                {
                    Exchange exchange = _matcher.ReceiveEmptyMessage(message);
                    if (exchange != null)
                    {
                        exchange.EndPoint = this;
                        _coapStack.ReceiveEmptyMessage(exchange, message);
                    }
                }
            }
            else if (log.IsDebugEnabled)
            {
                log.Debug("Silently ignoring non-CoAP message from " + e.EndPoint);
            }
        }
Пример #2
0
 /// <inheritdoc/>
 public void SendResponse(Exchange exchange, Response response)
 {
     _executor.Start(() => _coapStack.SendResponse(exchange, response));
 }
Пример #3
0
 /// <inheritdoc/>
 public void SendEmptyMessage(Exchange exchange, EmptyMessage message)
 {
     _executor.Start(() => _coapStack.SendEmptyMessage(exchange, message));
 }
Пример #4
0
        /// <inheritdoc/>
        public Exchange ReceiveResponse(Response response)
        {
            /*
             * This response could be
             * - The first CON/NON/ACK+response => deliver
             * - Retransmitted CON (because client got no ACK)
             *      => resend ACK
             */

            Exchange.KeyID    keyId    = new Exchange.KeyID(response.ID, response.Source);
            Exchange.KeyToken keyToken = new Exchange.KeyToken(response.Token, response.Source);

            Exchange exchange;

            if (_exchangesByToken.TryGetValue(keyToken, out exchange))
            {
                // There is an exchange with the given token
                Exchange prev = _deduplicator.FindPrevious(keyId, exchange);
                if (prev != null)
                {
                    // (and thus it holds: prev == exchange)
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Duplicate response " + response);
                    }
                    response.Duplicate = true;
                }
                else
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Exchange got reply: Cleaning up " + keyId);
                    }
                    _exchangesByID.Remove(keyId);
                }

                if (response.Type == MessageType.ACK && exchange.CurrentRequest.ID != response.ID)
                {
                    // The token matches but not the MID. This is a response for an older exchange
                    if (log.IsWarnEnabled)
                    {
                        log.Warn("Token matches but not MID: Expected " + exchange.CurrentRequest.ID + " but was " + response.ID);
                    }
                    // ignore response
                    return(null);
                }
                else
                {
                    // this is a separate response that we can deliver
                    return(exchange);
                }
            }
            else
            {
                // There is no exchange with the given token.
                if (response.Type != MessageType.ACK)
                {
                    Exchange prev = _deduplicator.Find(keyId);
                    if (prev != null)
                    {
                        response.Duplicate = true;
                        return(prev);
                    }
                }
                // ignore response
                return(null);
            }
        }
Пример #5
0
        /// <inheritdoc/>
        public Exchange ReceiveRequest(Request request)
        {
            /*
             * This request could be
             *  - Complete origin request => deliver with new exchange
             *  - One origin block        => deliver with ongoing exchange
             *  - Complete duplicate request or one duplicate block (because client got no ACK)
             *      =>
             *      if ACK got lost => resend ACK
             *      if ACK+response got lost => resend ACK+response
             *      if nothing has been sent yet => do nothing
             * (Retransmission is supposed to be done by the retransm. layer)
             */

            Exchange.KeyID keyId = new Exchange.KeyID(request.ID, request.Source);

            /*
             * The differentiation between the case where there is a Block1 or
             * Block2 option and the case where there is none has the advantage that
             * all exchanges that do not need blockwise transfer have simpler and
             * faster code than exchanges with blockwise transfer.
             */
            if (!request.HasOption(OptionType.Block1) && !request.HasOption(OptionType.Block2))
            {
                Exchange exchange = new Exchange(request, Origin.Remote);
                Exchange previous = _deduplicator.FindPrevious(keyId, exchange);
                if (previous == null)
                {
                    exchange.Completed += OnExchangeCompleted;
                    return(exchange);
                }
                else
                {
                    if (log.IsInfoEnabled)
                    {
                        log.Info("Message is a duplicate, ignore: " + request);
                    }
                    request.Duplicate = true;
                    return(previous);
                }
            }
            else
            {
                Exchange.KeyUri keyUri = new Exchange.KeyUri(request.URI, request.Source);

                if (log.IsDebugEnabled)
                {
                    log.Debug("Lookup ongoing exchange for " + keyUri);
                }
                Exchange ongoing;
                if (_ongoingExchanges.TryGetValue(keyUri, out ongoing))
                {
                    Exchange prev = _deduplicator.FindPrevious(keyId, ongoing);
                    if (prev != null)
                    {
                        if (log.IsInfoEnabled)
                        {
                            log.Info("Message is a duplicate: " + request);
                        }
                        request.Duplicate = true;
                    }
                    return(ongoing);
                }
                else
                {
                    // We have no ongoing exchange for that request block.

                    /*
                     * Note the difficulty of the following code: The first message
                     * of a blockwise transfer might arrive twice due to a
                     * retransmission. The new Exchange must be inserted in both the
                     * hash map 'ongoing' and the deduplicator. They must agree on
                     * which exchange they store!
                     */

                    Exchange exchange = new Exchange(request, Origin.Remote);
                    Exchange previous = _deduplicator.FindPrevious(keyId, exchange);
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("New ongoing exchange for remote Block1 request with key " + keyUri);
                    }
                    if (previous == null)
                    {
                        exchange.Completed       += OnExchangeCompleted;
                        _ongoingExchanges[keyUri] = exchange;
                        return(exchange);
                    }
                    else
                    {
                        if (log.IsInfoEnabled)
                        {
                            log.Info("Message is a duplicate: " + request);
                        }
                        request.Duplicate = true;
                        return(previous);
                    }
                } // if ongoing
            }     // if blockwise
        }
Пример #6
0
        /// <inheritdoc/>
        public void SendResponse(Exchange exchange, Response response)
        {
            if (response.ID == Message.None)
            {
                response.ID = System.Threading.Interlocked.Increment(ref _currentID) % (1 << 16);
            }

            /*
             * The response is a CON or NON or ACK and must be prepared for these
             * - CON  => ACK/RST // we only care to stop retransmission
             * - NON => RST // we don't care
             * - ACK  => nothing!
             * If this response goes lost, we must be prepared to get the same
             * CON/NON request with same MID again. We then find the corresponding
             * exchange and the ReliabilityLayer resends this response.
             */

            if (response.Destination == null)
            {
                throw new InvalidOperationException("Response has no destination set");
            }

            // If this is a CON notification we now can forget all previous NON notifications
            if (response.Type == MessageType.CON || response.Type == MessageType.ACK)
            {
                ObserveRelation relation = exchange.Relation;
                if (relation != null)
                {
                    RemoveNotificatoinsOf(relation);
                }
            }

            if (response.HasOption(OptionType.Block2))
            {
                Request         request = exchange.Request;
                Exchange.KeyUri keyUri  = new Exchange.KeyUri(request.URI, response.Destination);
                if (exchange.ResponseBlockStatus != null && !response.HasOption(OptionType.Observe))
                {
                    // Remember ongoing blockwise GET requests
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Ongoing Block2 started, storing " + keyUri + "\nOngoing " + request + "\nOngoing " + response);
                    }
                    _ongoingExchanges[keyUri] = exchange;
                }
                else
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Ongoing Block2 completed, cleaning up " + keyUri + "\nOngoing " + request + "\nOngoing " + response);
                    }
                    _ongoingExchanges.Remove(keyUri);
                }
            }

            // Insert CON and NON to match ACKs and RSTs to the exchange
            // Do not insert ACKs and RSTs.
            if (response.Type == MessageType.CON || response.Type == MessageType.NON)
            {
                Exchange.KeyID keyID = new Exchange.KeyID(response.ID, response.Destination);
                _exchangesByID[keyID] = exchange;
            }

            if (response.Type == MessageType.ACK || response.Type == MessageType.NON)
            {
                // Since this is an ACK or NON, the exchange is over with sending this response.
                if (response.Last)
                {
                    exchange.Complete = true;
                }
            } // else this is a CON and we need to wait for the ACK or RST
        }
Пример #7
0
        /// <inheritdoc/>
        public Exchange ReceiveResponse(Response response)
        {
            /*
             * This response could be
             * - The first CON/NON/ACK+response => deliver
             * - Retransmitted CON (because client got no ACK)
             *      => resend ACK
             */

            Exchange.KeyID keyId;
            if (response.Type == MessageType.ACK)
            {
                // own namespace
                keyId = new Exchange.KeyID(response.ID, null);
            }
            else
            {
                // remote namespace
                keyId = new Exchange.KeyID(response.ID, response.Source);
            }

            Exchange.KeyToken keyToken = new Exchange.KeyToken(response.Token);

            Exchange exchange;

            if (_exchangesByToken.TryGetValue(keyToken, out exchange))
            {
                // There is an exchange with the given token
                Exchange prev = _deduplicator.FindPrevious(keyId, exchange);
                if (prev != null)
                {
                    // (and thus it holds: prev == exchange)
                    if (log.IsInfoEnabled)
                    {
                        log.Info("Duplicate response for open exchange: " + response);
                    }
                    response.Duplicate = true;
                }
                else
                {
                    keyId = new Exchange.KeyID(exchange.CurrentRequest.ID, null);
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Exchange got response: Cleaning up " + keyId);
                    }
                    _exchangesByID.Remove(keyId);
                }

                if (response.Type == MessageType.ACK && exchange.CurrentRequest.ID != response.ID)
                {
                    // The token matches but not the MID. This is a response for an older exchange
                    if (log.IsWarnEnabled)
                    {
                        log.Warn("Possible MID reuse before lifetime end: " + response.TokenString + " expected MID " + exchange.CurrentRequest.ID + " but received " + response.ID);
                    }
                }

                return(exchange);
            }
            else
            {
                // There is no exchange with the given token.
                if (response.Type != MessageType.ACK)
                {
                    // only act upon separate responses
                    Exchange prev = _deduplicator.Find(keyId);
                    if (prev != null)
                    {
                        if (log.IsInfoEnabled)
                        {
                            log.Info("Duplicate response for completed exchange: " + response);
                        }
                        response.Duplicate = true;
                        return(prev);
                    }
                }
                else
                {
                    if (log.IsInfoEnabled)
                    {
                        log.Info("Ignoring unmatchable piggy-backed response from " + response.Source + ": " + response);
                    }
                }
                // ignore response
                return(null);
            }
        }
Пример #8
0
        /// <inheritdoc/>
        public void SendResponse(Exchange exchange, Response response)
        {
            if (response.ID == Message.None)
            {
                response.ID = System.Threading.Interlocked.Increment(ref _currentID) % (1 << 16);
            }

            /*
             * The response is a CON or NON or ACK and must be prepared for these
             * - CON => ACK / RST // we only care to stop retransmission
             * - NON => RST // we only care for observe
             * - ACK => nothing!
             * If this response goes lost, we must be prepared to get the same
             * CON/NON request with same MID again. We then find the corresponding
             * exchange and the ReliabilityLayer resends this response.
             */

            // If this is a CON notification we now can forget all previous NON notifications
            if (response.Type == MessageType.CON || response.Type == MessageType.ACK)
            {
                ObserveRelation relation = exchange.Relation;
                if (relation != null)
                {
                    RemoveNotificatoinsOf(relation);
                }
            }

            // Blockwise transfers are identified by URI and remote endpoint
            if (response.HasOption(OptionType.Block2))
            {
                Request         request = exchange.CurrentRequest;
                Exchange.KeyUri keyUri  = new Exchange.KeyUri(request.URI, response.Destination);
                // Observe notifications only send the first block, hence do not store them as ongoing
                if (exchange.ResponseBlockStatus != null && !response.HasOption(OptionType.Observe))
                {
                    // Remember ongoing blockwise GET requests
                    if (Utils.Put(_ongoingExchanges, keyUri, exchange) == null)
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("Ongoing Block2 started late, storing " + keyUri + " for " + request);
                        }
                    }
                    else
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("Ongoing Block2 continued, storing " + keyUri + " for " + request);
                        }
                    }
                }
                else
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Ongoing Block2 completed, cleaning up " + keyUri + " for " + request);
                    }
                    Exchange exc;
                    _ongoingExchanges.TryRemove(keyUri, out exc);
                }
            }

            // Insert CON and NON to match ACKs and RSTs to the exchange
            // Do not insert ACKs and RSTs.
            if (response.Type == MessageType.CON || response.Type == MessageType.NON)
            {
                Exchange.KeyID keyID = new Exchange.KeyID(response.ID, null);
                _exchangesByID[keyID] = exchange;
            }

            // Only CONs and Observe keep the exchange active
            if (response.Type != MessageType.CON && response.Last)
            {
                exchange.Complete = true;
            }
        }