Exemple #1
0
        private void PrepareTimeout(INextLayer nextLayer, Exchange exchange, Response response)
        {
            log.Debug(m => m($"PrepareTimeout - for response {response}"));
            response.TimedOut += (o, e) => {
                lock (exchange) {
                    ObserveRelation relation = exchange.Relation;
                    log.Debug(m => m($"Notification {relation.Exchange.Request.TokenString} timed out."));

                    Response next = relation.NextControlNotification;
                    if (next != null)
                    {
                        log.Debug("The notification has timed out and there is a fresher notification for the retransmission.");

                        // don't use the same ID
                        // next.ID = response.ID;
                        next.ID = Message.None;

                        relation.CurrentControlNotification = next;
                        relation.NextControlNotification    = null;

                        // Create a new task for sending next response so that we can leave the sync-block
                        Executor.Start(() => base.SendResponse(nextLayer, exchange, next));
                    }
                }
            };
        }
        /// <summary>
        /// When we receive a Confirmable response, we acknowledge it and it also
        /// counts as acknowledgment for the request. If the response is a duplicate,
        /// we stop it here and do not forward it to the upper layer.
        /// </summary>
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            TransmissionContext ctx = (TransmissionContext)exchange.Remove(TransmissionContextKey);

            if (ctx != null)
            {
                exchange.CurrentRequest.IsAcknowledged = true;
                ctx.Cancel();
            }

            if (response.Type == MessageType.CON && !exchange.Request.IsCancelled)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Response is confirmable, send ACK.");
                }
                EmptyMessage ack = EmptyMessage.NewACK(response);
                SendEmptyMessage(nextLayer, exchange, ack);
            }

            if (response.Duplicate)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Response is duplicate, ignore it.");
                }
            }
            else
            {
                base.ReceiveResponse(nextLayer, exchange, response);
            }
        }
Exemple #3
0
        /// <inheritdoc/>
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (response.HasOption(OptionType.Observe))
            {
                if (exchange.Request.IsCancelled)
                {
                    // The request was canceled and we no longer want notifications
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("ObserveLayer rejecting notification for canceled Exchange");
                    }

                    EmptyMessage rst = EmptyMessage.NewRST(response);
                    SendEmptyMessage(nextLayer, exchange, rst);
                    // Matcher sets exchange as complete when RST is sent
                }
                else
                {
                    PrepareReregistration(exchange, response, msg => SendRequest(nextLayer, exchange, msg));
                    base.ReceiveResponse(nextLayer, exchange, response);
                }
            }
            else
            {
                // No observe option in response => always deliver
                base.ReceiveResponse(nextLayer, exchange, response);
            }
        }
Exemple #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)
                    {
                        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(() => base.SendResponse(nextLayer, exchange, next));
                    }
                }
            };

            response.Retransmitting += (o, e) => {
                lock (exchange) {
                    ObserveRelation relation = exchange.Relation;
                    Response        next     = relation.NextControlNotification;
                    if (next != null)
                    {
                        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;

                        if (relation.CurrentControlNotification.Type == MessageType.CON)
                        {
                            // use the same ID if continuing from CON to CON
                            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(() => base.SendResponse(nextLayer, exchange, next));
                    }
                }
            };

            response.TimedOut += (o, e) => {
                ObserveRelation relation = exchange.Relation;
                log.Debug(m => m($"Notification {relation.Exchange.Request.TokenString} timed out. Cancel all relations with source {relation.Source}"));
                relation.CancelAll();
            };
        }
Exemple #5
0
 /// <inheritdoc/>
 public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     if (request.Token == null)
     {
         request.Token = NewToken();
     }
     base.SendRequest(nextLayer, exchange, request);
 }
Exemple #6
0
 /// <inheritdoc/>
 public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     if (exchange.CurrentRequest.Token == null)
     {
         throw new InvalidOperationException("Received requests's token cannot be null, use byte[0] for empty tokens");
     }
     base.ReceiveRequest(nextLayer, exchange, request);
 }
Exemple #7
0
 /// <inheritdoc/>
 public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
 {
     if (response.Token == null)
     {
         throw new InvalidOperationException("Received response's token cannot be null, use byte[0] for empty tokens");
     }
     base.ReceiveResponse(nextLayer, exchange, response);
 }
Exemple #8
0
 /// <inheritdoc/>
 public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
 {
     // A response must have the same token as the request it belongs to. If
     // the token is empty, we must use a byte array of length 0.
     if (response.Token == null)
         response.Token = exchange.CurrentRequest.Token;
     base.SendResponse(nextLayer, exchange, response);
 }
 /// <summary>
 /// When we receive a duplicate of a request, we stop it here and do not
 /// forward it to the upper layer. If the server has already sent a response,
 /// we send it again. If the request has only been acknowledged (but the ACK
 /// has gone lost or not reached the client yet), we resent the ACK. If the
 /// request has neither been responded, acknowledged or rejected yet, the
 /// server has not yet decided what to do with the request and we cannot do
 /// anything.
 /// </summary>
 public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     if (request.Duplicate)
     {
         // Request is a duplicate, so resend ACK, RST or response
         if (exchange.CurrentResponse != null)
         {
             if (log.IsDebugEnabled)
             {
                 log.Debug("Respond with the current response to the duplicate request");
             }
             base.SendResponse(nextLayer, exchange, exchange.CurrentResponse);
         }
         else if (exchange.CurrentRequest != null)
         {
             if (exchange.CurrentRequest.IsAcknowledged)
             {
                 if (log.IsDebugEnabled)
                 {
                     log.Debug("The duplicate request was acknowledged but no response computed yet. Retransmit ACK.");
                 }
                 EmptyMessage ack = EmptyMessage.NewACK(request);
                 SendEmptyMessage(nextLayer, exchange, ack);
             }
             else if (exchange.CurrentRequest.IsRejected)
             {
                 if (log.IsDebugEnabled)
                 {
                     log.Debug("The duplicate request was rejected. Reject again.");
                 }
                 EmptyMessage rst = EmptyMessage.NewRST(request);
                 SendEmptyMessage(nextLayer, exchange, rst);
             }
             else
             {
                 if (log.IsDebugEnabled)
                 {
                     log.Debug("The server has not yet decided what to do with the request. We ignore the duplicate.");
                 }
                 // The server has not yet decided, whether to acknowledge or
                 // reject the request. We know for sure that the server has
                 // received the request though and can drop this duplicate here.
             }
         }
         else
         {
             // Lost the current request. The server has not yet decided what to do.
         }
     }
     else
     {
         // Request is not a duplicate
         exchange.CurrentRequest = request;
         base.ReceiveRequest(nextLayer, exchange, request);
     }
 }
Exemple #10
0
        /// <inheritdoc/>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            BlockOption block1 = exchange.Block1ToAck;

            if (block1 != null)
            {
                exchange.Block1ToAck = null;
            }

            if (RequiresBlockwise(exchange, response))
            {
                log.Debug(m => m("Response payload {0}/{1} requires Blockwise", response.PayloadSize, _maxMessageSize));

                BlockwiseStatus status = FindResponseBlockStatus(exchange, response);

                Response block = GetNextResponseBlock(response, status);

                if (block1 != null)
                {
                    // in case we still have to ack the last block1
                    block.SetOption(block1);
                }

                if (block.Token == null)
                {
                    block.Token = exchange.Request.Token;
                }

                if (status.Complete)
                {
                    // clean up blockwise status
                    log.Debug(m => m("Ongoing finished on first block {0}", status));
                    exchange.ResponseBlockStatus = null;
                    ClearBlockCleanup(exchange);
                }
                else
                {
                    log.Debug(m => m("Ongoing started {0}", status));
                }

                exchange.CurrentResponse = block;
                base.SendResponse(nextLayer, exchange, block);
            }
            else
            {
                if (block1 != null)
                {
                    response.SetOption(block1);
                }

                exchange.CurrentResponse = response;
                // Block1 transfer completed
                ClearBlockCleanup(exchange);
                base.SendResponse(nextLayer, exchange, response);
            }
        }
 /// <inheritdoc/>
 public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
 {
     // A response must have the same token as the request it belongs to. If
     // the token is empty, we must use a byte array of length 0.
     if (response.Token == null)
     {
         response.Token = exchange.CurrentRequest.Token;
     }
     base.SendResponse(nextLayer, exchange, response);
 }
        /// <inheritdoc/>
        public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
#if false
            //  We now do this at the matcher layer so it can be random
            if (request.Token == null)
            {
                request.Token = NewToken();
            }
