def _process_connect_init(self):
        """
        Handles the initial part of the NATS protocol, moving from
        the (RE)CONNECTING to CONNECTED states when establishing
        a connection with the server.
        """
        # INFO {...}
        line = yield self.io.read_until(_CRLF_, max_bytes=None)
        _, args = line.split(INFO_OP + _SPC_, 1)
        self._server_info = tornado.escape.json_decode((args))

        if 'max_payload' in self._server_info:
            self._max_payload_size = self._server_info["max_payload"]

        # Check whether we need to upgrade to TLS first of all
        if 'tls_required' in self._server_info and self._server_info['tls_required']:
            # Detach and prepare for upgrading the TLS connection.
            self._loop.remove_handler(self._socket.fileno())

            tls_opts = {}
            if "tls" in self.options:
                # Allow customizing the TLS version though default
                # to one that the server supports at least.
                tls_opts = self.options["tls"]

            # Rewrap using a TLS connection, can't do handshake on connect
            # as the socket is non blocking.
            self._socket = ssl.wrap_socket(
                self._socket, do_handshake_on_connect=False, **tls_opts)

            # Use the TLS stream instead from now
            self.io = tornado.iostream.SSLIOStream(self._socket)
            self.io.set_close_callback(self._process_op_err)
            self.io._do_ssl_handshake()

        # Refresh state of the parser upon reconnect.
        if self.is_reconnecting:
            self._ps.reset()

        # CONNECT then send a PING expecting a PONG to make a
        # roundtrip to the server and assert that sent commands sent
        # this far have been processed already.
        cmd = self.connect_command()
        yield self.io.write(cmd)
        yield self.io.write(PING_PROTO)

        # FIXME: Add readline timeout for these.
        next_op = yield self.io.read_until(
            _CRLF_, max_bytes=MAX_CONTROL_LINE_SIZE)
        if self.options["verbose"] and OK_OP in next_op:
            next_op = yield self.io.read_until(
                _CRLF_, max_bytes=MAX_CONTROL_LINE_SIZE)
        if ERR_OP in next_op:
            err_line = next_op.decode()
            _, err_msg = err_line.split(_SPC_, 1)
            # FIXME: Maybe handling could be more special here,
            # checking for ErrAuthorization for example.
            # yield from self._process_err(err_msg)
            raise NatsError("nats: " + err_msg.rstrip('\r\n'))

        if PONG_PROTO in next_op:
            self._status = Client.CONNECTED

        self._loop.spawn_callback(self._read_loop)
        self._pongs = []
        self._pings_outstanding = 0
        self._ping_timer = tornado.ioloop.PeriodicCallback(
            self._ping_interval, self.options["ping_interval"] * 1000)
        self._ping_timer.start()

        # Queue and flusher for coalescing writes to the server.
        self._flush_queue = tornado.queues.Queue(maxsize=1024)
        self._loop.spawn_callback(self._flusher_loop)