public function connect($host, $port, Connection $connection, $timeout = 5)
    {
        if ($this->isConnected || $this->isConnecting) {
            return new RejectedPromise(new \LogicException('The client is already connected.'));
        }

        $this->isConnecting = true;
        $this->isConnected = false;

        $this->host = $host;
        $this->port = $port;

        $deferred = new Deferred();

        $this->establishConnection($this->host, $this->port, $timeout)
            ->then(function (DuplexStreamInterface $stream) use ($connection, $deferred, $timeout) {
                $this->stream = $stream;

                $this->emit('open', [$connection, $this]);

                $this->registerClient($connection, $timeout)
                    ->then(function (ConnectResponsePacket $responsePacket) use ($deferred, $connection) {
                        $this->isConnecting = false;
                        $this->isConnected = true;
                        $this->connection = $connection;

                        $this->emit('connect', [$responsePacket, $this]);
                        $deferred->resolve($responsePacket);
                    })
                    ->otherwise(function (\Exception $e) use ($deferred, $connection) {
                        $this->isConnecting = false;

                        $this->emitError($e);
                        $deferred->reject($e);

                        if ($this->stream !== null) {
                            $this->stream->close();
                        }

                        $this->emit('close', [$connection, $this]);
                    });
            })
            ->otherwise(function (\Exception $e) use ($deferred) {
                $this->isConnecting = false;

                $this->emitError($e);
                $deferred->reject($e);
            });

        return $deferred->promise();
    }