#endif
            base.SendRequest(nextLayer, exchange, request);
        }
Exemple #13
0
            public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
            {
                if (exchange == null)
                {
                    exchange          = new Exchange(request, Origin.Local);
                    exchange.EndPoint = request.EndPoint;
                }

                exchange.Request = request;
                base.SendRequest(nextLayer, exchange, request);
            }
Exemple #14
0
 public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     // if there is no BlockwiseLayer we still have to set it
     if (exchange.Request == null)
     {
         exchange.Request = request;
     }
     if (exchange.Deliverer != null)
     {
         exchange.Deliverer.DeliverRequest(exchange);
     }
 }
Exemple #15
0
 public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
 {
     if (!response.HasOption(OptionType.Observe))
     {
         exchange.Complete = true;
     }
     if (exchange.Deliverer != null)
     {
         // notify request that response has arrived
         exchange.Deliverer.DeliverResponse(exchange, response);
     }
 }
Exemple #16
0
        /// <inheritdoc/>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            BlockOption block1 = exchange.Block1ToAck;

            if (block1 != null)
            {
                exchange.Block1ToAck = null;
            }

            if (RequiresBlockwise(exchange, response))
            {
                // This must be a large response to a GET or POST request (PUT?)
                if (log.IsDebugEnabled)
                {
                    log.Debug("Response payload " + response.PayloadSize + "/" + _maxMessageSize + " requires Blockwise");
                }

                BlockwiseStatus status = FindResponseBlockStatus(exchange, response);

                Response block = GetNextResponseBlock(response, status);
                block.Type = response.Type; // This is only true for the first block
                if (block1 != null)         // in case we still have to ack the last block1
                {
                    block.SetOption(block1);
                }
                if (block.Token == null)
                {
                    block.Token = exchange.Request.Token;
                }

                if (response.HasOption(OptionType.Observe))
                {
                    // the ACK for the first block should acknowledge the whole notification
                    exchange.CurrentResponse = response;
                }
                else
                {
                    exchange.CurrentResponse = block;
                }
                base.SendResponse(nextLayer, exchange, block);
            }
            else
            {
                if (block1 != null)
                {
                    response.SetOption(block1);
                }
                exchange.CurrentResponse = response;
                base.SendResponse(nextLayer, exchange, response);
            }
        }
Exemple #17
0
        /// <summary>
        /// // Schedules a retransmission for confirmable messages.
        /// </summary>
        public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if (request.Type == MessageType.Unknown)
                request.Type = MessageType.CON;

            if (request.Type == MessageType.CON)
            {
                if (log.IsDebugEnabled)
                    log.Debug("Scheduling retransmission for " + request);
                PrepareRetransmission(exchange, request, ctx => SendRequest(nextLayer, exchange, request));
            }

            base.SendRequest(nextLayer, exchange, request);
        }
        /// <summary>
        /// // Schedules a retransmission for confirmable messages.
        /// </summary>
        public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if (request.Type == MessageType.Unknown)
            {
                request.Type = MessageType.CON;
            }

            if (request.Type == MessageType.CON)
            {
                _Log.Debug(m => m("Scheduling retransmission for {0}", request));
                PrepareRetransmission(exchange, request, ctx => SendRequest(nextLayer, exchange, request));
            }

            base.SendRequest(nextLayer, exchange, request);
        }
Exemple #19
0
 /// <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);
 }
Exemple #20
0
        /// <summary>
        /// Makes sure that the response type is correct. The response type for a NON
        /// can be NON or CON. The response type for a CON should either be an ACK
        /// with a piggy-backed response or, if an empty ACK has already be sent, a
        /// CON or NON with a separate response.
        /// </summary>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            MessageType mt = response.Type;

            if (mt == MessageType.Unknown)
            {
                MessageType reqType = exchange.CurrentRequest.Type;
                if (reqType == MessageType.CON)
                {
                    if (exchange.CurrentRequest.IsAcknowledged)
                    {
                        // send separate response
                        response.Type = MessageType.CON;
                    }
                    else
                    {
                        exchange.CurrentRequest.IsAcknowledged = true;
                        // send piggy-backed response
                        response.Type = MessageType.ACK;
                        response.ID   = exchange.CurrentRequest.ID;
                    }
                }
                else
                {
                    // send NON response
                    response.Type = MessageType.NON;
                }
            }
            else if (mt == MessageType.ACK || mt == MessageType.RST)
            {
                response.ID = exchange.CurrentRequest.ID;
            }

            if (response.Type == MessageType.CON)
            {
                _Log.Debug(m => m("Scheduling retransmission for {0}", response));
                PrepareRetransmission(exchange, response, ctx => SendResponse(nextLayer, exchange, response));
            }
            else if (response.Type == MessageType.NON && response.HasOption(OptionType.Observe))
            {
                _Log.Debug(m => m($"Scheduling timeout for {response}  @ {_nonTimeout}"));
                PrepareTimeout(exchange, response);
            }

            base.SendResponse(nextLayer, exchange, response);
        }
        /// <summary>
        /// If we receive an ACK or RST, we mark the outgoing request or response
        /// as acknowledged or rejected respectively and cancel its retransmission.
        /// </summary>
        public override void ReceiveEmptyMessage(INextLayer nextLayer, Exchange exchange, EmptyMessage message)
        {
            switch (message.Type)
            {
            case MessageType.ACK:
                if (exchange.Origin == Origin.Local)
                {
                    exchange.CurrentRequest.IsAcknowledged = true;
                }
                else
                {
                    exchange.CurrentResponse.IsAcknowledged = true;
                }

                break;

            case MessageType.RST:
                if (exchange.Origin == Origin.Local)
                {
                    exchange.CurrentRequest.IsRejected = true;
                }
                else
                {
                    exchange.CurrentResponse.IsRejected = true;
                }

                break;

            default:
                if (_Log.IsWarnEnabled)
                {
                    _Log.Warn("Empty messgae was not ACK nor RST: " + message);
                }
                break;
            }

            TransmissionContext ctx = (TransmissionContext)exchange.Remove(_TransmissionContextKey);

            if (ctx != null)
            {
                ctx.Cancel();
            }

            base.ReceiveEmptyMessage(nextLayer, exchange, message);
        }
        /// <inheritdoc/>
        public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            //  This assumes we don't change individual options - if this is not true then we need to do a deep copy.
            exchange.PreSecurityOptions = request.GetOptions().ToList();

            if ((request.Oscoap == null) && (exchange.OscoreContext == null))
            {
                base.SendRequest(nextLayer, exchange, request);
            }
            else if (request.HasOption(OptionType.Block2) && request.Block2.NUM > 0)
            {
                // This is the case if the user has explicitly added a block option
                // for random access.
                // Note: We do not regard it as random access when the block num is
                // 0. This is because the user might just want to do early block
                // size negotiation but actually wants to receive all blocks.
                log.Debug("Request carries explicit defined block2 option: create random access blockwise status");

                BlockwiseStatus status = new BlockwiseStatus(request.ContentFormat);
                BlockOption     block2 = request.Block2;
                status.CurrentSZX     = block2.SZX;
                status.CurrentNUM     = block2.NUM;
                status.IsRandomAccess = true;
                exchange.OSCOAP_ResponseBlockStatus = status;
                base.SendRequest(nextLayer, exchange, request);
            }
            else if (RequiresBlockwise(request))
            {
                // This must be a large POST or PUT request
                log.Debug(m => m($"Request payload {request.PayloadSize}/{_maxMessageSize} requires Blockwise."));

                BlockwiseStatus status = FindRequestBlockStatus(exchange, request);
                Request         block  = GetNextRequestBlock(request, exchange.PreSecurityOptions, status);
                exchange.OscoreRequestBlockStatus = status;
                exchange.CurrentRequest           = block;

                log.Debug($"Block message to send: {block}");
                base.SendRequest(nextLayer, exchange, block);
            }
            else
            {
                exchange.CurrentRequest = request;
                base.SendRequest(nextLayer, exchange, request);
            }
        }
