/// <inheritdoc/> public void AddObserveRelation(ObserveRelation relation) { ObserveRelation old = null; _observeRelations.AddOrUpdate(relation.Key, relation, (k, v) => { old = v; return(relation); }); if (old != null) { old.Cancel(); 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); } } }
/// <inheritdoc/> public override void ReceiveEmptyMessage(INextLayer nextLayer, Exchange exchange, EmptyMessage message) { // NOTE: We could also move this into the MessageObserverAdapter from // sendResponse into the method rejected(). if (message.Type == MessageType.RST && exchange.Origin == Origin.Remote) { // The response has been rejected ObserveRelation relation = exchange.Relation; if (relation != null) { relation.Cancel(); } // else there was no observe relation ship and this layer ignores the rst } base.ReceiveEmptyMessage(nextLayer, exchange, message); }
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(); } } } }
/// <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); }