Пример #1
0
 /// <inheritdoc/>
 public void AddObserveRelation(ObserveRelation relation)
 {
     if (_observeRelations.AddOrUpdate(relation, false, (k, v) => true))
     {
         if (log.IsDebugEnabled)
         {
             log.Debug("Replacing observe relation between " + relation.Key + " and resource " + Uri);
         }
     }
     else
     {
         if (log.IsDebugEnabled)
         {
             log.Debug("Successfully established observe relation between " + relation.Key + " and resource " + Uri);
         }
     }
 }
        private void CheckForObserveOption(Exchange exchange, IResource resource)
        {
            Request request = exchange.Request;

            if (request.Method != Method.GET)
            {
                return;
            }

            System.Net.EndPoint source = request.Source;
            Int32?obs = request.Observe;

            if (obs.HasValue && resource.Observable)
            {
                if (obs == 0)
                {
                    // Requests wants to observe and resource allows it :-)
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Initiate an observe relation between " + source + " and resource " + resource.Uri);
                    }
                    ObservingEndpoint remote   = _observeManager.FindObservingEndpoint(source);
                    ObserveRelation   relation = new ObserveRelation(_config, remote, resource, exchange);
                    remote.AddObserveRelation(relation);
                    exchange.Relation = relation;
                    // all that's left is to add the relation to the resource which
                    // the resource must do itself if the response is successful
                }
                else if (obs == 1)
                {
                    ObserveRelation relation = _observeManager.GetRelation(source, request.Token);
                    if (relation != null)
                    {
                        relation.Cancel();
                    }
                }
            }
        }
Пример #3
0
        /// <inheritdoc/>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            ObserveRelation relation = exchange.Relation;

            if (relation != null && relation.Established)
            {
                if (exchange.Request.IsAcknowledged || exchange.Request.Type == MessageType.NON)
                {
                    // Transmit errors as CON
                    if (!Code.IsSuccess(response.Code))
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("Response has error code " + response.Code + " and must be sent as CON");
                        }
                        response.Type = MessageType.CON;
                        relation.Cancel();
                    }
                    else
                    {
                        // Make sure that every now and than a CON is mixed within
                        if (relation.Check())
                        {
                            if (log.IsDebugEnabled)
                            {
                                log.Debug("The observe relation check requires the notification to be sent as CON");
                            }
                            response.Type = MessageType.CON;
                        }
                        else
                        {
                            // By default use NON, but do not override resource decision
                            if (response.Type == MessageType.Unknown)
                            {
                                response.Type = MessageType.NON;
                            }
                        }
                    }
                }

                // This is a notification
                response.Last = false;

                /*
                 * The matcher must be able to find the NON notifications to remove
                 * them from the exchangesByID map
                 */
                if (response.Type == MessageType.NON)
                {
                    relation.AddNotification(response);
                }

                /*
                 * Only one Confirmable message is allowed to be in transit. A CON
                 * is in transit as long as it has not been acknowledged, rejected,
                 * or timed out. All further notifications are postponed here. If a
                 * former CON is acknowledged or timeouts, it starts the freshest
                 * notification (In case of a timeout, it keeps the retransmission
                 * counter). When a fresh/younger notification arrives but must be
                 * postponed we forget any former notification.
                 */
                if (response.Type == MessageType.CON)
                {
                    PrepareSelfReplacement(nextLayer, exchange, response);
                }

                // The decision whether to postpone this notification or not and the
                // decision which notification is the freshest to send next must be
                // synchronized
                lock (exchange)
                {
                    Response current = relation.CurrentControlNotification;
                    if (current != null && IsInTransit(current))
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("A former notification is still in transit. Postpone " + response);
                        }
                        // use the same ID
                        response.ID = current.ID;
                        relation.NextControlNotification = response;
                        return;
                    }
                    else
                    {
                        relation.CurrentControlNotification = response;
                        relation.NextControlNotification    = null;
                    }
                }
            }
            // else no observe was requested or the resource does not allow it
            base.SendResponse(nextLayer, exchange, response);
        }