Exemple #23
0
 /// <inheritdoc/>
 public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     if ((request.Oscoap == null) && (exchange.OscoapContext == null))
     {
         base.SendRequest(nextLayer, exchange, request);
     }
     else if (request.HasOption(OptionType.Block2) && request.Block2.NUM > 0)
     {
         // This is the case if the user has explicitly added a block option
         // for random access.
         // Note: We do not regard it as random access when the block num is
         // 0. This is because the user might just want to do early block
         // size negotiation but actually wants to receive all blocks.
         if (log.IsDebugEnabled)
         {
             log.Debug("Request carries explicit defined block2 option: create random access blockwise status");
         }
         BlockwiseStatus status = new BlockwiseStatus(request.ContentFormat);
         BlockOption     block2 = request.Block2;
         status.CurrentSZX     = block2.SZX;
         status.CurrentNUM     = block2.NUM;
         status.IsRandomAccess = true;
         exchange.OSCOAP_ResponseBlockStatus = status;
         base.SendRequest(nextLayer, exchange, request);
     }
     else if (RequiresBlockwise(request))
     {
         // This must be a large POST or PUT request
         if (log.IsDebugEnabled)
         {
             log.Debug("Request payload " + request.PayloadSize + "/" + _maxMessageSize + " requires Blockwise.");
         }
         BlockwiseStatus status = FindRequestBlockStatus(exchange, request);
         Request         block  = GetNextRequestBlock(request, status);
         exchange.OSCOAP_RequestBlockStatus = status;
         exchange.CurrentRequest            = block;
         base.SendRequest(nextLayer, exchange, block);
     }
     else
     {
         exchange.CurrentRequest = request;
         base.SendRequest(nextLayer, exchange, request);
     }
 }
        /// <summary>
        /// Makes sure that the response type is correct. The response type for a NON
        /// can be NON or CON. The response type for a CON should either be an ACK
        /// with a piggy-backed response or, if an empty ACK has already be sent, a
        /// CON or NON with a separate response.
        /// </summary>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            MessageType mt = response.Type;

            if (mt == MessageType.Unknown)
            {
                MessageType reqType = exchange.CurrentRequest.Type;
                if (reqType == MessageType.CON)
                {
                    if (exchange.CurrentRequest.IsAcknowledged)
                    {
                        // send separate response
                        response.Type = MessageType.CON;
                    }
                    else
                    {
                        exchange.CurrentRequest.IsAcknowledged = true;
                        // send piggy-backed response
                        response.Type = MessageType.ACK;
                        response.ID   = exchange.CurrentRequest.ID;
                    }
                }
                else
                {
                    // send NON response
                    response.Type = MessageType.NON;
                }
            }
            else if (mt == MessageType.ACK || mt == MessageType.RST)
            {
                response.ID = exchange.CurrentRequest.ID;
            }

            if (response.Type == MessageType.CON)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Scheduling retransmission for " + response);
                }
                PrepareRetransmission(exchange, response, ctx => SendResponse(nextLayer, exchange, response));
            }

            base.SendResponse(nextLayer, exchange, response);
        }
Exemple #25
0
        /// <summary>
        /// Makes sure that the response type is correct. The response type for a NON
	    /// can be NON or CON. The response type for a CON should either be an ACK
	    /// with a piggy-backed response or, if an empty ACK has already be sent, a
        /// CON or NON with a separate response.
        /// </summary>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            MessageType mt = response.Type;
            if (mt == MessageType.Unknown)
            {
                MessageType reqType = exchange.CurrentRequest.Type;
                if (reqType == MessageType.CON)
                {
                    if (exchange.CurrentRequest.IsAcknowledged)
                    {
                        // send separate response
                        response.Type = MessageType.CON;
                    }
                    else
                    {
                        exchange.CurrentRequest.IsAcknowledged = true;
                        // send piggy-backed response
                        response.Type = MessageType.ACK;
                        response.ID = exchange.CurrentRequest.ID;
                    }
                }
                else
                {
                    // send NON response
                    response.Type = MessageType.NON;
                }
            }
            else if (mt == MessageType.ACK || mt == MessageType.RST)
            {
                response.ID = exchange.CurrentRequest.ID;
            }

            if (response.Type == MessageType.CON)
            {
                if (log.IsDebugEnabled)
                    log.Debug("Scheduling retransmission for " + response);
                PrepareRetransmission(exchange, response, ctx => SendResponse(nextLayer, exchange, response));
            }

            base.SendResponse(nextLayer, exchange, response);
        }
Exemple #26
0
        /// <inheritdoc/>
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (response.HasOption(OptionType.Observe))
            {
                if (exchange.Request.IsCancelled)
                {
                    // The request was canceled and we no longer want notifications
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("ObserveLayer rejecting notification for canceled Exchange");
                    }
                    EmptyMessage rst = EmptyMessage.NewRST(response);
                    SendEmptyMessage(nextLayer, exchange, rst);
                    // Matcher sets exchange as complete when RST is sent
                }
                else
                {
                    // Reregistration is currently not supported and will be handled on another level
                    // REMARK:
                    //  - "Cancel()"- or "ProactiveCancel()" of "ObserveRelation" cancels the initial request
                    //  - "ReregistrationContext" takes into consideration the wrong request
                    // This seems to be a bug

                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Reregistration not supported");
                    }

                    //PrepareReregistration(exchange, response, msg => SendRequest(nextLayer, exchange, msg));

                    base.ReceiveResponse(nextLayer, exchange, response);
                }
            }
            else
            {
                // No observe option in response => always deliver
                base.ReceiveResponse(nextLayer, exchange, response);
            }
        }
Exemple #27
0
        /// <inheritdoc/>
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (response.HasOption(OptionType.Observe))
            {
                if (exchange.Request.IsCancelled)
                {
                    // The request was canceled and we no longer want notifications
                    log.Debug("ObserveLayer rejecting notification for canceled Exchange");

                    EmptyMessage rst = EmptyMessage.NewRST(response);
                    SendEmptyMessage(nextLayer, exchange, rst);
                    // Matcher sets exchange as complete when RST is sent

                    return;
                }

                if (exchange.Request.ObserveReconnect)
                {
                    PrepareReregistration(exchange, response, msg => SendRequest(nextLayer, exchange, msg));
                }
            }
            base.ReceiveResponse(nextLayer, exchange, response);
        }
Exemple #28
0
 /// <inheritdoc/>
 public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     if (request.HasOption(OptionType.Block2) && request.Block2.NUM > 0)
     {
         // This is the case if the user has explicitly added a block option
         // for random access.
         // Note: We do not regard it as random access when the block num is
         // 0. This is because the user might just want to do early block
         // size negotiation but actually wants to receive all blocks.
         if (log.IsDebugEnabled)
             log.Debug("Request carries explicit defined block2 option: create random access blockwise status");
         BlockwiseStatus status = new BlockwiseStatus(request.ContentFormat);
         BlockOption block2 = request.Block2;
         status.CurrentSZX = block2.SZX;
         status.CurrentNUM = block2.NUM;
         status.IsRandomAccess = true;
         exchange.ResponseBlockStatus = status;
         base.SendRequest(nextLayer, exchange, request);
     }
     else if (RequiresBlockwise(request))
     {
         // This must be a large POST or PUT request
         if (log.IsDebugEnabled)
             log.Debug("Request payload " + request.PayloadSize + "/" + _maxMessageSize + " requires Blockwise.");
         BlockwiseStatus status = FindRequestBlockStatus(exchange, request);
         Request block = GetNextRequestBlock(request, status);
         exchange.RequestBlockStatus = status;
         exchange.CurrentRequest = block;
         base.SendRequest(nextLayer, exchange, block);
     }
     else
     {
         exchange.CurrentRequest = request;
         base.SendRequest(nextLayer, exchange, request);
     }
 }
