Exemple #1
0
        /// <inheritdoc/>
        public void SendRequest(Exchange exchange, Request request)
        {
            if (request.ID == Message.None)
            {
                request.ID = System.Threading.Interlocked.Increment(ref _currentID) % (1 << 16);
            }

            /*
             * The request is a CON or NON and must be prepared for these responses
             * - CON => ACK / RST / ACK+response / CON+response / NON+response
             * - NON => RST / CON+response / NON+response
             * If this request goes lost, we do not get anything back.
             */

            // the MID is from the local namespace -- use blank address
            Exchange.KeyID keyID = new Exchange.KeyID(request.ID, null, request.Session);

            //  If we do not have a token, then create one
            Exchange.KeyToken keyToken;
            if (request.Token == null)
            {
                int length = _tokenLength;
                if (_tokenLength < 0)
                {
                    length = _random.Next(8);
                }

                byte[] token = new byte[length];
                int    tries = 0;

                do
                {
                    if ((length < 8) && (tries > length * 5 + 1))
                    {
                        length += 1;
                        tries   = 0;
                        token   = new byte[length];
                    }

                    _random.NextBytes(token);
                    keyToken = new Exchange.KeyToken(token);
                } while (_exchangesByToken.ContainsKey(keyToken));

                request.Token = token;
            }
            else
            {
                keyToken = new Exchange.KeyToken(request.Token);
            }

            exchange.Completed += OnExchangeCompleted;


            _Log.Debug(m => m("Stored open request by {0}, {1}", keyID, keyToken));

            _exchangesByID[keyID]       = exchange;
            _exchangesByToken[keyToken] = exchange;
        }
Exemple #2
0
        private void OnExchangeCompleted(Object sender, EventArgs e)
        {
            Exchange exchange = (Exchange)sender;

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

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

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

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

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

                Request request = exchange.CurrentRequest;
                if (request != null && (request.HasOption(OptionType.Block1) || response.HasOption(OptionType.Block2)))
                {
                    Exchange.KeyUri uriKey = new Exchange.KeyUri(request, request.Source);

                    _Log.Debug(m => m($"Remote ongoing completed, cleaning up {uriKey}"));

                    Exchange exc;
                    _ongoingExchanges.TryRemove(uriKey, out exc);
                }

                // Remove all remaining NON-notifications if this exchange is an observe relation
                ObserveRelation relation = exchange.Relation;
                if (relation != null)
                {
                    RemoveNotificatoinsOf(relation);
                }
            }
        }
Exemple #3
0
        /// <inheritdoc/>
        public Exchange ReceiveResponse(Response response)
        {
            /*
             * This response could be
             * - The first CON/NON/ACK+response => deliver
             * - Retransmitted CON (because client got no ACK)
             *      => resend ACK
             */

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

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

            Exchange exchange;

            if (_exchangesByToken.TryGetValue(keyToken, out exchange))
            {
                //  We need to play games if this is multicast
                if (exchange.CurrentRequest.IsMulticast)
                {
                    Exchange newExchange = new Exchange(exchange);
                    newExchange.Request = exchange.Request;
                    exchange            = newExchange;
                }

                // There is an exchange with the given token
                Exchange prev = _deduplicator.FindPrevious(keyId, exchange);
                if (prev != null)
                {
                    // (and thus it holds: prev == exchange)
                    _Log.Info(m => m($"Duplicate response for open exchange: {response}"));
                    response.Duplicate = true;
                }
                else
                {
                    keyId = new Exchange.KeyID(exchange.CurrentRequest.ID, null, response.Session);
                    _Log.Debug(m => m($"Exchange got response: Cleaning up {keyId}"));
                    _exchangesByID.Remove(keyId);
                }

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

                return(exchange);
            }
            else
            {
                // There is no exchange with the given token.
                if (response.Type != MessageType.ACK)
                {
                    // only act upon separate responses
                    Exchange prev = _deduplicator.Find(keyId);
                    if (prev != null)
                    {
                        _Log.Info(m => m($"Duplicate response for completed exchange: {response}"));
                        response.Duplicate = true;
                        return(prev);
                    }
                }
                else
                {
                    _Log.Info(m => m($"Ignoring unmatchable piggy-backed response from {response.Source}: {response}"));
                }

                // ignore response
                return(null);
            }
        }
Exemple #4
0
        /// <inheritdoc/>
        public Exchange ReceiveResponse(Response response)
        {
            /*
             * This response could be
             * - The first CON/NON/ACK+response => deliver
             * - Retransmitted CON (because client got no ACK)
             *      => resend ACK
             */

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

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

            Exchange exchange;

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

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

                return(exchange);
            }
            else
            {
                // There is no exchange with the given token.
                if (response.Type != MessageType.ACK)
                {
                    // only act upon separate responses
                    Exchange prev = _deduplicator.Find(keyId);
                    if (prev != null)
                    {
                        if (_Log.IsInfoEnabled)
                        {
                            _Log.Info("Duplicate response for completed exchange: " + response);
                        }
                        response.Duplicate = true;
                        return(prev);
                    }
                }
                else
                {
                    if (_Log.IsInfoEnabled)
                    {
                        _Log.Info("Ignoring unmatchable piggy-backed response from " + response.Source + ": " + response);
                    }
                }
                // ignore response
                return(null);
            }
        }