/// <summary>
        /// Executes the AMQP network detach operation.
        /// </summary>
        /// <param name="timeout">
        /// Timeout to wait for for detach response. A timeout of 0 or less will not block to wait for a response.
        /// </param>
        /// <param name="cause">Error to detach link. Can be null.</param>
        /// <exception cref="Amqp.AmqpException">
        /// Throws when an error occur during amqp detach. Or contains Error response from detach.
        /// </exception>
        /// <exception cref="System.TimeoutException">
        /// Throws when detach response is not received in specified timeout.
        /// </exception>
        protected override void DoClose(TimeSpan timeout, Error cause = null)
        {
            if (IsDurable)
            {
                Task t = this.Link.DetachAsync(cause);
                if (TimeSpan.Compare(timeout, TimeSpan.Zero) > 0)
                {
                    /*
                     * AmqpNetLite does not allow a timeout to be specific for link detach request even though
                     * it uses the same close operation which takes a parameter for timeout. AmqpNetLite uses
                     * it default timeout of 60000ms, see AmqpObject.DefaultTimeout, for the detach close
                     * operation forcing the detach request to be synchronous. To allow for asynchronous detach
                     * request an NMS MessageConsumer must call the DetachAsync method on a link which will block
                     * for up to 60000ms asynchronously to set a timeout exception or complete the task.
                     */
                    const int amqpNetLiteDefaultTimeoutMillis = 60000; // taken from AmqpObject.DefaultTimeout
                    TimeSpan  amqpNetLiteDefaultTimeout       = TimeSpan.FromMilliseconds(amqpNetLiteDefaultTimeoutMillis);
                    // Create timeout which allows for the 60000ms block in the DetachAsync task.
                    TimeSpan actualTimeout = amqpNetLiteDefaultTimeout + timeout;

                    TaskUtil.Wait(t, actualTimeout);
                    if (t.Exception != null)
                    {
                        if (t.Exception is AggregateException)
                        {
                            throw t.Exception.InnerException;
                        }
                        else
                        {
                            throw t.Exception;
                        }
                    }
                }
            }
            else
            {
                base.DoClose(timeout, cause);
            }
        }
Example #2
0
        internal void Connect()
        {
            if (this.state.CompareAndSet(ConnectionState.INITIAL, ConnectionState.CONNECTING))
            {
                Address addr = UriUtil.ToAddress(connInfo.remoteHost, connInfo.username, connInfo.password ?? string.Empty);
                Tracer.InfoFormat("Creating Address: {0}", addr.Host);
                if (this.clientIdCanSet.CompareAndSet(true, false))
                {
                    if (this.ClientId == null)
                    {
                        connInfo.ResourceId = this.clientIdGenerator.GenerateId();
                    }
                    else
                    {
                        connInfo.ResourceId = new Id(ClientId);
                    }
                    Tracer.InfoFormat("Staring Connection with Client Id : {0}", this.ClientId);
                }

                Open openFrame = CreateOpenFrame(this.connInfo);

                Task <Amqp.Connection> fconn = this.implCreate(addr, openFrame, this.OpenResponse);
                // wait until the Open request is sent
                this.impl = TaskUtil.Wait(fconn, connInfo.connectTimeout);
                if (fconn.Exception != null)
                {
                    // exceptions thrown from TaskUtil are typically System.AggregateException and are usually transport exceptions for secure transport.
                    // extract the innerException of interest and wrap it as an NMS exception
                    if (fconn.Exception is AggregateException)
                    {
                        throw ExceptionSupport.Wrap(fconn.Exception.InnerException,
                                                    "Failed to connect host {0}. Cause: {1}", openFrame.HostName, fconn.Exception.InnerException?.Message ?? fconn.Exception.Message);
                    }
                    else
                    {
                        throw ExceptionSupport.Wrap(fconn.Exception,
                                                    "Failed to connect host {0}. Cause: {1}", openFrame.HostName, fconn.Exception?.Message);
                    }
                }

                this.impl.Closed += OnInternalClosed;
                this.impl.AddClosedCallback(OnInternalClosed);
                this.latch = new CountDownLatch(1);

                ConnectionState finishedState = ConnectionState.UNKNOWN;
                // Wait for Open response
                try
                {
                    bool received = this.latch.await((this.Info.requestTimeout == 0) ? Timeout.InfiniteTimeSpan : this.RequestTimeout);
                    if (received && this.impl.Error == null && fconn.Exception == null)
                    {
                        Tracer.InfoFormat("Connection {0} has connected.", this.impl.ToString());
                        finishedState = ConnectionState.CONNECTED;
                        // register connection factory once client Id accepted.
                        MessageFactory <ConnectionInfo> .Register(this);
                    }
                    else
                    {
                        if (!received)
                        {
                            // Timeout occured waiting on response
                            Tracer.InfoFormat("Connection Response Timeout. Failed to receive response from {0} in {1}ms", addr.Host, this.Info.requestTimeout);
                        }
                        finishedState = ConnectionState.INITIAL;

                        if (fconn.Exception == null)
                        {
                            if (!received)
                            {
                                throw ExceptionSupport.GetTimeoutException(this.impl, "Connection {0} has failed to connect in {1}ms.", ClientId, connInfo.closeTimeout);
                            }
                            Tracer.ErrorFormat("Connection {0} has Failed to connect. Message: {1}", ClientId, (this.impl.Error == null ? "Unknown" : this.impl.Error.ToString()));

                            throw ExceptionSupport.GetException(this.impl, "Connection {0} has failed to connect.", ClientId);
                        }
                        else
                        {
                            throw ExceptionSupport.Wrap(fconn.Exception, "Connection {0} failed to connect.", ClientId);
                        }
                    }
                }
                finally
                {
                    this.latch = null;
                    this.state.GetAndSet(finishedState);
                    if (finishedState != ConnectionState.CONNECTED)
                    {
                        this.impl.Close(TimeSpan.FromMilliseconds(connInfo.closeTimeout), null);
                    }
                }
            }
        }