Exemple #29
0
        /// <inheritdoc />
        public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if ((request.OscoapContext != null) || (exchange.OscoapContext != null))
            {
                SecurityContext ctx = exchange.OscoapContext;
                if (request.OscoapContext != null)
                {
                    ctx = request.OscoapContext;
                    exchange.OscoapContext = ctx;
                }

                Codec.IMessageEncoder me = Spec.NewMessageEncoder();
                Request encryptedRequest = new Request(request.Method);

                if (request.Payload != null)
                {
                    encryptedRequest.Payload = request.Payload;
                }

                MoveRequestHeaders(request, encryptedRequest);

                _Log.Info(m => m("New inner response message\n{0}", encryptedRequest.ToString()));

                ctx.Sender.IncrementSequenceNumber();

                Encrypt0Message enc       = new Encrypt0Message(false);
                byte[]          msg       = me.Encode(encryptedRequest);
                int             tokenSize = msg[0] & 0xf;
                byte[]          msg2      = new byte[msg.Length - (3 + tokenSize)];
                Array.Copy(msg, 4 + tokenSize, msg2, 1, msg2.Length - 1);
                msg2[0] = msg[1];
                enc.SetContent(msg2);

                // Build AAD
                CBORObject aad = CBORObject.NewArray();
                aad.Add(CBORObject.FromObject(1)); // version
                aad.Add(CBORObject.NewArray());
                aad[1].Add(CBORObject.FromObject(ctx.Sender.Algorithm));
                aad.Add(CBORObject.FromObject(ctx.Sender.Id));
                aad.Add(CBORObject.FromObject(ctx.Sender.PartialIV));
                aad.Add(CBORObject.FromObject(new byte[0]));
                if (ctx.GroupId != null)
                {
                    aad.Add(CBORObject.FromObject(ctx.GroupId));
                }

#if DEBUG
                switch (SecurityContext.FutzError)
                {
                case 1:
                    aad[0] = CBORObject.FromObject(2);
                    break;     // Change version #

                case 2:
                    aad[1] = CBORObject.FromObject(request.Code + 1);
                    break;     // Change request code

                case 3:
                    aad[2] = CBORObject.FromObject(ctx.Sender.Algorithm.AsInt32() + 1);
                    break;     // Change algorithm number
                }
#endif

                _Log.Info(m => m("SendRequest: AAD = {0}", BitConverter.ToString(aad.EncodeToBytes())));

                enc.SetExternalData(aad.EncodeToBytes());
#if DEBUG
                {
                    byte[] fooX = ctx.Sender.PartialIV;
                    if (SecurityContext.FutzError == 8)
                    {
                        fooX[fooX.Length - 1] += 1;
                    }
                    enc.AddAttribute(HeaderKeys.IV, ctx.Sender.GetIV(fooX), Attributes.DO_NOT_SEND);
                }
#else
                enc.AddAttribute(HeaderKeys.IV, ctx.Sender.GetIV(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND);
#endif
                enc.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), /* Attributes.PROTECTED */ Attributes.DO_NOT_SEND);
                enc.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.Algorithm, Attributes.DO_NOT_SEND);
                enc.AddAttribute(HeaderKeys.KeyId, CBORObject.FromObject(ctx.Sender.Id), /*Attributes.PROTECTED*/ Attributes.DO_NOT_SEND);
                if (ctx.GroupId != null)
                {
                    enc.AddAttribute(CBORObject.FromObject("gid"), CBORObject.FromObject(ctx.GroupId), Attributes.DO_NOT_SEND);
                }

                if (_Log.IsInfoEnabled)
                {
                    _Log.Info("SendRequest: AAD = " + BitConverter.ToString(aad.EncodeToBytes()));
                    _Log.Info("SendRequest: IV = " + BitConverter.ToString(ctx.Sender.GetIV(ctx.Sender.PartialIV).GetByteString()));
                    _Log.Info("SendRequest: Key = " + BitConverter.ToString(ctx.Sender.Key));
                }

                enc.Encrypt(ctx.Sender.Key);

                if (ctx.Sender.SigningKey != null)
                {
                    CounterSignature sig = new CounterSignature(ctx.Sender.SigningKey);
                    sig.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.SigningKey[CoseKeyKeys.Algorithm], Attributes.DO_NOT_SEND);
                    sig.SetObject(enc);
                    CBORObject aad2 = ctx.Sender.SigningKey[CoseKeyKeys.Algorithm];
                    sig.SetExternalData(aad2.EncodeToBytes());
                    CBORObject signatureBytes = sig.EncodeToCBORObject();
                    enc.AddAttribute(HeaderKeys.CounterSignature, signatureBytes, Attributes.DO_NOT_SEND);
                }

                byte[] optionValue = DoCompression(enc);

                OscoapOption o = new OscoapOption();
                o.Set(optionValue);
                request.AddOption(o);
                request.Payload = enc.GetEncryptedContent();

                if (request.HasOption(OptionType.Observe))
                {
                    request.Method = Method.FETCH;
                }
                else
                {
                    request.Method = Method.POST;
                }
            }
            base.SendRequest(nextLayer, exchange, request);
        }
Exemple #30
0
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (response.HasOption(OptionType.Oscoap))
            {
                Option op = response.GetFirstOption(OptionType.Oscoap);

                if (exchange.OscoapContext == null)
                {
                    return;
                }

                SecurityContext ctx = exchange.OscoapContext;

                bool fServerIv = true;

                Encrypt0Message msg = Uncompress(op.RawValue);
                if (msg == null)
                {
                    return;
                }
                msg.SetEncryptedContent(response.Payload);

                SecurityContext.EntityContext recip = ctx.Recipient;
                if (recip == null)
                {
                    if (ctx.GroupId == null)
                    {
                        //  This is not currently a valid state to be in
                        return;
                    }
                    CBORObject kid = msg.FindAttribute(HeaderKeys.KeyId);
                    if (kid == null)
                    {
                        //  this is not currently a valid state to be in
                        return;
                    }
                    recip = ctx.Recipients[kid.GetByteString()];
                    if (recip == null)
                    {
                        // M00TODO - deal with asking the user for a recipient structure at this point.
                        return;
                    }
                }

                if (msg.FindAttribute(HeaderKeys.PartialIV) == null)
                {
                    msg.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND);
                    fServerIv = false;
                }


                byte[] partialIV  = msg.FindAttribute(HeaderKeys.PartialIV).GetByteString();
                byte[] seqNoArray = new byte[8];
                Array.Copy(partialIV, 0, seqNoArray, 8 - partialIV.Length, partialIV.Length);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(seqNoArray);
                }
                Int64 seqNo = BitConverter.ToInt64(seqNoArray, 0);

                if (fServerIv)
                {
                    if (_replayWindow && recip.ReplayWindow.HitTest(seqNo))
                    {
                        return;
                    }
                }

                msg.AddAttribute(HeaderKeys.Algorithm, recip.Algorithm, Attributes.DO_NOT_SEND);

                CBORObject fullIV;
                if (fServerIv)
                {
                    fullIV = recip.GetIV(partialIV);
                }
                else
                {
                    fullIV = ctx.Sender.GetIV(partialIV);
                }
                msg.AddAttribute(HeaderKeys.IV, fullIV, Attributes.DO_NOT_SEND);

                //  build aad
                CBORObject aad = CBORObject.NewArray();
                aad.Add(1);
                aad.Add(CBORObject.NewArray());
                aad[1].Add(recip.Algorithm);
                aad.Add(ctx.Sender.Id);
                aad.Add(ctx.Sender.PartialIV);
                aad.Add(CBORObject.FromObject(new byte[0])); // OPTIONS
                if (ctx.GroupId != null)
                {
                    aad.Add(ctx.GroupId);
                }

                msg.SetExternalData(aad.EncodeToBytes());

                _Log.Info(m => m($"fServerIv = {fServerIv}"));
                _Log.Info(m => m("ReceiveResponse: AAD = " + BitConverter.ToString(aad.EncodeToBytes())));
                _Log.Info(m => m($"ReceiveResponse: IV = {BitConverter.ToString(fullIV.GetByteString())}"));
                _Log.Info(m => m($"ReceiveResponse: Key = {BitConverter.ToString(recip.Key)}"));

                byte[] payload = msg.Decrypt(recip.Key);

                recip.ReplayWindow.SetHit(seqNo);

                byte[] rgb = new byte[payload.Length + _FixedHeader.Length - 1];
                Array.Copy(_FixedHeader, rgb, _FixedHeader.Length);
                Array.Copy(payload, 1, rgb, _FixedHeader.Length, payload.Length - 1);
                rgb[1] = payload[0];
                Codec.IMessageDecoder me = Spec.NewMessageDecoder(rgb);
                Response decryptedReq    = me.DecodeResponse();

                response.Payload    = decryptedReq.Payload;
                response.StatusCode = decryptedReq.StatusCode;

                RestoreOptions(response, decryptedReq);
            }
            base.ReceiveResponse(nextLayer, exchange, response);
        }