Пример #4
0
        private void PrepareSelfReplacement(INextLayer nextLayer, Exchange exchange, Response response)
        {
            response.Acknowledged += (o, e) =>
            {
                lock (exchange)
                {
                    ObserveRelation relation = exchange.Relation;
                    Response        next     = relation.NextControlNotification;
                    relation.CurrentControlNotification = next; // next may be null
                    relation.NextControlNotification    = null;
                    if (next != null)
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("Notification has been acknowledged, send the next one");
                        }
                        // this is not a self replacement, hence a new ID
                        next.ID = Message.None;
                        // Create a new task for sending next response so that we can leave the sync-block
                        Executor.Start(() => SendResponse(nextLayer, exchange, next));
                    }
                }
            };

            response.Retransmitting += (o, e) =>
            {
                lock (exchange)
                {
                    ObserveRelation relation = exchange.Relation;
                    Response        next     = relation.NextControlNotification;
                    if (next != null)
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("The notification has timed out and there is a fresher notification for the retransmission.");
                        }
                        // Cancel the original retransmission and send the fresh notification here
                        response.IsCancelled = true;
                        // use the same ID
                        next.ID = response.ID;
                        // Convert all notification retransmissions to CON
                        if (next.Type != MessageType.CON)
                        {
                            next.Type = MessageType.CON;
                            PrepareSelfReplacement(nextLayer, exchange, next);
                        }
                        relation.CurrentControlNotification = next;
                        relation.NextControlNotification    = null;
                        // Create a new task for sending next response so that we can leave the sync-block
                        Executor.Start(() => SendResponse(nextLayer, exchange, next));
                    }
                }
            };

            response.TimedOut += (o, e) =>
            {
                ObserveRelation relation = exchange.Relation;
                if (log.IsDebugEnabled)
                {
                    log.Debug("Notification" + relation.Exchange.Request.TokenString
                              + " timed out. Cancel all relations with source " + relation.Source);
                }
                relation.CancelAll();
            };
        }
Пример #5
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;
            }
        }
Пример #6
0
        /// <inheritdoc/>
        public void RemoveObserveRelation(ObserveRelation relation)
        {
            Boolean val;

            _observeRelations.TryRemove(relation, out val);
        }
Пример #7
0
        private void OnExchangeCompleted(Object sender, EventArgs e)
        {
            Exchange exchange = (Exchange)sender;

            /*
             * Logging in this method leads to significant performance loss.
             * Uncomment logging code only for debugging purposes.
             */

            if (exchange.Origin == Origin.Local)
            {
                // this endpoint created the Exchange by issuing a request
                Exchange.KeyID    keyID    = new Exchange.KeyID(exchange.CurrentRequest.ID, null, null);
                Exchange.KeyToken keyToken = new Exchange.KeyToken(exchange.CurrentRequest.Token);

                if (_Log.IsDebugEnabled)
                {
                    _Log.Debug("Exchange completed: Cleaning up " + keyToken);
                }

                _exchangesByToken.Remove(keyToken);
                // in case an empty ACK was lost
                _exchangesByID.Remove(keyID);
            }
            else // Origin.Remote
            {
                // this endpoint created the Exchange to respond a request

                Response response = exchange.CurrentResponse;
                if (response != null && response.Type != MessageType.ACK)
                {
                    // only response MIDs are stored for ACK and RST, no reponse Tokens
                    Exchange.KeyID midKey = new Exchange.KeyID(response.ID, null, response.Session);
                    //if (log.IsDebugEnabled)
                    //    log.Debug("Remote ongoing completed, cleaning up " + midKey);
                    _exchangesByID.Remove(midKey);
                }

                Request request = exchange.CurrentRequest;
                if (request != null && (request.HasOption(OptionType.Block1) || response.HasOption(OptionType.Block2)))
                {
#if INCLUDE_OSCOAP
                    byte[] oscoapValue = null;
                    if (request.HasOption(OptionType.Oscoap))
                    {
                        oscoapValue = request.Oscoap.RawValue;
                    }
                    Exchange.KeyUri uriKey = new Exchange.KeyUri(request.URI, oscoapValue, request.Source);
#else
                    Exchange.KeyUri uriKey = new Exchange.KeyUri(request.URI, request.Source);
#endif
                    if (_Log.IsDebugEnabled)
                    {
                        _Log.Debug("Remote ongoing completed, cleaning up " + uriKey);
                    }
                    Exchange exc;
                    _ongoingExchanges.TryRemove(uriKey, out exc);
                }

                // Remove all remaining NON-notifications if this exchange is an observe relation
                ObserveRelation relation = exchange.Relation;
                if (relation != null)
                {
                    RemoveNotificatoinsOf(relation);
                }
            }
        }
Пример #8
0
 /// <inheritdoc/>
 public void RemoveObserveRelation(ObserveRelation relation)
 {
     ((ICollection <KeyValuePair <String, ObserveRelation> >)_observeRelations).Remove(new KeyValuePair <String, ObserveRelation>(relation.Key, relation));
 }
Пример #9
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
        }