<commit_before>/*  This file is part of the Kate project.
 *
 *  Copyright (C) 2012 Christoph Cullmann <cullmann@kde.org>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#include "kateprojectview.h"
#include "kateprojectpluginview.h"

#include <ktexteditor/document.h>
#include <ktexteditor/view.h>

#include <QContextMenuEvent>
#include <QSortFilterProxyModel>
#include <KMimeType>
#include <KMimeTypeTrader>
#include <QMenu>
#include <KRun>
#include <KIcon>
#include <KLineEdit>

KateProjectView::KateProjectView (KateProjectPluginView *pluginView, KateProject *project)
  : QWidget ()
  , m_pluginView (pluginView)
  , m_project (project)
  , m_treeView (new KateProjectViewTree(pluginView, project))
  , m_filter (new KLineEdit ())
{
  /**
   * layout tree view and co.
   */
  QVBoxLayout *layout = new QVBoxLayout ();
  layout->setSpacing (0);
  layout->addWidget (m_treeView);
  layout->addWidget (m_filter);
  setLayout (layout);

  /**
   * do some stuff if line edit is changed
   */
  connect (m_filter, SIGNAL(textChanged(QString)), this, SLOT(filterTextChanged(QString)));
}

KateProjectView::~KateProjectView ()
{
}

void KateProjectView::selectFile (const QString &file)
{
  m_treeView->selectFile (file);
}

void KateProjectView::openSelectedDocument ()
{
  m_treeView->openSelectedDocument ();
}

void KateProjectView::filterTextChanged (QString filterText)
{
  /**
   * filter
   */
  static_cast<QSortFilterProxyModel *>(m_treeView->model ())->setFilterFixedString (filterText);

  /**
   * expand
   */
  if (!filterText.isEmpty())
    QTimer::singleShot (100, m_treeView, SLOT(expandAll ()));
}

// kate: space-indent on; indent-width 2; replace-tabs on;
<commit_msg>fix comp<commit_after>/*  This file is part of the Kate project.
 *
 *  Copyright (C) 2012 Christoph Cullmann <cullmann@kde.org>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#include "kateprojectview.h"
#include "kateprojectpluginview.h"

#include <ktexteditor/document.h>
#include <ktexteditor/view.h>

#include <QContextMenuEvent>
#include <QSortFilterProxyModel>
#include <KMimeType>
#include <KMimeTypeTrader>
#include <QMenu>
#include <KRun>
#include <KIcon>
#include <KLineEdit>
#include <QVBoxLayout>

KateProjectView::KateProjectView (KateProjectPluginView *pluginView, KateProject *project)
  : QWidget ()
  , m_pluginView (pluginView)
  , m_project (project)
  , m_treeView (new KateProjectViewTree(pluginView, project))
  , m_filter (new KLineEdit ())
{
  /**
   * layout tree view and co.
   */
  QVBoxLayout *layout = new QVBoxLayout ();
  layout->setSpacing (0);
  layout->addWidget (m_treeView);
  layout->addWidget (m_filter);
  setLayout (layout);

  /**
   * do some stuff if line edit is changed
   */
  connect (m_filter, SIGNAL(textChanged(QString)), this, SLOT(filterTextChanged(QString)));
}

KateProjectView::~KateProjectView ()
{
}

void KateProjectView::selectFile (const QString &file)
{
  m_treeView->selectFile (file);
}

void KateProjectView::openSelectedDocument ()
{
  m_treeView->openSelectedDocument ();
}

void KateProjectView::filterTextChanged (QString filterText)
{
  /**
   * filter
   */
  static_cast<QSortFilterProxyModel *>(m_treeView->model ())->setFilterFixedString (filterText);

  /**
   * expand
   */
  if (!filterText.isEmpty())
    QTimer::singleShot (100, m_treeView, SLOT(expandAll ()));
}