Exemple #31
0
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (exchange.OscoapContext != null)
            {
                SecurityContext ctx = exchange.OscoapContext;

                Codec.IMessageEncoder me   = Spec.NewMessageEncoder();
                Response encryptedResponse = new Response((StatusCode)response.Code);

                if (response.Payload != null)
                {
                    encryptedResponse.Payload = response.Payload;
                }

                MoveResponseHeaders(response, encryptedResponse);

                if (_Log.IsInfoEnabled)
                {
                    _Log.Info("SendResponse: New inner response message");
                    _Log.Info(encryptedResponse.ToString());
                }

                //  Build AAD
                CBORObject aad = CBORObject.NewArray();
                aad.Add(1);
                aad.Add(CBORObject.NewArray());
                aad[1].Add(ctx.Sender.Algorithm);
                aad.Add(exchange.OscoapSenderId);
                aad.Add(exchange.OscoapSequenceNumber);
                aad.Add(CBORObject.FromObject(new byte[0])); // Options
                if (ctx.GroupId != null)
                {
                    aad.Add(ctx.GroupId);
                }

                if (_Log.IsInfoEnabled)
                {
                    _Log.Info("SendResponse: AAD = " + BitConverter.ToString(aad.EncodeToBytes()));
                }

                Encrypt0Message enc       = new Encrypt0Message(false);
                byte[]          msg       = me.Encode(encryptedResponse);
                int             tokenSize = msg[0] & 0xf;
                byte[]          msg2      = new byte[msg.Length - (3 + tokenSize)];
                Array.Copy(msg, 4 + tokenSize, msg2, 1, msg2.Length - 1);
                msg2[0] = msg[1];
                enc.SetContent(msg2);
                enc.SetExternalData(aad.EncodeToBytes());

                if (response.HasOption(OptionType.Observe) || ctx.GroupId != null)
                {
                    enc.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), Attributes.UNPROTECTED);
                    enc.AddAttribute(HeaderKeys.IV, ctx.Sender.GetIV(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND);
                    ctx.Sender.IncrementSequenceNumber();
                    if (ctx.GroupId != null)
                    {
                        enc.AddAttribute(HeaderKeys.KeyId, CBORObject.FromObject(ctx.Sender.Id), Attributes.UNPROTECTED);
                    }
                }
                else
                {
                    CBORObject iv = ctx.Recipient.GetIV(exchange.OscoapSequenceNumber);

                    enc.AddAttribute(HeaderKeys.IV, iv, Attributes.DO_NOT_SEND);
                }

                _Log.Info(m => m($"SendResponse: IV = {BitConverter.ToString(enc.FindAttribute(HeaderKeys.IV, Attributes.DO_NOT_SEND).GetByteString())}"));
                _Log.Info(m => m($"SendResponse: Key = {BitConverter.ToString(ctx.Sender.Key)}"));

                enc.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.Algorithm, Attributes.DO_NOT_SEND);
                enc.Encrypt(ctx.Sender.Key);

                byte[] finalBody = DoCompression(enc);

                OscoapOption o = new OscoapOption(OptionType.Oscoap);
                o.Set(finalBody);
                response.AddOption(o);
                response.StatusCode = StatusCode.Content;
                response.Payload    = enc.GetEncryptedContent();

                //  Need to be able to retrieve this again undersome cirumstances.

                if (encryptedResponse.HasOption(OptionType.Block2))
                {
                    Request         request = exchange.CurrentRequest;
                    Exchange.KeyUri keyUri  = new Exchange.KeyUri(request.URI, null, response.Destination);

                    //  Observe notification only send the first block, hence do not store them as ongoing
                    if (exchange.OSCOAP_ResponseBlockStatus != null && !encryptedResponse.HasOption(OptionType.Observe))
                    {
                        //  Remember ongoing blockwise GET requests
                        BlockHolder blockInfo = new BlockHolder(exchange);
                        if (Util.Utils.Put(_ongoingExchanges, keyUri, blockInfo) == null)
                        {
                            if (_Log.IsInfoEnabled)
                            {
                                _Log.Info("Ongoing Block2 started late, storing " + keyUri + " for " + request);
                            }
                        }
                        else
                        {
                            if (_Log.IsInfoEnabled)
                            {
                                _Log.Info("Ongoing Block2 continued, storing " + keyUri + " for " + request);
                            }
                        }
                    }
                    else
                    {
                        if (_Log.IsInfoEnabled)
                        {
                            _Log.Info("Ongoing Block2 completed, cleaning up " + keyUri + " for " + request);
                        }
                        BlockHolder exc;
                        _ongoingExchanges.TryRemove(keyUri, out exc);
                    }
                }
            }

            base.SendResponse(nextLayer, exchange, response);
        }
Exemple #32
0
 /// <inheritdoc/>
 public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
 {
     if (response.Token == null)
         throw new InvalidOperationException("Received response's token cannot be null, use byte[0] for empty tokens");
     base.ReceiveResponse(nextLayer, exchange, response);
 }
Exemple #33
0
 /// <inheritdoc/>
 public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     if (exchange.CurrentRequest.Token == null)
         throw new InvalidOperationException("Received requests's token cannot be null, use byte[0] for empty tokens");
     base.ReceiveRequest(nextLayer, exchange, request);
 }
Exemple #34
0
        /// <summary>
        /// If we receive an ACK or RST, we mark the outgoing request or response
        /// as acknowledged or rejected respectively and cancel its retransmission.
        /// </summary>
        public override void ReceiveEmptyMessage(INextLayer nextLayer, Exchange exchange, EmptyMessage message)
        {
            switch (message.Type)
            {
                case MessageType.ACK:
                    if (exchange.Origin == Origin.Local)
                        exchange.CurrentRequest.IsAcknowledged = true;
                    else
                        exchange.CurrentResponse.IsAcknowledged = true;
                    break;
                case MessageType.RST:
                    if (exchange.Origin == Origin.Local)
                        exchange.CurrentRequest.IsRejected = true;
                    else
                        exchange.CurrentResponse.IsRejected = true;
                    break;
                default:
                    if (log.IsWarnEnabled)
                        log.Warn("Empty messgae was not ACK nor RST: " + message);
                    break;
            }

            TransmissionContext ctx = (TransmissionContext)exchange.Remove(TransmissionContextKey);
            if (ctx != null)
                ctx.Cancel();

            base.ReceiveEmptyMessage(nextLayer, exchange, message);
        }
Exemple #35
0
 /// <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);
 }
Exemple #36
0
        /// <inheritdoc/>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            BlockOption block1 = exchange.Block1ToAck;
            if (block1 != null)
                exchange.Block1ToAck = null;

            if (RequiresBlockwise(exchange, response))
            {
                // This must be a large response to a GET or POST request (PUT?)
                if (log.IsDebugEnabled)
                    log.Debug("Response payload " + response.PayloadSize + "/" + _maxMessageSize + " requires Blockwise");

                BlockwiseStatus status = FindResponseBlockStatus(exchange, response);

                Response block = GetNextResponseBlock(response, status);
                block.Type = response.Type; // This is only true for the first block
                if (block1 != null) // in case we still have to ack the last block1
                    block.SetOption(block1);
                if (block.Token == null)
                    block.Token = exchange.Request.Token;

                if (response.HasOption(OptionType.Observe))
                {
                    // the ACK for the first block should acknowledge the whole notification
                    exchange.CurrentResponse = response;
                }
                else
                {
                    exchange.CurrentResponse = block;
                }
                base.SendResponse(nextLayer, exchange, block);

            }
            else
            {
                if (block1 != null)
                    response.SetOption(block1);
                exchange.CurrentResponse = response;
                base.SendResponse(nextLayer, exchange, response);
            }
        }
Exemple #37
0
        /// <summary>
        /// When we receive a duplicate of a request, we stop it here and do not
	    /// forward it to the upper layer. If the server has already sent a response,
	    /// we send it again. If the request has only been acknowledged (but the ACK
	    /// has gone lost or not reached the client yet), we resent the ACK. If the
        /// request has neither been responded, acknowledged or rejected yet, the
	    /// server has not yet decided what to do with the request and we cannot do
	    /// anything.
        /// </summary>
        public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if (request.Duplicate)
            {
                // Request is a duplicate, so resend ACK, RST or response
                if (exchange.CurrentResponse != null)
                {
                    if (log.IsDebugEnabled)
                        log.Debug("Respond with the current response to the duplicate request");
                    base.SendResponse(nextLayer, exchange, exchange.CurrentResponse);
                }
                else if (exchange.CurrentRequest != null)
                {
                    if (exchange.CurrentRequest.IsAcknowledged)
                    {
                        if (log.IsDebugEnabled)
                            log.Debug("The duplicate request was acknowledged but no response computed yet. Retransmit ACK.");
                        EmptyMessage ack = EmptyMessage.NewACK(request);
                        SendEmptyMessage(nextLayer, exchange, ack);
                    }
                    else if (exchange.CurrentRequest.IsRejected)
                    {
                        if (log.IsDebugEnabled)
                            log.Debug("The duplicate request was rejected. Reject again.");
                        EmptyMessage rst = EmptyMessage.NewRST(request);
                        SendEmptyMessage(nextLayer, exchange, rst);
                    }
                    else
                    {
                        if (log.IsDebugEnabled)
                            log.Debug("The server has not yet decided what to do with the request. We ignore the duplicate.");
                        // The server has not yet decided, whether to acknowledge or
                        // reject the request. We know for sure that the server has
                        // received the request though and can drop this duplicate here.
                    }
                }
                else
                {
                    // Lost the current request. The server has not yet decided what to do.
                }
            }
            else
            {
                // Request is not a duplicate
                exchange.CurrentRequest = request;
                base.ReceiveRequest(nextLayer, exchange, request);
            }
        }
Exemple #38
0
        /// <summary>
        /// When we receive a Confirmable response, we acknowledge it and it also
	    /// counts as acknowledgment for the request. If the response is a duplicate,
        /// we stop it here and do not forward it to the upper layer.
        /// </summary>
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            TransmissionContext ctx = (TransmissionContext)exchange.Remove(TransmissionContextKey);
            if (ctx != null)
            {
                exchange.CurrentRequest.IsAcknowledged = true;
                ctx.Cancel();
            }

            if (response.Type == MessageType.CON && !exchange.Request.IsCancelled)
            {
                if (log.IsDebugEnabled)
                    log.Debug("Response is confirmable, send ACK.");
                EmptyMessage ack = EmptyMessage.NewACK(response);
                SendEmptyMessage(nextLayer, exchange, ack);
            }

            if (response.Duplicate)
            {
                if (log.IsDebugEnabled)
                    log.Debug("Response is duplicate, ignore it.");
            }
            else
            {
                base.ReceiveResponse(nextLayer, exchange, response);
            }
        }
Exemple #39
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);
        }
Exemple #40
0
        /// <inheritdoc/>
        public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if (request.HasOption(OptionType.Block1))
            {
                // This must be a large POST or PUT request
                BlockOption block1 = request.Block1;
                if (log.IsDebugEnabled)
                    log.Debug("Request contains block1 option " + block1);

                BlockwiseStatus status = FindRequestBlockStatus(exchange, request);
                if (block1.NUM == 0 && status.CurrentNUM > 0)
                {
                    // reset the blockwise transfer
                    if (log.IsDebugEnabled)
                        log.Debug("Block1 num is 0, the client has restarted the blockwise transfer. Reset status.");
                    status = new BlockwiseStatus(request.ContentType);
                    exchange.RequestBlockStatus = status;
                }

                if (block1.NUM == status.CurrentNUM)
                {
                    if (request.ContentType == status.ContentFormat)
                    {
                        status.AddBlock(request.Payload);
                    }
                    else
                    {
                        Response error = Response.CreatePiggybackedResponse(request, StatusCode.RequestEntityIncomplete);
                        error.AddOption(new BlockOption(OptionType.Block1, block1.NUM, block1.SZX, block1.M));
                        error.SetPayload("Changed Content-Format");
                        request.IsAcknowledged = true;
                        exchange.CurrentResponse = error;
                        base.SendResponse(nextLayer, exchange, error);
                        return;
                    }

                    status.CurrentNUM = status.CurrentNUM + 1;
                    if (block1.M)
                    {
                        if (log.IsDebugEnabled)
                            log.Debug("There are more blocks to come. Acknowledge this block.");

                        if (request.Type == MessageType.CON)
                        {
                            Response piggybacked = Response.CreatePiggybackedResponse(request, StatusCode.Continue);
                            piggybacked.AddOption(new BlockOption(OptionType.Block1, block1.NUM, block1.SZX, true));
                            piggybacked.Last = false;
                            request.IsAcknowledged = true;
                            exchange.CurrentResponse = piggybacked;
                            base.SendResponse(nextLayer, exchange, piggybacked);
                        }
                        // do not assemble and deliver the request yet
                    }
                    else
                    {
                        if (log.IsDebugEnabled)
                            log.Debug("This was the last block. Deliver request");

                        // Remember block to acknowledge. TODO: We might make this a boolean flag in status.
                        exchange.Block1ToAck = block1;

                        // Block2 early negotiation
                        EarlyBlock2Negotiation(exchange, request);

                        // Assemble and deliver
                        Request assembled = new Request(request.Method); // getAssembledRequest(status, request);
                        AssembleMessage(status, assembled, request);
                        // assembled.setAcknowledged(true); // TODO: prevents accept from sending ACK. Maybe the resource uses separate...
                        exchange.Request = assembled;
                        base.ReceiveRequest(nextLayer, exchange, assembled);
                    }
                }
                else
                {
                    // ERROR, wrong number, Incomplete
                    if (log.IsWarnEnabled)
                        log.Warn("Wrong block number. Expected " + status.CurrentNUM + " but received " + block1.NUM + ". Respond with 4.08 (Request Entity Incomplete).");
                    Response error = Response.CreatePiggybackedResponse(request, StatusCode.RequestEntityIncomplete);
                    error.AddOption(new BlockOption(OptionType.Block1, block1.NUM, block1.SZX, block1.M));
                    error.SetPayload("Wrong block number");
                    request.IsAcknowledged = true;
                    exchange.CurrentResponse = error;
                    base.SendResponse(nextLayer, exchange, error);
                }
            }
            else if (exchange.Response != null && request.HasOption(OptionType.Block2))
            {
                // The response has already been generated and the client just wants
                // the next block of it
                BlockOption block2 = request.Block2;
                Response response = exchange.Response;
                BlockwiseStatus status = FindResponseBlockStatus(exchange, response);
                status.CurrentNUM = block2.NUM;
                status.CurrentSZX = block2.SZX;

                Response block = GetNextResponseBlock(response, status);
                block.Token = request.Token;
                block.RemoveOptions(OptionType.Observe);

                if (status.Complete)
                {
                    // clean up blockwise status
                    if (log.IsDebugEnabled)
                        log.Debug("Ongoing is complete " + status);
                    exchange.ResponseBlockStatus = null;
                }
                else
                {
                    if (log.IsDebugEnabled)
                        log.Debug("Ongoing is continuing " + status);
                }

                exchange.CurrentResponse = block;
                base.SendResponse(nextLayer, exchange, block);

            }
            else
            {
                EarlyBlock2Negotiation(exchange, request);

                exchange.Request = request;
                base.ReceiveRequest(nextLayer, exchange, request);
            }
        }
Exemple #41
0
 /// <inheritdoc/>
 public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
 {
     if (response.HasOption(OptionType.Observe))
     {
         if (exchange.Request.IsCancelled)
         {
             // The request was canceled and we no longer want notifications
             if (log.IsDebugEnabled)
                 log.Debug("ObserveLayer rejecting notification for canceled Exchange");
             EmptyMessage rst = EmptyMessage.NewRST(response);
             SendEmptyMessage(nextLayer, exchange, rst);
             // Matcher sets exchange as complete when RST is sent
         }
         else
         {
             PrepareReregistration(exchange, response, msg => SendRequest(nextLayer, exchange, msg));
             base.ReceiveResponse(nextLayer, exchange, response);
         }
     }
     else
     {
         // No observe option in response => always deliver
         base.ReceiveResponse(nextLayer, exchange, response);
     }
 }
Exemple #42
0
 /// <inheritdoc/>
 public override void SendRequest(INextLayer nextLayer, Exchange exchange, Request request)
 {
     if (request.Token == null)
         request.Token = NewToken();
     base.SendRequest(nextLayer, exchange, request);
 }
Exemple #43
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);
        }