// kate: space-indent on; indent-width 2; replace-tabs on;
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/dcd.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
<commit_msg>Adds DD2 dcd functionality<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/dcd.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file dcd.C
/// @brief Subroutines duty cycle calibration
///
// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/phy/dcd.H>
#include <generic/memory/lib/utils/scom.H>
#include <generic/memory/lib/utils/pos.H>
#include <lib/utils/poll.H>
#include <lib/utils/conversions.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCBIST;
using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{

// Definition of the ADR32S duty cycle distortion registers
// Note: per John Bialas, ADR32S1 and CONTROL1_P0_4 do not hook up to any logic, removing them to avoid errors
const std::vector<uint64_t> dutyCycleDistortionTraits<fapi2::TARGET_TYPE_MCA>::DUTY_CYCLE_DISTORTION_REG =
{
    MCA_DDRPHY_ADR_DCD_CONTROL_P0_ADR32S0,
    MCA_DDRPHY_DP16_DCD_CONTROL0_P0_0,
    MCA_DDRPHY_DP16_DCD_CONTROL1_P0_0,
    MCA_DDRPHY_DP16_DCD_CONTROL0_P0_1,
    MCA_DDRPHY_DP16_DCD_CONTROL1_P0_1,
    MCA_DDRPHY_DP16_DCD_CONTROL0_P0_2,
    MCA_DDRPHY_DP16_DCD_CONTROL1_P0_2,
    MCA_DDRPHY_DP16_DCD_CONTROL0_P0_3,
    MCA_DDRPHY_DP16_DCD_CONTROL1_P0_3,
    MCA_DDRPHY_DP16_DCD_CONTROL0_P0_4,
};

// Definition of the ADR32S duty cycle distortion registers
// Note: per John Bialas, ADR32S1 and CONTROL1_P0_4 do not hook up to any logic, removing them to avoid errors
const std::vector<uint64_t> dutyCycleDistortionTraits<fapi2::TARGET_TYPE_MCA>::DLL_CONTROL_REG =
{
    MCA_DDRPHY_ADR_DLL_CNTL_P0_ADR32S0,
    MCA_DDRPHY_DP16_DLL_CNTL0_P0_0,
    MCA_DDRPHY_DP16_DLL_CNTL1_P0_0,
    MCA_DDRPHY_DP16_DLL_CNTL0_P0_1,
    MCA_DDRPHY_DP16_DLL_CNTL1_P0_1,
    MCA_DDRPHY_DP16_DLL_CNTL0_P0_2,
    MCA_DDRPHY_DP16_DLL_CNTL1_P0_2,
    MCA_DDRPHY_DP16_DLL_CNTL0_P0_3,
    MCA_DDRPHY_DP16_DLL_CNTL1_P0_3,
    MCA_DDRPHY_DP16_DLL_CNTL0_P0_4,
};

namespace dcd
{

///
/// @brief Sets up the DLL control regs for the DCD calibration - specialization for MCA
/// @param[in] i_target MCA target on which to operate
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
/// @note Always needs to be run for DD1.* parts.  unsure for DD2
///
template< >
fapi2::ReturnCode setup_dll_control_regs( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
{
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    for (const auto& r : TT::DLL_CONTROL_REG)
    {
        fapi2::buffer<uint64_t> l_data;

        FAPI_TRY(mss::getScom(i_target, r, l_data));

        // Stops cal from updating and disables cal good to keep parity good (these regs have parity issues on bits 60-63)
        l_data.clearBit<TT::DLL_CAL_UPDATE>();
        l_data.clearBit<TT::DLL_CAL_GOOD>();

        FAPI_TRY(mss::putScom(i_target, r, l_data));
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Restores the DLL control regs after the DCD calibration - specialization for MCA
/// @param[in] i_target MCA target on which to operate
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
/// @note Always needs to be run for DD1.* parts.  unsure for DD2
///
template< >
fapi2::ReturnCode restore_dll_control_regs( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target )
{
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    for (const auto& r : TT::DLL_CONTROL_REG)
    {
        fapi2::buffer<uint64_t> l_data;

        FAPI_TRY(mss::getScom(i_target, r, l_data));

        // Re-enables cal to update
        l_data.setBit<TT::DLL_CAL_UPDATE>();

        FAPI_TRY(mss::putScom(i_target, r, l_data));
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Helper to iterate over ADR32S 'sides' when performing DCD cal - MCA specialization
/// @param[in] i_target the MCA to iterate for
/// @param[in] i_reg the register (ADR0 or ADR1's register)
/// @param[in] i_seed the seed value for the adjuster
/// @param[in] i_side bool; true if this is side a, false for side b
/// @param[out] o_value the value of the adjuster when the compare bit changes state
/// @return FAPI2_RC_SUCCESS iff ok
///
template< >
fapi2::ReturnCode sw_cal_side_helper( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
                                      const uint64_t i_reg,
                                      const uint64_t i_seed,
                                      const bool i_side,
                                      uint64_t& o_value )
{
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    constexpr uint64_t l_dcd_adjust_overflow =  0b1111111;
    constexpr uint64_t l_dcd_adjust_underflow = 0b0000000;

    constexpr uint64_t l_delay = mss::DELAY_100NS;
    const uint64_t l_delay_in_cycles = mss::ns_to_cycles(i_target, l_delay);

    // The DCD algorithm steps until we see a 0 to 1 or 1 to 0 transition
    // 1 means that we need to decrease to get to the 50/50 duty cycle case
    // 0 means that we need to increase to get to the 50/50 duty cycle case
    // If compare out is 0, we tick up ...
    // Signed value which helps us increment or decrement the adjustment
    int64_t l_tick = 1;
    // ... and we expect a transition to 1 (need to decrease to get to the 50/50 duty cycle)
    bool l_expected = 1;
    // ... and we don't expect to overflow
    uint64_t l_overrun = l_dcd_adjust_overflow;

    fapi2::buffer<uint64_t> l_read;
    uint64_t l_current_adjust = i_seed;
    size_t l_iter = 0;

    // More or less mirror's Bialas's logic for DD2 so we can kind of try out the algorithm on DD1.

    FAPI_INF("enter dcd_cal_helper %s 0x%016lx seed: 0x%016lx side: %d",
             mss::c_str(i_target), i_reg, i_seed, i_side );

    // Prime the system with the starting values. We don't need to read/modify/write here as we're resetting
    // the world and saving a scom here is likely benificial. Clear the compare out bit as writing it set
    // will cause the PHY to throw a parity error
    set_dcd_value(i_target, l_read, l_current_adjust);
    l_read.setBit<TT::DCD_CONTROL_DLL_CORRECT_EN>();
    l_read.writeBit<TT::DCD_CONTROL_DLL_ITER_A>(i_side);
    l_read.clearBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>();

    // Sets the DCD calibration bit enable to a 0 if we're in DD2
    if(!mss::chip_ec_nimbus_lt_2_0(i_target))
    {
        l_read.clearBit<TT::DCD_DD2_CAL_ENABLE>();
    }

    FAPI_TRY( mss::putScom(i_target, i_reg, l_read) );

    // Read. Note the register is volatile in that l_read which we just wrote isn't what we'll read
    // as the distortion logic will take the seeded adjustment value and give us information on the next
    // read (so don't get cute and remove this getScom.)
    FAPI_TRY( mss::getScom(i_target, i_reg, l_read) );

    // Based on the 'direction' we're going, we have some values to setup. We setup the bit == 0 case
    // when we initialized these variables above.
    if (l_read.getBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>())
    {
        // If compare out is 1, we tick down ...
        l_tick = -1;

        // ... and we expect a transition to 0 (need to increase to get to the 50/50 duty cycle)
        l_expected = 0;

        // ... and we don't expect to underflow
        l_overrun = l_dcd_adjust_underflow;
    }

    do
    {
        l_iter += 1;
        bool l_current_compare = l_read.getBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>();

        FAPI_INF("dcd_cal_helper: iter %d tick: %d expected: %d overrun: 0x%x out: %d adj: 0x%x",
                 l_iter, l_tick, l_expected, l_overrun, l_current_compare, l_current_adjust);

        if (l_current_compare == l_expected)
        {
            break;
        }

        // If we're here we're not done, so just adjust and try again. Clear the compare out bit, it must
        // always be 0 or the PHY will parity error
        set_dcd_value(i_target, l_read, l_current_adjust + l_tick);
        l_read.clearBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>();
        FAPI_TRY( mss::putScom(i_target, i_reg, l_read) );

        // Wait for valid results...
        FAPI_TRY( fapi2::delay(l_delay, mss::cycles_to_simcycles(l_delay_in_cycles)) );

        // Check our results
        FAPI_TRY( mss::getScom(i_target, i_reg, l_read) );

        // Includes an extra wait for the next loop
        FAPI_TRY( fapi2::delay(l_delay, mss::cycles_to_simcycles(l_delay_in_cycles)) );

        // Gets the current adjustment value
        get_dcd_value(i_target, l_read, l_current_adjust);

    }
    while (l_current_adjust != l_overrun);

    FAPI_ASSERT( l_current_adjust != l_overrun,
                 fapi2::MSS_DUTY_CLOCK_DISTORTION_CAL_FAILED()
                 .set_TARGET(i_target)
                 .set_CURRENT_ADJUST(l_current_adjust)
                 .set_SIDE(i_side)
                 .set_REGISTER(i_reg)
                 .set_REGISTER_VALUE(l_read),
                 "Failed DCD for %s 0x%016lx", mss::c_str(i_target), i_reg );

    // If we're here, we were done and there were no errors. So we can return back the current adjust value
    // as the output/result of our operation
    o_value = l_current_adjust;
    FAPI_INF("side: %d final adjust value: 0x%x (0x%x)", i_side, o_value, l_current_adjust);

    return FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Helper to iterate over a DCD register's 'sides' when performing DCD cal - MCA specialization
/// @param[in] i_target the target to iterate for
/// @param[in] i_reg the register (ADR0 or ADR1's register)
/// @param[in,out] io_seed the seed value for the adjuster
/// @return FAPI2_RC_SUCCESS iff ok
///
template< >
fapi2::ReturnCode sw_cal_per_register( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
                                       const uint64_t i_reg,
                                       uint64_t& io_seed)
{
    constexpr bool A_SIDE = true;
    constexpr bool B_SIDE = false;
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;
    uint64_t l_a_side_value = 0;
    uint64_t l_b_side_value = 0;
    fapi2::buffer<uint64_t> l_buff;

    auto l_a_rc = sw_cal_side_helper(i_target, i_reg, io_seed, A_SIDE, l_a_side_value);

    // Updates the seed value to avoid underflow issues
    io_seed = (l_a_side_value == 0) ? (io_seed) : (l_a_side_value - 1);

    // We want to seed the other side (and each subsequent port) with the
    // value found in the pervious iteration as that will likely reduce the number
    // of iterations to find the transition. We back up one so that if we're on
    // a transition, we don't 'bounce' from a 1 to a 0. This will give us a good
    // transition if the a-side value is really to be the b-side value too.
    auto l_b_rc = sw_cal_side_helper(i_target, i_reg, io_seed, B_SIDE, l_b_side_value);

    // The final value is the average of the a-side and b-side values.
    FAPI_TRY(compute_dcd_value(l_a_rc, l_a_side_value, l_b_rc, l_b_side_value, io_seed));

    FAPI_INF("%s calibrated value for both sides for reg 0x%016lx cal value: 0x%02x, a_side 0x%02x b_side: 0x%02x",
             mss::c_str(i_target), i_reg, io_seed,
             l_a_side_value, l_b_side_value);

    // Stores the final calibrated values in the register with a RMW
    FAPI_TRY( mss::getScom(i_target, i_reg, l_buff) );
    set_dcd_value(i_target, l_buff, io_seed);
    l_buff.clearBit<TT::DCD_CONTROL_DLL_COMPARE_OUT>();

    // Note this writes all the other values to 0's which is OK for DD1 and DD2
    FAPI_TRY( mss::putScom(i_target, i_reg, l_buff) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Sets the value to write out to the DCD register in question
/// @param[in,out] i_a_side_rc - a side's return code - cannot be const due to the fapi logging function modifying the RC
/// @param[in] i_a_side_val - a side's value
/// @param[in,out] i_b_side_rc - b side's return code - cannot be const due to the fapi logging function modifying the RC
/// @param[in] i_b_side_val - b side's value
/// @param[out] o_value - value to use for the DCD register
/// @return FAPI2_RC_SUCCESS iff ok
/// @note Due to DCD algorithm fails due to bad HW, the algorithm is going to do the following
/// Per the PHY team, we do not want to fail out existing HW for the DCD calibration fails
/// 1) Use prior calibrated value if a/b fail - return success
/// 2) Use a if b failed
/// 3) Use b if a failed
/// 4) Average if a and b both passed
///
fapi2::ReturnCode compute_dcd_value(fapi2::ReturnCode& io_a_side_rc,
                                    const uint64_t i_a_side_val,
                                    fapi2::ReturnCode& io_b_side_rc,
                                    const uint64_t i_b_side_val,
                                    uint64_t& o_value)
{
    // 1) per lab/design team, we want to return a passing RC
    //  We pass this  hardware as a large amount of HW fails DCD calibration but runs fine without it
    if((io_a_side_rc != FAPI2_RC_SUCCESS) &&
       (io_b_side_rc != FAPI2_RC_SUCCESS))
    {
        // Log a-side and b-side RC's leave the seed as it is
        FAPI_ERR("Recovered from DCD calibration fail - both side A and side B failed, using prior calibrated value");
        fapi2::logError(io_a_side_rc);
        fapi2::logError(io_b_side_rc);
        return FAPI2_RC_SUCCESS;
    }

    // 2) b failed, use a's value
    if(io_b_side_rc != FAPI2_RC_SUCCESS)
    {
        FAPI_ERR("Recovered from DCD calibration fail - side B failed, using side-A's value");
        fapi2::logError(io_b_side_rc);
        o_value = i_a_side_val;
        return FAPI2_RC_SUCCESS;
    }

    // 3) a failed, use b's value
    if(io_a_side_rc != FAPI2_RC_SUCCESS)
    {
        FAPI_ERR("Recovered from DCD calibration fail - side A failed, using side-B's value");
        fapi2::logError(io_a_side_rc);
        o_value = i_b_side_val;
        return FAPI2_RC_SUCCESS;
    }

    // 4) average a and b as both passed
    FAPI_DBG("Both sides A/B passed - averaging");
    o_value = (i_a_side_val + i_b_side_val) / 2;
    return FAPI2_RC_SUCCESS;
}

///
/// @brief Logs the passing vs failing results from the hardware DCD calibration
/// @param[in] i_target the target to iterate for
/// @param[in] i_reg the register (ADR0 or ADR1's register)
/// @param[in] i_data the registers data
/// @param[in,out] io_sum the sum of all good values
/// @param[in,out] io_failing_regs a vector containing all failing registers
///
template< >
void log_reg_results( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
                      const uint64_t i_reg,
                      const fapi2::buffer<uint64_t>& i_data,
                      uint64_t& io_sum,
                      std::vector<uint64_t>& io_failing_regs)
{
    // Traits definition
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    const bool l_failed = i_data.getBit<TT::DCD_DD2_CAL_ERROR>();

    FAPI_INF("%s DCD calibration %s on reg 0x%016lx", mss::c_str(i_target), l_failed ? "passed" : "failed", i_reg);

    // Updates the failing registers if the error bit is set
    if(l_failed)
    {
        io_failing_regs.push_back(i_reg);
    }
    // Updates sum if we passed
    else
    {
        uint64_t l_result = 0;
        get_dcd_value(i_target, i_data, l_result);
        io_sum += l_result;
    }
}

///
/// @brief Polls for done on an individual DCD register and logs passing vs failing results - MCA specialization
/// @param[in] i_target the target to iterate for
/// @param[in] i_reg the register (ADR0 or ADR1's register)
/// @param[in,out] io_sum the sum of all good values - note: will not update if DCD calibration fails
/// @param[in,out] io_failing_regs a vector containing all failing registers - note: will not add a value if DCD cal passes
/// @return FAPI2_RC_SUCCESS iff ok
///
template< >
fapi2::ReturnCode poll_for_done_and_log_reg( const fapi2::Target<TARGET_TYPE_MCA>& i_target,
        const uint64_t i_reg,
        uint64_t& io_sum,
        std::vector<uint64_t>& io_failing_regs)
{
    // Traits definition
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    // Sets fapi2::current_err for safety
    fapi2::current_err = FAPI2_RC_SUCCESS;

    // Poll limit declaration
    // Max number of loops we can have and still pass is going to the bottom (128 down) ,seeing the transition
    // Then going all the way to the top and seeing the transition (256 steps up)
    // Realistically, this is not very likely at all
    constexpr uint64_t POLL_LIMIT = 128 + 256;

    // Declares parameters for the polling
    auto l_poll = mss::poll_parameters(DELAY_100NS,
                                       DELAY_100NS,
                                       DELAY_100NS,
                                       DELAY_100NS,
                                       POLL_LIMIT);
    fapi2::buffer<uint64_t> l_result;

    // Polls for DCD finished
    const auto l_poll_finished = mss::poll(i_target,
                                           i_reg,
                                           l_poll,
                                           [&l_result, &i_reg](const size_t poll_remaining,
                                                   const fapi2::buffer<uint64_t>& stat_reg) -> bool
    {
        FAPI_INF("DCD register 0x%016lx calibration reg value 0x%016llx, remaining: %d", i_reg, stat_reg, poll_remaining);
        l_result = stat_reg;
        return stat_reg.getBit<TT::DCD_DD2_CAL_DONE>();
    });

    // If the polling didn't finish, exit out with an error
    FAPI_ASSERT( l_poll_finished,
                 fapi2::MSS_HARDWARE_DUTY_CLOCK_DISTORTION_CAL_TIMEOUT()
                 .set_TARGET(i_target)
                 .set_REGISTER(i_reg),
                 "Timed out in hardware DCD for %s 0x%016lx", mss::c_str(i_target), i_reg );

    // Otherwise, log the information about these results
    log_reg_results(i_target, i_reg, l_result, io_sum, io_failing_regs);

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Kicks off the DCD HW calibration - MCA specialization
/// @param[in] i_target the target to iterate for
/// @return FAPI2_RC_SUCCESS iff ok
///
template< >
fapi2::ReturnCode execute_hw_calibration( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
{
    // Traits definition
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    // DCD hardware calibration is a three step process:
    // 1) kick off cal on all the registers
    // 2) poll for done on all of the registers - add failing regs into a vector for the workaround/log the results and make an average of all good regs
    //    Note: step 2 is done separately from 1 to speed up the polling process - it will take some time to kick off all DCD's, so all calibrations are started before polling
    // 3) loop through the list of failing DCD regs and do the software calibration

    // Variable declaration
    uint64_t l_good_sum = 0;
    uint64_t l_good_average = 0;
    std::vector<uint64_t> l_failing_registers;

    // 1) kick off cal on all the registers
    {
        // Default value of the mid point of our range, hit the SW cal enable and is present bits (bits 8/10 in phy nomenclature)
        constexpr uint64_t DCD_CAL_ON = 0x80a0;
        FAPI_TRY(mss::scom_blastah(i_target, TT::DUTY_CYCLE_DISTORTION_REG, DCD_CAL_ON), "%s failed to start DCD calibration",
                 mss::c_str(i_target));
    }

    // 2) poll for done on all of the registers - add failing regs into a vector for the workaround/log the results and make an average of all good regs
    // Loops through each DCD register and checks to see if calibration is done
    // Additionally, updates the sum if this DCD call error is cleared, but logs a failing register if the error bit is set
    for(const auto& l_reg : TT::DUTY_CYCLE_DISTORTION_REG)
    {
        FAPI_TRY(poll_for_done_and_log_reg(i_target, l_reg, l_good_sum, l_failing_registers),
                 "%s failed to poll for DCD done properly on reg 0x%016lx", mss::c_str(i_target), l_reg);
    }

    // Computes the average - current we have the sum of all good values, we need to divide by the number of passing regs
    {
        // The number of good registers is the number of registers minus the number of failing registers
        const uint64_t l_num_good_regs = TT::DUTY_CYCLE_DISTORTION_REG.size() - l_failing_registers.size();
        l_good_average = l_good_sum / l_num_good_regs;
        FAPI_INF("%s the number of failing regs %lu the number of good regs %lu the sum %lu and the good average %lu",
                 mss::c_str(i_target), l_failing_registers.size(), l_num_good_regs, l_good_sum, l_good_average);
    }

    // 3) loop through the list of failing DCD regs and do the software calibration
    for(const auto& l_reg : l_failing_registers)
    {
        // Copies the seed so we can preserve the average
        uint64_t l_seed = l_good_average;
        FAPI_INF("%s executing software calibration on failing register 0x%016lx with seed of %lu", mss::c_str(i_target), l_reg,
                 l_seed);
        FAPI_TRY(sw_cal_per_register(i_target, l_reg, l_seed),
                 "%s failed to execute the software DCD calibration on register 0x%016lx", mss::c_str(i_target), l_reg);
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Kicks off the DCD HW calibration - MCBIST specialization
/// @param[in] i_target the target to iterate for
/// @return FAPI2_RC_SUCCESS iff ok
///
template< >
fapi2::ReturnCode execute_hw_calibration( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    // First, check if we're a DD1 level of a Nimbus part, if so, skip this calibration as it does not exist
    if(mss::chip_ec_nimbus_lt_2_0(i_target))
    {
        FAPI_INF("%s skipping hardware DCD calibration as this is a DD2 module", mss::c_str(i_target));
        return FAPI2_RC_SUCCESS;
    }

    // Now that we know we are a DD2 Nimbus part, run DCD calibration on each port individually
    // Note: we might have been able to speed this up by running on all ports at the same time, but it would make the code much more complex
    for(const auto& l_mca : mss::find_targets<TARGET_TYPE_MCA>(i_target))
    {
        FAPI_TRY(setup_dll_control_regs(l_mca), "%s failed to setup the DLLs for DCD calibration!", mss::c_str(l_mca));
        FAPI_TRY(execute_hw_calibration(l_mca), "%s failed to run DCD calibration!", mss::c_str(l_mca));
        FAPI_TRY(restore_dll_control_regs(l_mca), "%s failed to restore the DLLs for DCD calibration!", mss::c_str(l_mca));
    }

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace dcd
} // close namespace mss
<|endoftext|>


<commit_before>// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <net_permissions.h>
#include <netbase.h>
#include <util/error.h>
#include <util/system.h>
#include <util/translation.h>

const std::vector<std::string> NET_PERMISSIONS_DOC{
    "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
    "noban (do not ban for misbehavior)",
    "forcerelay (relay transactions that are already in the mempool; implies relay)",
    "relay (relay even in -blocksonly mode)",
    "mempool (allow requesting BIP35 mempool contents)",
};

// The parse the following format "perm1,perm2@xxxxxx"
bool TryParsePermissionFlags(const std::string str, NetPermissionFlags& output, size_t& readen, bilingual_str& error)
{
    NetPermissionFlags flags = PF_NONE;
    const auto atSeparator = str.find('@');

    // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
    if (atSeparator == std::string::npos) {
        NetPermissions::AddFlag(flags, PF_ISIMPLICIT);
        readen = 0;
    }
    // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
    else {
        readen = 0;
        // permissions == perm1,perm2
        const auto permissions = str.substr(0, atSeparator);
        while (readen < permissions.length()) {
            const auto commaSeparator = permissions.find(',', readen);
            const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
            // permission == perm1
            const auto permission = permissions.substr(readen, len);
            readen += len; // We read "perm1"
            if (commaSeparator != std::string::npos) readen++; // We read ","

            if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, PF_BLOOMFILTER);
            else if (permission == "noban") NetPermissions::AddFlag(flags, PF_NOBAN);
            else if (permission == "forcerelay") NetPermissions::AddFlag(flags, PF_FORCERELAY);
            else if (permission == "mempool") NetPermissions::AddFlag(flags, PF_MEMPOOL);
            else if (permission == "all") NetPermissions::AddFlag(flags, PF_ALL);
            else if (permission == "relay") NetPermissions::AddFlag(flags, PF_RELAY);
            else if (permission.length() == 0); // Allow empty entries
            else {
                error = strprintf(_("Invalid P2P permission: '%s'"), permission);
                return false;
            }
        }
        readen++;
    }

    output = flags;
    error = Untranslated("");
    return true;
}

std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
{
    std::vector<std::string> strings;
    if (NetPermissions::HasFlag(flags, PF_BLOOMFILTER)) strings.push_back("bloomfilter");
    if (NetPermissions::HasFlag(flags, PF_NOBAN)) strings.push_back("noban");
    if (NetPermissions::HasFlag(flags, PF_FORCERELAY)) strings.push_back("forcerelay");
    if (NetPermissions::HasFlag(flags, PF_RELAY)) strings.push_back("relay");
    if (NetPermissions::HasFlag(flags, PF_MEMPOOL)) strings.push_back("mempool");
    return strings;
}

bool NetWhitebindPermissions::TryParse(const std::string str, NetWhitebindPermissions& output, bilingual_str& error)
{
    NetPermissionFlags flags;
    size_t offset;
    if (!TryParsePermissionFlags(str, flags, offset, error)) return false;

    const std::string strBind = str.substr(offset);
    CService addrBind;
    if (!Lookup(strBind, addrBind, 0, false)) {
        error = ResolveErrMsg("whitebind", strBind);
        return false;
    }
    if (addrBind.GetPort() == 0) {
        error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
        return false;
    }

    output.m_flags = flags;
    output.m_service = addrBind;
    error = Untranslated("");
    return true;
}

bool NetWhitelistPermissions::TryParse(const std::string str, NetWhitelistPermissions& output, bilingual_str& error)
{
    NetPermissionFlags flags;
    size_t offset;
    if (!TryParsePermissionFlags(str, flags, offset, error)) return false;

    const std::string net = str.substr(offset);
    CSubNet subnet;
    LookupSubNet(net, subnet);
    if (!subnet.IsValid()) {
        error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
        return false;
    }

    output.m_flags = flags;
    output.m_subnet = subnet;
    error = Untranslated("");
    return true;
}
<commit_msg>refactor: Put`TryParsePermissionFlags` in anonymous namespace<commit_after>// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <net_permissions.h>
#include <netbase.h>
#include <util/error.h>
#include <util/system.h>
#include <util/translation.h>

const std::vector<std::string> NET_PERMISSIONS_DOC{
    "bloomfilter (allow requesting BIP37 filtered blocks and transactions)",
    "noban (do not ban for misbehavior)",
    "forcerelay (relay transactions that are already in the mempool; implies relay)",
    "relay (relay even in -blocksonly mode)",
    "mempool (allow requesting BIP35 mempool contents)",
};

namespace {

// The parse the following format "perm1,perm2@xxxxxx"
bool TryParsePermissionFlags(const std::string str, NetPermissionFlags& output, size_t& readen, bilingual_str& error)
{
    NetPermissionFlags flags = PF_NONE;
    const auto atSeparator = str.find('@');

    // if '@' is not found (ie, "xxxxx"), the caller should apply implicit permissions
    if (atSeparator == std::string::npos) {
        NetPermissions::AddFlag(flags, PF_ISIMPLICIT);
        readen = 0;
    }
    // else (ie, "perm1,perm2@xxxxx"), let's enumerate the permissions by splitting by ',' and calculate the flags
    else {
        readen = 0;
        // permissions == perm1,perm2
        const auto permissions = str.substr(0, atSeparator);
        while (readen < permissions.length()) {
            const auto commaSeparator = permissions.find(',', readen);
            const auto len = commaSeparator == std::string::npos ? permissions.length() - readen : commaSeparator - readen;
            // permission == perm1
            const auto permission = permissions.substr(readen, len);
            readen += len; // We read "perm1"
            if (commaSeparator != std::string::npos) readen++; // We read ","

            if (permission == "bloomfilter" || permission == "bloom") NetPermissions::AddFlag(flags, PF_BLOOMFILTER);
            else if (permission == "noban") NetPermissions::AddFlag(flags, PF_NOBAN);
            else if (permission == "forcerelay") NetPermissions::AddFlag(flags, PF_FORCERELAY);
            else if (permission == "mempool") NetPermissions::AddFlag(flags, PF_MEMPOOL);
            else if (permission == "all") NetPermissions::AddFlag(flags, PF_ALL);
            else if (permission == "relay") NetPermissions::AddFlag(flags, PF_RELAY);
            else if (permission.length() == 0); // Allow empty entries
            else {
                error = strprintf(_("Invalid P2P permission: '%s'"), permission);
                return false;
            }
        }
        readen++;
    }

    output = flags;
    error = Untranslated("");
    return true;
}

}

std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
{
    std::vector<std::string> strings;
    if (NetPermissions::HasFlag(flags, PF_BLOOMFILTER)) strings.push_back("bloomfilter");
    if (NetPermissions::HasFlag(flags, PF_NOBAN)) strings.push_back("noban");
    if (NetPermissions::HasFlag(flags, PF_FORCERELAY)) strings.push_back("forcerelay");
    if (NetPermissions::HasFlag(flags, PF_RELAY)) strings.push_back("relay");
    if (NetPermissions::HasFlag(flags, PF_MEMPOOL)) strings.push_back("mempool");
    return strings;
}

bool NetWhitebindPermissions::TryParse(const std::string str, NetWhitebindPermissions& output, bilingual_str& error)
{
    NetPermissionFlags flags;
    size_t offset;
    if (!TryParsePermissionFlags(str, flags, offset, error)) return false;

    const std::string strBind = str.substr(offset);
    CService addrBind;
    if (!Lookup(strBind, addrBind, 0, false)) {
        error = ResolveErrMsg("whitebind", strBind);
        return false;
    }
    if (addrBind.GetPort() == 0) {
        error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
        return false;
    }

    output.m_flags = flags;
    output.m_service = addrBind;
    error = Untranslated("");
    return true;
}

bool NetWhitelistPermissions::TryParse(const std::string str, NetWhitelistPermissions& output, bilingual_str& error)
{
    NetPermissionFlags flags;
    size_t offset;
    if (!TryParsePermissionFlags(str, flags, offset, error)) return false;

    const std::string net = str.substr(offset);
    CSubNet subnet;
    LookupSubNet(net, subnet);
    if (!subnet.IsValid()) {
        error = strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net);
        return false;
    }

    output.m_flags = flags;
    output.m_subnet = subnet;
    error = Untranslated("");
    return true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, Cloudera, inc.
// Confidential Cloudera Information: Covered by NDA.
// All rights reserved.

#include <string>
#include <vector>
#include <boost/functional/hash.hpp>

#include "kudu/gutil/strings/substitute.h"
#include "kudu/rpc/outbound_call.h"
#include "kudu/rpc/constants.h"
#include "kudu/rpc/rpc_controller.h"
#include "kudu/rpc/rpc_introspection.pb.h"
#include "kudu/rpc/serialization.h"
#include "kudu/rpc/transfer.h"

namespace kudu {
namespace rpc {

using strings::Substitute;
using google::protobuf::Message;
using google::protobuf::io::CodedOutputStream;

///
/// OutboundCall
///

OutboundCall::OutboundCall(const ConnectionId& conn_id,
                           const string& method,
                           google::protobuf::Message* response_storage,
                           RpcController* controller,
                           const ResponseCallback& callback)
  : state_(READY),
    conn_id_(conn_id),
    callback_(callback),
    controller_(DCHECK_NOTNULL(controller)),
    response_(DCHECK_NOTNULL(response_storage)) {
  DVLOG(4) << "OutboundCall " << this << " constructed with state_: " << StateName(state_)
           << " and RPC timeout: " << controller->timeout().ToString();
  header_.set_method_name(method);
  header_.set_call_id(kInvalidCallId);
  start_time_ = MonoTime::Now(MonoTime::FINE);
}

OutboundCall::~OutboundCall() {
  DCHECK(IsFinished());
  DVLOG(4) << "OutboundCall " << this << " destroyed with state_: " << StateName(state_);
}

Status OutboundCall::SerializeTo(vector<Slice>* slices) {
  size_t param_len = request_buf_.size();
  if (PREDICT_FALSE(param_len == 0)) {
    return Status::InvalidArgument("Must call SetRequestParam() before SerializeTo()");
  }

  const MonoDelta &timeout = controller_->timeout();
  if (timeout.Initialized()) {
    header_.set_timeout_millis(timeout.ToMilliseconds());
  }

  CHECK_OK(serialization::SerializeHeader(header_, param_len, &header_buf_));

  // Return the concatenated packet.
  slices->push_back(Slice(header_buf_));
  slices->push_back(Slice(request_buf_));
  return Status::OK();
}

Status OutboundCall::SetRequestParam(const Message& message) {
  return serialization::SerializeMessage(message, &request_buf_);
}

Status OutboundCall::status() const {
  lock_guard<simple_spinlock> l(&lock_);
  return status_;
}

const ErrorStatusPB* OutboundCall::error_pb() const {
  lock_guard<simple_spinlock> l(&lock_);
  return error_pb_.get();
}

string OutboundCall::StateName(State state) {
  switch (state) {
    case READY:
      return "READY";
    case ON_OUTBOUND_QUEUE:
      return "ON_OUTBOUND_QUEUE";
    case SENT:
      return "SENT";
    case TIMED_OUT:
      return "TIMED_OUT";
    case FINISHED_ERROR:
      return "FINISHED_ERROR";
    case FINISHED_SUCCESS:
      return "FINISHED_SUCCESS";
    default:
      LOG(DFATAL) << "Unknown state in OutboundCall: " << state;
      return StringPrintf("UNKNOWN(%d)", state);
  }
}

void OutboundCall::set_state(State new_state) {
  lock_guard<simple_spinlock> l(&lock_);
  set_state_unlocked(new_state);
}

OutboundCall::State OutboundCall::state() const {
  lock_guard<simple_spinlock> l(&lock_);
  return state_;
}

void OutboundCall::set_state_unlocked(State new_state) {
  // Sanity check state transitions.
  DVLOG(3) << "OutboundCall " << this << " (" << ToString() << ") switching from " <<
    StateName(state_) << " to " << StateName(new_state);
  switch (new_state) {
    case ON_OUTBOUND_QUEUE:
      DCHECK_EQ(state_, READY);
      break;
    case SENT:
      DCHECK_EQ(state_, ON_OUTBOUND_QUEUE);
      break;
    case TIMED_OUT:
      DCHECK(state_ == SENT || state_ == ON_OUTBOUND_QUEUE);
      break;
    case FINISHED_SUCCESS:
      DCHECK_EQ(state_, SENT);
      break;
    default:
      // No sanity checks for others.
      break;
  }

  state_ = new_state;
}

void OutboundCall::CallCallback() {
  callback_();
}

void OutboundCall::SetResponse(gscoped_ptr<CallResponse> resp) {
  Slice r(resp->serialized_response());

  if (resp->is_success()) {

    // TODO: here we're deserializing the call response within the reactor thread,
    // which isn't great, since it would block processing of other RPCs in parallel.
    // Should look into a way to avoid this.
    if (!response_->ParseFromArray(r.data(), r.size())) {
      SetFailed(Status::IOError("Invalid response, missing fields",
                                response_->InitializationErrorString()));
      return;
    }
    set_state(FINISHED_SUCCESS);
    CallCallback();
  } else {
    // Error
    gscoped_ptr<ErrorStatusPB> err(new ErrorStatusPB());
    if (!err->ParseFromArray(r.data(), r.size())) {
      SetFailed(Status::IOError("Was an RPC error but could not parse error response",
                                err->InitializationErrorString()));
      return;
    }
    ErrorStatusPB* err_raw = err.release();
    SetFailed(Status::RemoteError(err_raw->message()), err_raw);
  }
}

void OutboundCall::SetQueued() {
  set_state(ON_OUTBOUND_QUEUE);
}

void OutboundCall::SetSent() {
  set_state(SENT);

  // This method is called in the reactor thread, so free the header buf,
  // which was also allocated from this thread. tcmalloc's thread caching
  // behavior is a lot more efficient if memory is freed from the same thread
  // which allocated it -- this lets it keep to thread-local operations instead
  // of taking a mutex to put memory back on the global freelist.
  delete [] header_buf_.release();

  // request_buf_ is also done being used here, but since it was allocated by
  // the caller thread, we would rather let that thread free it whenever it
  // deletes the RpcController.
}

void OutboundCall::SetFailed(const Status &status,
                             ErrorStatusPB* err_pb) {
  {
    lock_guard<simple_spinlock> l(&lock_);
    status_ = status;
    if (status_.IsRemoteError()) {
      CHECK(err_pb);
      error_pb_.reset(err_pb);
    } else {
      CHECK(!err_pb);
    }
    set_state_unlocked(FINISHED_ERROR);
  }
  CallCallback();
}

void OutboundCall::SetTimedOut() {
  {
    lock_guard<simple_spinlock> l(&lock_);
    // TODO: have a better error message which includes the call timeout,
    // remote host, how long it spent in the queue, other useful stuff.
    status_ = Status::TimedOut("Call timed out");
    set_state_unlocked(TIMED_OUT);
  }
  CallCallback();
}

bool OutboundCall::IsTimedOut() const {
  lock_guard<simple_spinlock> l(&lock_);
  return state_ == TIMED_OUT;
}

bool OutboundCall::IsFinished() const {
  lock_guard<simple_spinlock> l(&lock_);
  switch (state_) {
    case READY:
    case ON_OUTBOUND_QUEUE:
    case SENT:
      return false;
    case TIMED_OUT:
    case FINISHED_ERROR:
    case FINISHED_SUCCESS:
      return true;
    default:
      LOG(FATAL) << "Unknown call state: " << state_;
      return false;
  }
}

string OutboundCall::ToString() const {
  return Substitute("RPC call $0 -> $1",
                      method(), conn_id_.ToString());
}

void OutboundCall::DumpPB(const DumpRunningRpcsRequestPB& req,
                          RpcCallInProgressPB* resp) {
  lock_guard<simple_spinlock> l(&lock_);
  resp->mutable_header()->CopyFrom(header_);
  resp->set_micros_elapsed(
    MonoTime::Now(MonoTime::FINE) .GetDeltaSince(start_time_).ToMicroseconds());
}

///
/// UserCredentials
///

UserCredentials::UserCredentials() {}

bool UserCredentials::has_effective_user() const {
  return !eff_user_.empty();
}

void UserCredentials::set_effective_user(const string& eff_user) {
  eff_user_ = eff_user;
}

bool UserCredentials::has_real_user() const {
  return !real_user_.empty();
}

void UserCredentials::set_real_user(const string& real_user) {
  real_user_ = real_user;
}

bool UserCredentials::has_password() const {
  return !password_.empty();
}

void UserCredentials::set_password(const string& password) {
  password_ = password;
}

void UserCredentials::CopyFrom(const UserCredentials& other) {
  eff_user_ = other.eff_user_;
  real_user_ = other.real_user_;
  password_ = other.password_;
}

string UserCredentials::ToString() const {
  // Does not print the password.
  return StringPrintf("{real_user=%s, eff_user=%s}", real_user_.c_str(), eff_user_.c_str());
}

size_t UserCredentials::HashCode() const {
  size_t seed = 0;
  if (has_effective_user()) {
    boost::hash_combine(seed, effective_user());
  }
  if (has_real_user()) {
    boost::hash_combine(seed, real_user());
  }
  if (has_password()) {
    boost::hash_combine(seed, password());
  }
  return seed;
}

bool UserCredentials::Equals(const UserCredentials& other) const {
  return (effective_user() == other.effective_user()
       && real_user() == other.real_user()
       && password() == other.password());
}

///
/// ConnectionId
///

ConnectionId::ConnectionId() {}

ConnectionId::ConnectionId(const ConnectionId& other) {
  DoCopyFrom(other);
}

ConnectionId::ConnectionId(const Sockaddr& remote, const string& service_name,
                           const UserCredentials& user_credentials) {
  remote_ = remote;
  service_name_ = service_name;
  user_credentials_.CopyFrom(user_credentials);
}

void ConnectionId::set_remote(const Sockaddr& remote) {
  remote_ = remote;
}

void ConnectionId::set_service_name(const string& service_name) {
  service_name_ = service_name;
}

void ConnectionId::set_user_credentials(const UserCredentials& user_credentials) {
  user_credentials_.CopyFrom(user_credentials);
}

void ConnectionId::CopyFrom(const ConnectionId& other) {
  DoCopyFrom(other);
}

string ConnectionId::ToString() const {
  // Does not print the password.
  return StringPrintf("{remote=%s, service_name=%s, user_credentials=%s}",
      remote_.ToString().c_str(), service_name_.c_str(),
      user_credentials_.ToString().c_str());
}

void ConnectionId::DoCopyFrom(const ConnectionId& other) {
  remote_ = other.remote_;
  service_name_ = other.service_name_;
  user_credentials_.CopyFrom(other.user_credentials_);
}

size_t ConnectionId::HashCode() const {
  size_t seed = 0;
  boost::hash_combine(seed, remote_.HashCode());
  boost::hash_combine(seed, service_name_);
  boost::hash_combine(seed, user_credentials_.HashCode());
  return seed;
}

bool ConnectionId::Equals(const ConnectionId& other) const {
  return (remote() == other.remote()
       && service_name() == other.service_name()
       && user_credentials().Equals(other.user_credentials()));
}

size_t ConnectionIdHash::operator() (const ConnectionId& conn_id) const {
  return conn_id.HashCode();
}

bool ConnectionIdEqual::operator() (const ConnectionId& cid1, const ConnectionId& cid2) const {
  return cid1.Equals(cid2);
}

///
/// CallResponse
///

CallResponse::CallResponse()
 : parsed_(false) {
}

Status CallResponse::ParseFrom(gscoped_ptr<InboundTransfer> transfer) {
  CHECK(!parsed_);
  RETURN_NOT_OK(serialization::ParseMessage(transfer->data(), &header_, &serialized_response_));
  transfer_.swap(transfer);
  parsed_ = true;
  return Status::OK();
}

} // namespace rpc
} // namespace kudu
<commit_msg>Handle null timeout case in OutboundCall DVLOG(4)<commit_after>// Copyright (c) 2013, Cloudera, inc.
// Confidential Cloudera Information: Covered by NDA.
// All rights reserved.

#include <string>
#include <vector>
#include <boost/functional/hash.hpp>

#include "kudu/gutil/strings/substitute.h"
#include "kudu/rpc/outbound_call.h"
#include "kudu/rpc/constants.h"
#include "kudu/rpc/rpc_controller.h"
#include "kudu/rpc/rpc_introspection.pb.h"
#include "kudu/rpc/serialization.h"
#include "kudu/rpc/transfer.h"

namespace kudu {
namespace rpc {

using strings::Substitute;
using google::protobuf::Message;
using google::protobuf::io::CodedOutputStream;

///
/// OutboundCall
///

OutboundCall::OutboundCall(const ConnectionId& conn_id,
                           const string& method,
                           google::protobuf::Message* response_storage,
                           RpcController* controller,
                           const ResponseCallback& callback)
  : state_(READY),
    conn_id_(conn_id),
    callback_(callback),
    controller_(DCHECK_NOTNULL(controller)),
    response_(DCHECK_NOTNULL(response_storage)) {
  DVLOG(4) << "OutboundCall " << this << " constructed with state_: " << StateName(state_)
           << " and RPC timeout: "
           << (controller->timeout().Initialized() ? controller->timeout().ToString() : "none");
  header_.set_method_name(method);
  header_.set_call_id(kInvalidCallId);
  start_time_ = MonoTime::Now(MonoTime::FINE);
}

OutboundCall::~OutboundCall() {
  DCHECK(IsFinished());
  DVLOG(4) << "OutboundCall " << this << " destroyed with state_: " << StateName(state_);
}

Status OutboundCall::SerializeTo(vector<Slice>* slices) {
  size_t param_len = request_buf_.size();
  if (PREDICT_FALSE(param_len == 0)) {
    return Status::InvalidArgument("Must call SetRequestParam() before SerializeTo()");
  }

  const MonoDelta &timeout = controller_->timeout();
  if (timeout.Initialized()) {
    header_.set_timeout_millis(timeout.ToMilliseconds());
  }

  CHECK_OK(serialization::SerializeHeader(header_, param_len, &header_buf_));

  // Return the concatenated packet.
  slices->push_back(Slice(header_buf_));
  slices->push_back(Slice(request_buf_));
  return Status::OK();
}

Status OutboundCall::SetRequestParam(const Message& message) {
  return serialization::SerializeMessage(message, &request_buf_);
}

Status OutboundCall::status() const {
  lock_guard<simple_spinlock> l(&lock_);
  return status_;
}

const ErrorStatusPB* OutboundCall::error_pb() const {
  lock_guard<simple_spinlock> l(&lock_);
  return error_pb_.get();
}

string OutboundCall::StateName(State state) {
  switch (state) {
    case READY:
      return "READY";
    case ON_OUTBOUND_QUEUE:
      return "ON_OUTBOUND_QUEUE";
    case SENT:
      return "SENT";
    case TIMED_OUT:
      return "TIMED_OUT";
    case FINISHED_ERROR:
      return "FINISHED_ERROR";
    case FINISHED_SUCCESS:
      return "FINISHED_SUCCESS";
    default:
      LOG(DFATAL) << "Unknown state in OutboundCall: " << state;
      return StringPrintf("UNKNOWN(%d)", state);
  }
}

void OutboundCall::set_state(State new_state) {
  lock_guard<simple_spinlock> l(&lock_);
  set_state_unlocked(new_state);
}

OutboundCall::State OutboundCall::state() const {
  lock_guard<simple_spinlock> l(&lock_);
  return state_;
}

void OutboundCall::set_state_unlocked(State new_state) {
  // Sanity check state transitions.
  DVLOG(3) << "OutboundCall " << this << " (" << ToString() << ") switching from " <<
    StateName(state_) << " to " << StateName(new_state);
  switch (new_state) {
    case ON_OUTBOUND_QUEUE:
      DCHECK_EQ(state_, READY);
      break;
    case SENT:
      DCHECK_EQ(state_, ON_OUTBOUND_QUEUE);
      break;
    case TIMED_OUT:
      DCHECK(state_ == SENT || state_ == ON_OUTBOUND_QUEUE);
      break;
    case FINISHED_SUCCESS:
      DCHECK_EQ(state_, SENT);
      break;
    default:
      // No sanity checks for others.
      break;
  }

  state_ = new_state;
}

void OutboundCall::CallCallback() {
  callback_();
}

void OutboundCall::SetResponse(gscoped_ptr<CallResponse> resp) {
  Slice r(resp->serialized_response());

  if (resp->is_success()) {

    // TODO: here we're deserializing the call response within the reactor thread,
    // which isn't great, since it would block processing of other RPCs in parallel.
    // Should look into a way to avoid this.
    if (!response_->ParseFromArray(r.data(), r.size())) {
      SetFailed(Status::IOError("Invalid response, missing fields",
                                response_->InitializationErrorString()));
      return;
    }
    set_state(FINISHED_SUCCESS);
    CallCallback();
  } else {
    // Error
    gscoped_ptr<ErrorStatusPB> err(new ErrorStatusPB());
    if (!err->ParseFromArray(r.data(), r.size())) {
      SetFailed(Status::IOError("Was an RPC error but could not parse error response",
                                err->InitializationErrorString()));
      return;
    }
    ErrorStatusPB* err_raw = err.release();
    SetFailed(Status::RemoteError(err_raw->message()), err_raw);
  }
}

void OutboundCall::SetQueued() {
  set_state(ON_OUTBOUND_QUEUE);
}

void OutboundCall::SetSent() {
  set_state(SENT);

  // This method is called in the reactor thread, so free the header buf,
  // which was also allocated from this thread. tcmalloc's thread caching
  // behavior is a lot more efficient if memory is freed from the same thread
  // which allocated it -- this lets it keep to thread-local operations instead
  // of taking a mutex to put memory back on the global freelist.
  delete [] header_buf_.release();

  // request_buf_ is also done being used here, but since it was allocated by
  // the caller thread, we would rather let that thread free it whenever it
  // deletes the RpcController.
}

void OutboundCall::SetFailed(const Status &status,
                             ErrorStatusPB* err_pb) {
  {
    lock_guard<simple_spinlock> l(&lock_);
    status_ = status;
    if (status_.IsRemoteError()) {
      CHECK(err_pb);
      error_pb_.reset(err_pb);
    } else {
      CHECK(!err_pb);
    }
    set_state_unlocked(FINISHED_ERROR);
  }
  CallCallback();
}

void OutboundCall::SetTimedOut() {
  {
    lock_guard<simple_spinlock> l(&lock_);
    // TODO: have a better error message which includes the call timeout,
    // remote host, how long it spent in the queue, other useful stuff.
    status_ = Status::TimedOut("Call timed out");
    set_state_unlocked(TIMED_OUT);
  }
  CallCallback();
}

bool OutboundCall::IsTimedOut() const {
  lock_guard<simple_spinlock> l(&lock_);
  return state_ == TIMED_OUT;
}

bool OutboundCall::IsFinished() const {
  lock_guard<simple_spinlock> l(&lock_);
  switch (state_) {
    case READY:
    case ON_OUTBOUND_QUEUE:
    case SENT:
      return false;
    case TIMED_OUT:
    case FINISHED_ERROR:
    case FINISHED_SUCCESS:
      return true;
    default:
      LOG(FATAL) << "Unknown call state: " << state_;
      return false;
  }
}

string OutboundCall::ToString() const {
  return Substitute("RPC call $0 -> $1",
                      method(), conn_id_.ToString());
}

void OutboundCall::DumpPB(const DumpRunningRpcsRequestPB& req,
                          RpcCallInProgressPB* resp) {
  lock_guard<simple_spinlock> l(&lock_);
  resp->mutable_header()->CopyFrom(header_);
  resp->set_micros_elapsed(
    MonoTime::Now(MonoTime::FINE) .GetDeltaSince(start_time_).ToMicroseconds());
}

///
/// UserCredentials
///

UserCredentials::UserCredentials() {}

bool UserCredentials::has_effective_user() const {
  return !eff_user_.empty();
}

void UserCredentials::set_effective_user(const string& eff_user) {
  eff_user_ = eff_user;
}

bool UserCredentials::has_real_user() const {
  return !real_user_.empty();
}

void UserCredentials::set_real_user(const string& real_user) {
  real_user_ = real_user;
}

bool UserCredentials::has_password() const {
  return !password_.empty();
}

void UserCredentials::set_password(const string& password) {
  password_ = password;
}

void UserCredentials::CopyFrom(const UserCredentials& other) {
  eff_user_ = other.eff_user_;
  real_user_ = other.real_user_;
  password_ = other.password_;
}

string UserCredentials::ToString() const {
  // Does not print the password.
  return StringPrintf("{real_user=%s, eff_user=%s}", real_user_.c_str(), eff_user_.c_str());
}

size_t UserCredentials::HashCode() const {
  size_t seed = 0;
  if (has_effective_user()) {
    boost::hash_combine(seed, effective_user());
  }
  if (has_real_user()) {
    boost::hash_combine(seed, real_user());
  }
  if (has_password()) {
    boost::hash_combine(seed, password());
  }
  return seed;
}

bool UserCredentials::Equals(const UserCredentials& other) const {
  return (effective_user() == other.effective_user()
       && real_user() == other.real_user()
       && password() == other.password());
}

///
/// ConnectionId
///

ConnectionId::ConnectionId() {}

ConnectionId::ConnectionId(const ConnectionId& other) {
  DoCopyFrom(other);
}

ConnectionId::ConnectionId(const Sockaddr& remote, const string& service_name,
                           const UserCredentials& user_credentials) {
  remote_ = remote;
  service_name_ = service_name;
  user_credentials_.CopyFrom(user_credentials);
}

void ConnectionId::set_remote(const Sockaddr& remote) {
  remote_ = remote;
}

void ConnectionId::set_service_name(const string& service_name) {
  service_name_ = service_name;
}

void ConnectionId::set_user_credentials(const UserCredentials& user_credentials) {
  user_credentials_.CopyFrom(user_credentials);
}

void ConnectionId::CopyFrom(const ConnectionId& other) {
  DoCopyFrom(other);
}

string ConnectionId::ToString() const {
  // Does not print the password.
  return StringPrintf("{remote=%s, service_name=%s, user_credentials=%s}",
      remote_.ToString().c_str(), service_name_.c_str(),
      user_credentials_.ToString().c_str());
}

void ConnectionId::DoCopyFrom(const ConnectionId& other) {
  remote_ = other.remote_;
  service_name_ = other.service_name_;
  user_credentials_.CopyFrom(other.user_credentials_);
}

size_t ConnectionId::HashCode() const {
  size_t seed = 0;
  boost::hash_combine(seed, remote_.HashCode());
  boost::hash_combine(seed, service_name_);
  boost::hash_combine(seed, user_credentials_.HashCode());
  return seed;
}

bool ConnectionId::Equals(const ConnectionId& other) const {
  return (remote() == other.remote()
       && service_name() == other.service_name()
       && user_credentials().Equals(other.user_credentials()));
}

size_t ConnectionIdHash::operator() (const ConnectionId& conn_id) const {
  return conn_id.HashCode();
}

bool ConnectionIdEqual::operator() (const ConnectionId& cid1, const ConnectionId& cid2) const {
  return cid1.Equals(cid2);
}

///
/// CallResponse
///

CallResponse::CallResponse()
 : parsed_(false) {
}

Status CallResponse::ParseFrom(gscoped_ptr<InboundTransfer> transfer) {
  CHECK(!parsed_);
  RETURN_NOT_OK(serialization::ParseMessage(transfer->data(), &header_, &serialized_response_));
  transfer_.swap(transfer);
  parsed_ = true;
  return Status::OK();
}

} // namespace rpc
} // namespace kudu
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_adu_access.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//--------------------------------------------------------------------------
//
//
/// @file p9_adu_access.C
/// @brief Read coherent state of memory via the ADU (FAPI)
///
// *HWP HWP Owner Christina Graves clgraves@us.ibm.com
// *HWP FW Owner: Thi Tran thi@us.ibm.com
// *HWP Team: Nest
// *HWP Level: 2
// *HWP Consumed by: SBE
//
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------------
#include <p9_adu_access.H>
#include <p9_adu_coherent_utils.H>

extern "C" {

//--------------------------------------------------------------------------
//  HWP entry point
//--------------------------------------------------------------------------
    fapi2::ReturnCode p9_adu_access(const
                                    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
                                    const uint64_t i_address,
                                    const bool i_rnw,
                                    const uint32_t i_flags,
                                    const bool i_firstGranule,
                                    const bool i_lastGranule,
                                    uint8_t io_data[])
    {

        bool l_busyBitStatus = false;
        adu_status_busy_handler l_busyHandling;

        // mark HWP entry
        FAPI_DBG("Entering ...\n");

        // Process input flag
        p9_ADU_oper_flag l_myAduFlag;
        l_myAduFlag.getFlag(i_flags);

        if( i_lastGranule && l_myAduFlag.getAutoIncrement() )
        {
            //call this function to clear the altd_auto_inc bit before the last iteration
            FAPI_TRY(p9_adu_coherent_clear_autoinc(i_target), "Error from p9_adu_coherent_clear_autoinc");
        }

        if (i_rnw)
        {
            //read the data
            FAPI_TRY(p9_adu_coherent_adu_read(i_target, i_firstGranule, i_address, l_myAduFlag, io_data),
                     "Error from p9_adu_coherent_adu_read");
        }
        else
        {
            //write the data
            FAPI_TRY(p9_adu_coherent_adu_write(i_target, i_firstGranule, i_address, l_myAduFlag, io_data),
                     "Error from p9_adu_coherent_adu_write");
        }

        //If we are not in fastmode or this is the last granule, we want to check the status
        if ( (i_lastGranule) || (l_myAduFlag.getFastMode() == false) )
        {
            if ( (l_myAduFlag.getAutoIncrement()) && !i_lastGranule )
            {
                // Only expect ADU busy if in AUTOINC AND it's not the last granule
                l_busyHandling = EXPECTED_BUSY_BIT_SET;
            }
            else
            {
                l_busyHandling = EXPECTED_BUSY_BIT_CLEAR;
            }

            FAPI_TRY(p9_adu_coherent_status_check(i_target, l_busyHandling, false,
                                                  l_busyBitStatus),
                     "Error from p9_adu_coherent_status_check");

            //If it's the last read/write
            if (i_lastGranule)
            {
                FAPI_TRY(p9_adu_coherent_cleanup_adu(i_target),
                         "Error doing p9_adu_coherent_cleanup_adu");
            }
        }

    fapi_try_exit:

        if ( fapi2::current_err && l_myAduFlag.getOperFailCleanup() )
        {
            (void) p9_adu_coherent_utils_reset_adu(i_target);
            uint32_t num_attempts = l_myAduFlag.getNumLockAttempts();
            (void) p9_adu_coherent_manage_lock(i_target, false, false, num_attempts);
        }

        FAPI_DBG("Exiting...");
        return fapi2::current_err;
    }

} // extern "C"
<commit_msg>Changes in error handling to stop the read/write as soon as an error occurs<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_adu_access.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//--------------------------------------------------------------------------
//
//
/// @file p9_adu_access.C
/// @brief Read coherent state of memory via the ADU (FAPI)
///
// *HWP HWP Owner Christina Graves clgraves@us.ibm.com
// *HWP FW Owner: Thi Tran thi@us.ibm.com
// *HWP Team: Nest
// *HWP Level: 2
// *HWP Consumed by: SBE
//
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------------
#include <p9_adu_access.H>
#include <p9_adu_coherent_utils.H>

extern "C" {

//--------------------------------------------------------------------------
//  HWP entry point
//--------------------------------------------------------------------------
    fapi2::ReturnCode p9_adu_access(const
                                    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
                                    const uint64_t i_address,
                                    const bool i_rnw,
                                    const uint32_t i_flags,
                                    const bool i_firstGranule,
                                    const bool i_lastGranule,
                                    uint8_t io_data[])
    {

        bool l_busyBitStatus = false;
        adu_status_busy_handler l_busyHandling;

        // mark HWP entry
        FAPI_DBG("Entering ...\n");

        // Process input flag
        p9_ADU_oper_flag l_myAduFlag;
        l_myAduFlag.getFlag(i_flags);

        if( i_lastGranule && l_myAduFlag.getAutoIncrement() )
        {
            //call this function to clear the altd_auto_inc bit before the last iteration
            FAPI_TRY(p9_adu_coherent_clear_autoinc(i_target), "Error from p9_adu_coherent_clear_autoinc");
        }

        if (i_rnw)
        {
            //read the data
            FAPI_TRY(p9_adu_coherent_adu_read(i_target, i_firstGranule, i_address, l_myAduFlag, io_data),
                     "Error from p9_adu_coherent_adu_read");
        }
        else
        {
            //write the data
            FAPI_TRY(p9_adu_coherent_adu_write(i_target, i_firstGranule, i_address, l_myAduFlag, io_data),
                     "Error from p9_adu_coherent_adu_write");
        }

        //If we are not in fastmode or this is the last granule, we want to check the status
        if ( (i_lastGranule) || (l_myAduFlag.getFastMode() == false) )
        {
            if ( (l_myAduFlag.getAutoIncrement()) && !i_lastGranule )
            {
                // Only expect ADU busy if in AUTOINC AND it's not the last granule
                l_busyHandling = EXPECTED_BUSY_BIT_SET;
            }
            else
            {
                l_busyHandling = EXPECTED_BUSY_BIT_CLEAR;
            }

            FAPI_TRY(p9_adu_coherent_status_check(i_target, l_busyHandling, false,
                                                  l_busyBitStatus),
                     "Error from p9_adu_coherent_status_check");

            //If it's the last read/write
            if (i_lastGranule)
            {
                FAPI_TRY(p9_adu_coherent_cleanup_adu(i_target),
                         "Error doing p9_adu_coherent_cleanup_adu");
            }
        }

    fapi_try_exit:
        fapi2::ReturnCode saveError = fapi2::current_err;

        if ( fapi2::current_err && l_myAduFlag.getOperFailCleanup() )
        {
            (void) p9_adu_coherent_utils_reset_adu(i_target);
            uint32_t num_attempts = l_myAduFlag.getNumLockAttempts();
            (void) p9_adu_coherent_manage_lock(i_target, false, false, num_attempts);
        }

        FAPI_DBG("Exiting...");
        return saveError;
    }

} // extern "C"
<|endoftext|>


<commit_before>// Copyright 2016 Tom Barthel-Steer
// http://www.tomsteer.net
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "nicselectdialog.h"
#include "ui_nicselectdialog.h"
#include <QNetworkInterface>

NICSelectDialog::NICSelectDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::NICSelectDialog)
{
    ui->setupUi(this);
    m_selectedInterface = QNetworkInterface();

    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();

    foreach(QNetworkInterface interface, interfaces)
    {
        bool ok = false;
        // We want interfaces which are IPv4 and can multicast
        QString ipString;
        foreach (QNetworkAddressEntry e, interface.addressEntries()) {
            if(!ipString.isEmpty())
                ipString.append(",");
            ipString.append(e.ip().toString());
            if(e.ip().protocol() == QAbstractSocket::IPv4Protocol)
               ok = true;
        }
        ok = ok & (interface.flags() | QNetworkInterface::CanMulticast);

        if(ok)
        {
            ui->listWidget->addItem(QString("%1 (%2)")
                                    .arg(interface.humanReadableName())
                                    .arg(ipString));

            m_interfaceList << interface;
        }
    }

    ui->btnSelect->setEnabled(false);
}

NICSelectDialog::~NICSelectDialog()
{
    delete ui;
}

void NICSelectDialog::on_listWidget_itemSelectionChanged()
{
    ui->btnSelect->setEnabled(true);
}

void NICSelectDialog::on_btnSelect_pressed()
{
    m_selectedInterface = m_interfaceList[ui->listWidget->currentRow()];
    accept();
}

void NICSelectDialog::on_btnWorkOffline_pressed()
{
    reject();
}
<commit_msg>Fixed another compiler warning re: unsafe use of flags and boolean<commit_after>// Copyright 2016 Tom Barthel-Steer
// http://www.tomsteer.net
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "nicselectdialog.h"
#include "ui_nicselectdialog.h"
#include <QNetworkInterface>

NICSelectDialog::NICSelectDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::NICSelectDialog)
{
    ui->setupUi(this);
    m_selectedInterface = QNetworkInterface();

    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();

    foreach(QNetworkInterface interface, interfaces)
    {
        bool ok = false;
        // We want interfaces which are IPv4 and can multicast
        QString ipString;
        foreach (QNetworkAddressEntry e, interface.addressEntries()) {
            if(!ipString.isEmpty())
                ipString.append(",");
            ipString.append(e.ip().toString());
            if(e.ip().protocol() == QAbstractSocket::IPv4Protocol)
               ok = true;
        }
        ok = ok & (bool)(interface.flags() | QNetworkInterface::CanMulticast);

        if(ok)
        {
            ui->listWidget->addItem(QString("%1 (%2)")
                                    .arg(interface.humanReadableName())
                                    .arg(ipString));

            m_interfaceList << interface;
        }
    }

    ui->btnSelect->setEnabled(false);
}

NICSelectDialog::~NICSelectDialog()
{
    delete ui;
}

void NICSelectDialog::on_listWidget_itemSelectionChanged()
{
    ui->btnSelect->setEnabled(true);
}

void NICSelectDialog::on_btnSelect_pressed()
{
    m_selectedInterface = m_interfaceList[ui->listWidget->currentRow()];
    accept();
}

void NICSelectDialog::on_btnWorkOffline_pressed()
{
    reject();
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

      if (p.is_all_zeros()) return "Unknown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>added MooPolice client identification<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		. map_emtry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

      if (p.is_all_zeros()) return "Unknown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>