Exemple #44
0
        /// <inheritdoc/>
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (!response.HasOption(OptionType.Block1) && !response.HasOption(OptionType.Block2))
            {
                // There is no block1 or block2 option, therefore it is a normal response
                exchange.Response = response;
                base.ReceiveResponse(nextLayer, exchange, response);
                return;
            }

            BlockOption block1 = response.Block1;
            if (block1 != null)
            {
                // TODO: What if request has not been sent blockwise (server error)
                if (log.IsDebugEnabled)
                    log.Debug("Response acknowledges block " + block1);

                BlockwiseStatus status = exchange.RequestBlockStatus;
                if (!status.Complete)
                {
                    // TODO: the response code should be CONTINUE. Otherwise deliver
                    // Send next block
                    Int32 currentSize = 1 << (4 + status.CurrentSZX);
                    Int32 nextNum = status.CurrentNUM + currentSize / block1.Size;
                    if (log.IsDebugEnabled)
                        log.Debug("Send next block num = " + nextNum);
                    status.CurrentNUM = nextNum;
                    status.CurrentSZX = block1.SZX;
                    Request nextBlock = GetNextRequestBlock(exchange.Request, status);
                    if (nextBlock.Token == null)
                        nextBlock.Token = response.Token; // reuse same token
                    exchange.CurrentRequest = nextBlock;
                    base.SendRequest(nextLayer, exchange, nextBlock);
                    // do not deliver response
                }
                else if (!response.HasOption(OptionType.Block2))
                {
                    // All request block have been acknowledged and we receive a piggy-backed
                    // response that needs no blockwise transfer. Thus, deliver it.
                    base.ReceiveResponse(nextLayer, exchange, response);
                }
                else
                {
                    if (log.IsDebugEnabled)
                        log.Debug("Response has Block2 option and is therefore sent blockwise");
                }
            }

            BlockOption block2 = response.Block2;
            if (block2 != null)
            {
                BlockwiseStatus status = FindResponseBlockStatus(exchange, response);

                if (block2.NUM == status.CurrentNUM)
                {
                    // We got the block we expected :-)
                    status.AddBlock(response.Payload);
                    Int32? obs = response.Observe;
                    if (obs.HasValue)
                        status.Observe = obs.Value;

                    // notify blocking progress
                    exchange.Request.FireResponding(response);

                    if (status.IsRandomAccess)
                    {
                        // The client has requested this specifc block and we deliver it
                        exchange.Response = response;
                        base.ReceiveResponse(nextLayer, exchange, response);
                    }
                    else if (block2.M)
                    {
                        if (log.IsDebugEnabled)
                            log.Debug("Request the next response block");
                        // TODO: If this is a notification, do we have to use
                        // another token now?

                        Request request = exchange.Request;
                        Int32 num = block2.NUM + 1;
                        Int32 szx = block2.SZX;
                        Boolean m = false;
                        Request block = new Request(request.Method);
                        block.Token = response.Token;
                        block.SetOptions(request.GetOptions());
                        block.Destination = request.Destination;

                        block.Type = request.Type; // NON could make sense over SMS or similar transports
                        block.SetOption(new BlockOption(OptionType.Block2, num, szx, m));
                        status.CurrentNUM = num;

                        // to make it easier for Observe, we do not re-use the Token
                        //if (!response.HasOption(OptionType.Observe))
                        //{
                        //    block.Token = request.Token;
                        //}

                        // make sure not to use Observe for block retrieval
                        block.RemoveOptions(OptionType.Observe);

                        exchange.CurrentRequest = block;
                        base.SendRequest(nextLayer, exchange, block);
                    }
                    else
                    {
                        if (log.IsDebugEnabled)
                            log.Debug("We have received all " + status.BlockCount + " blocks of the response. Assemble and deliver.");
                        Response assembled = new Response(response.StatusCode);
                        AssembleMessage(status, assembled, response);
                        assembled.Type = response.Type;

                        // set overall transfer RTT
                        assembled.RTT = (DateTime.Now - exchange.Timestamp).TotalMilliseconds;

                        // Check if this response is a notification
                        Int32 observe = status.Observe;
                        if (observe != BlockwiseStatus.NoObserve)
                        {
                            assembled.AddOption(Option.Create(OptionType.Observe, observe));
                            // This is necessary for notifications that are sent blockwise:
                            // Reset block number AND container with all blocks
                            exchange.ResponseBlockStatus = null;
                        }

                        if (log.IsDebugEnabled)
                            log.Debug("Assembled response: " + assembled);
                        exchange.Response = assembled;
                        base.ReceiveResponse(nextLayer, exchange, assembled);
                    }

                }
                else
                {
                    // ERROR, wrong block number (server error)
                    // TODO: This scenario is not specified in the draft.
                    // Currently, we reject it and cancel the request.
                    if (log.IsWarnEnabled)
                        log.Warn("Wrong block number. Expected " + status.CurrentNUM + " but received " + block2.NUM + ". Reject response; exchange has failed.");
                    if (response.Type == MessageType.CON)
                    {
                        EmptyMessage rst = EmptyMessage.NewRST(response);
                        base.SendEmptyMessage(nextLayer, exchange, rst);
                    }
                    exchange.Request.IsCancelled = true;
                }
            }
        }
Exemple #45
0
        /// <inheritdoc/>
        public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if (request.HasOption(OptionType.Block1))
            {
                //  If this is a multicast address we are receiving this on, then we should ignore it
                if (request.IsMulticast)
                {
                    return;
                }

                // This must be a large POST or PUT request
                BlockOption block1 = request.Block1;
                log.Debug(m => m("Request contains block1 option {0}", block1));

                BlockwiseStatus status = FindRequestBlockStatus(exchange, request);
                if (block1.NUM == 0 && status.CurrentNUM > 0)
                {
                    // reset the blockwise transfer
                    log.Debug("Block1 num is 0, the client has restarted the blockwise transfer. Reset status.");
                    status = new BlockwiseStatus(request.ContentType);
                    exchange.RequestBlockStatus = status;
                }

                if (block1.NUM == status.CurrentNUM)
                {
                    if (request.ContentType == status.ContentFormat)
                    {
                        status.AddBlock(request.Payload);
                    }
                    else
                    {
                        Response error = Response.CreateResponse(request, StatusCode.RequestEntityIncomplete);
                        error.AddOption(new BlockOption(OptionType.Block1, block1.NUM, block1.SZX, block1.M));
                        error.SetPayload("Changed Content-Format");

                        exchange.CurrentResponse = error;
                        base.SendResponse(nextLayer, exchange, error);
                        return;
                    }

                    status.CurrentNUM += 1;
                    if (block1.M)
                    {
                        log.Debug("There are more blocks to come. Acknowledge this block.");

                        Response piggybacked = Response.CreateResponse(request, StatusCode.Continue);
                        piggybacked.AddOption(new BlockOption(OptionType.Block1, block1.NUM, block1.SZX, true));
                        piggybacked.Last = false;

                        exchange.CurrentResponse = piggybacked;
                        base.SendResponse(nextLayer, exchange, piggybacked);

                        // do not assemble and deliver the request yet
                    }
                    else
                    {
                        log.Debug("This was the last block. Deliver request");

                        // Remember block to acknowledge. TODO: We might make this a boolean flag in status.
                        exchange.Block1ToAck = block1;

                        // Block2 early negotiation
                        EarlyBlock2Negotiation(exchange, request);

                        // Assemble and deliver
                        Request assembled = new Request(request.Method);
                        AssembleMessage(status, assembled, request);

                        assembled.Session       = request.Session;
                        exchange.Request        = assembled;
                        exchange.CurrentRequest = assembled;
                        base.ReceiveRequest(nextLayer, exchange, assembled);
                    }
                }
                else
                {
                    // ERROR, wrong number, Incomplete
                    log.Warn(m => m("Wrong block number. Expected {0} but received {1}. Respond with 4.08 (Request Entity Incomplete).",
                                    status.CurrentNUM, block1.NUM));
                    Response error = Response.CreateResponse(request, StatusCode.RequestEntityIncomplete);
                    error.AddOption(new BlockOption(OptionType.Block1, block1.NUM, block1.SZX, block1.M));
                    error.SetPayload("Wrong block number");
                    exchange.CurrentResponse = error;
                    base.SendResponse(nextLayer, exchange, error);
                }
            }
            else if (exchange.Response != null && request.HasOption(OptionType.Block2))
            {
                // The response has already been generated and the client just wants
                // the next block of it
                BlockOption     block2   = request.Block2;
                Response        response = exchange.Response;
                BlockwiseStatus status   = FindResponseBlockStatus(exchange, response);
                status.CurrentNUM = block2.NUM;
                status.CurrentSZX = block2.SZX;

                Response block = GetNextResponseBlock(response, status);
                block.Token = request.Token;
                block.RemoveOptions(OptionType.Observe);

                if (status.Complete)
                {
                    // clean up blockwise status
                    log.Debug(m => m("Ongoing is complete {0}", status));
                    exchange.ResponseBlockStatus = null;
                    ClearBlockCleanup(exchange);
                }
                else
                {
                    log.Debug(m => m("Ongoing is continuing {0}", status));
                }

                exchange.CurrentResponse = block;
                base.SendResponse(nextLayer, exchange, block);
            }
            else
            {
                EarlyBlock2Negotiation(exchange, request);

                exchange.Request = request;
                base.ReceiveRequest(nextLayer, exchange, request);
            }
        }
Exemple #46
0
        /// <inheritdoc/>
        public override void SendResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            BlockOption block1 = exchange.Block1ToAck;
            if (block1 != null)
                exchange.Block1ToAck = null;

            if (RequiresBlockwise(exchange, response))
            {
                if (log.IsDebugEnabled)
                    log.Debug("Response payload " + response.PayloadSize + "/" + _maxMessageSize + " requires Blockwise");

                BlockwiseStatus status = FindResponseBlockStatus(exchange, response);

                Response block = GetNextResponseBlock(response, status);
                
                if (block1 != null) // in case we still have to ack the last block1
                    block.SetOption(block1);
                if (block.Token == null)
                    block.Token = exchange.Request.Token;

                if (status.Complete)
                {
                    // clean up blockwise status
                    if (log.IsDebugEnabled)
                        log.Debug("Ongoing finished on first block " + status);
                    exchange.ResponseBlockStatus = null;
                    ClearBlockCleanup(exchange);
                }
                else
                {
                    if (log.IsDebugEnabled)
                        log.Debug("Ongoing started " + status);
                }

                exchange.CurrentResponse = block;
                base.SendResponse(nextLayer, exchange, block);
            }
            else
            {
                if (block1 != null)
                    response.SetOption(block1);
                exchange.CurrentResponse = response;
                // Block1 transfer completed
                ClearBlockCleanup(exchange);
                base.SendResponse(nextLayer, exchange, response);
            }
        }
Exemple #47
0
        /// <inheritdoc/>
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            // do not continue fetching blocks if canceled
            if (exchange.Request.IsCancelled)
            {
                // reject (in particular for Block+Observe)
                if (response.Type != MessageType.ACK)
                {
                    log.Debug("Rejecting blockwise transfer for canceled Exchange");
                    EmptyMessage rst = EmptyMessage.NewRST(response);
                    SendEmptyMessage(nextLayer, exchange, rst);
                    // Matcher sets exchange as complete when RST is sent
                }
                return;
            }

            if (!response.HasOption(OptionType.Block1) && !response.HasOption(OptionType.Block2))
            {
                // There is no block1 or block2 option, therefore it is a normal response
                exchange.Response = response;
                base.ReceiveResponse(nextLayer, exchange, response);
                return;
            }

            BlockOption block1 = response.Block1;

            if (block1 != null)
            {
                // TODO: What if request has not been sent blockwise (server error)
                log.Debug(m => m("Response acknowledges block " + block1));
                BlockwiseStatus status = exchange.RequestBlockStatus;

                if (exchange.Request.Session == null)
                {
                    exchange.Request.Session = exchange.CurrentRequest.Session;
                    if (exchange.Request.Session.IsReliable && exchange.Request.Session.MaxSendSize >= 1024)
                    {
                        status.CurrentSZX = 6;
                    }
                }

                if (!status.Complete)
                {
                    // TODO: the response code should be CONTINUE. Otherwise deliver
                    // Send next block
                    int currentSize = 1 << (4 + status.CurrentSZX);
                    int nextNum     = status.CurrentNUM + currentSize / block1.Size;
                    log.Debug(m => m("Send next block num = " + nextNum));
                    status.CurrentNUM = nextNum;
                    status.CurrentSZX = block1.SZX;
                    Request nextBlock = GetNextRequestBlock(exchange.Request, status);
                    if (exchange.Request.IsMulticast)
                    {
                        //  Multicast jumps to the Unicast address
                        exchange.Request.Destination = response.Source;
                    }
                    if (nextBlock.Token == null)
                    {
                        nextBlock.Token = response.Token; // reuse same token
                    }

                    nextBlock.RemoveOptions(OptionType.Observe);

                    exchange.CurrentRequest = nextBlock;
                    base.SendRequest(nextLayer, exchange, nextBlock);
                    // do not deliver response
                }
                else if (!response.HasOption(OptionType.Block2))
                {
                    // All request block have been acknowledged and we receive a piggy-backed
                    // response that needs no blockwise transfer. Thus, deliver it.
                    base.ReceiveResponse(nextLayer, exchange, response);
                }
                else
                {
                    log.Debug("Response has Block2 option and is therefore sent blockwise");
                }
            }

            BlockOption block2 = response.Block2;

            if (block2 != null)
            {
                BlockwiseStatus status = FindResponseBlockStatus(exchange, response);

                if (block2.NUM == status.CurrentNUM)
                {
                    // We got the block we expected :-)
                    int?obs = response.Observe;
                    if (obs.HasValue)
                    {
                        status.Observe = obs.Value;
                    }

                    //  Is the block sized as we expect it
                    int blockCount = 1;
                    int blockSize  = 1 << (block2.SZX + 4);

                    if (response.Payload != null)
                    {
                        if (block2.SZX == 7)
                        {
                            blockSize  = 1024;
                            blockCount = (response.Payload.Length + 1023) / 1024;
                        }

                        if (response.Payload.Length != blockSize * blockCount)
                        {
                            if (!block2.M)
                            {
                                if ((blockCount - 1) * blockSize >= response.Payload.Length ||
                                    response.Payload.Length >= blockSize * blockCount)
                                {
                                    //  This is problem as the body size is wrong.
                                    return;
                                }
                            }
                            else
                            {
                                //  The body size is wrong
                                return;
                            }
                        }
                    }

                    status.AddBlock(response.Payload);

                    // notify blocking progress
                    exchange.Request.FireResponding(response);

                    if (status.IsRandomAccess)
                    {
                        // The client has requested this specific block and we deliver it
                        exchange.Response = response;
                        base.ReceiveResponse(nextLayer, exchange, response);
                    }
                    else if (block2.M)
                    {
                        log.Debug("Request the next response block");
                        exchange.Complete = true;
                        exchange.Complete = false;

                        Request request = exchange.Request;
                        int     num     = block2.NUM + blockCount;
                        int     szx     = block2.SZX;
                        bool    m       = false;

                        Request block = new Request(request.Method)
                        {
                            Type        = request.Type,
                            Destination = request.IsMulticast ? response.Source : request.Destination,
                            Session     = request.Session
                        };
                        // NON could make sense over SMS or similar transports
                        block.SetOptions(request.GetOptions());
                        block.SetOption(new BlockOption(OptionType.Block2, num, szx, m));
                        // we use the same token to ease traceability (GET without Observe no longer cancels relations)
                        // block.Token = response.Token;
                        // make sure not to use Observe for block retrieval
                        block.RemoveOptions(OptionType.Observe);

                        status.CurrentNUM = num;

                        exchange.CurrentRequest = block;
                        base.SendRequest(nextLayer, exchange, block);
                    }
                    else
                    {
                        log.Debug(m => m("We have received all {0} blocks of the response. Assemble and deliver.",
                                         status.BlockCount));
                        Response assembled = new Response(response.StatusCode);
                        AssembleMessage(status, assembled, response);
                        assembled.Type = response.Type;

                        // set overall transfer RTT
                        assembled.RTT = (DateTime.Now - exchange.Timestamp).TotalMilliseconds;

                        // Check if this response is a notification
                        int observe = status.Observe;
                        if (observe != BlockwiseStatus.NoObserve)
                        {
                            assembled.AddOption(Option.Create(OptionType.Observe, observe));
                            // This is necessary for notifications that are sent blockwise:
                            // Reset block number AND container with all blocks
                            exchange.ResponseBlockStatus = null;
                        }

                        log.Debug(m => m("Assembled response: {0}", assembled));
                        exchange.Response = assembled;
                        base.ReceiveResponse(nextLayer, exchange, assembled);
                    }
                }
                else
                {
                    // ERROR, wrong block number (server error)
                    // TODO: This scenario is not specified in the draft.
                    // Currently, we reject it and cancel the request.
                    log.Warn(m => m("Wrong block number. Expected {0} but received {1}" +
                                    ". Reject response; exchange has failed.", status.CurrentNUM, block2.NUM));
                    if (response.Type == MessageType.CON)
                    {
                        EmptyMessage rst = EmptyMessage.NewRST(response);
                        base.SendEmptyMessage(nextLayer, exchange, rst);
                    }
                    exchange.Request.IsCancelled = true;
                }
            }
        }
Exemple #48
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();
            };
        }