<commit_before>//
// OpenThread library, Copyright (C) 2002 - 2003  The Open Thread Group
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//
// Win32Barrier.c++ - C++ Barrier class built on top of POSIX threads.
// ~~~~~~~~~~~~~~~~~~
//

#include  <OpenThreads/Barrier>
#include  <OpenThreads/Thread>
#include  <OpenThreads/ScopedLock>
#include "Win32BarrierPrivateData.h"
using namespace OpenThreads;

// so compiler can place it somewhere
Win32BarrierPrivateData::~Win32BarrierPrivateData()
{
};

//----------------------------------------------------------------------------
//
// Decription: Constructor
//
// Use: public.
//
Barrier::Barrier(int numThreads) {
    Win32BarrierPrivateData *pd = new Win32BarrierPrivateData();
    pd->cnt = 0;
    pd->phase = 0;
    pd->maxcnt = numThreads;
    _valid = true;
    _prvData = static_cast<void *>(pd);
}
//----------------------------------------------------------------------------
//
// Decription: Destructor
//
// Use: public.
//
Barrier::~Barrier() {
    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);
    delete pd;
}
//----------------------------------------------------------------------------
//
// Decription: Reset the barrier to its original state
//
// Use: public.
//
void Barrier::reset() {
    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);
    pd->cnt = 0;
    pd->phase = 0;
}
//----------------------------------------------------------------------------
//
// Decription: Block until numThreads threads have entered the barrier.
//
// Use: public.
//
void Barrier::block(unsigned int numThreads) {

    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);

    if(numThreads != 0) pd->maxcnt = numThreads;
    int my_phase;

    ScopedLock<Mutex> lock(pd->lock);
    if( _valid )
    {
        my_phase = pd->phase;
        ++pd->cnt;

        if (pd->cnt == pd->maxcnt) {             // I am the last one
		    pd->cnt = 0;                         // reset for next use
		    pd->phase = 1 - my_phase;            // toggle phase
		    pd->cond.broadcast();
        }else{
		    while (pd->phase == my_phase ) {
			    pd->cond.wait(&pd->lock);
		    }
	    }
    }
}

void Barrier::invalidate()
{
    Win32BarrierPrivateData *pd =
            static_cast<Win32BarrierPrivateData*>(_prvData);

	pd->lock.lock();
	_valid = false;
	pd->lock.unlock();
	release();
}

//----------------------------------------------------------------------------
//
// Description: Release the barrier, now.
//
// Use: public.
//
void Barrier::release() {

    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);

    int my_phase;

    ScopedLock<Mutex> lock(pd->lock);
    my_phase = pd->phase;

    pd->cnt = 0;                         // reset for next use
    pd->phase = 1 - my_phase;            // toggle phase
    pd->cond.broadcast();

}

//----------------------------------------------------------------------------
//
// Description: Return the number of threads currently blocked in the barrier
//
// Use: public
//
int Barrier::numThreadsCurrentlyBlocked() {

    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);

    int numBlocked = -1;
    ScopedLock<Mutex> lock(pd->lock);
    numBlocked = pd->cnt;
    ScopedLock<Mutex> unlock(pd->lock);
    return numBlocked;

}
<commit_msg>removed extra ScopedLock<commit_after>//
// OpenThread library, Copyright (C) 2002 - 2003  The Open Thread Group
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//
// Win32Barrier.c++ - C++ Barrier class built on top of POSIX threads.
// ~~~~~~~~~~~~~~~~~~
//

#include  <OpenThreads/Barrier>
#include  <OpenThreads/Thread>
#include  <OpenThreads/ScopedLock>
#include "Win32BarrierPrivateData.h"
using namespace OpenThreads;

// so compiler can place it somewhere
Win32BarrierPrivateData::~Win32BarrierPrivateData()
{
};

//----------------------------------------------------------------------------
//
// Decription: Constructor
//
// Use: public.
//
Barrier::Barrier(int numThreads) {
    Win32BarrierPrivateData *pd = new Win32BarrierPrivateData();
    pd->cnt = 0;
    pd->phase = 0;
    pd->maxcnt = numThreads;
    _valid = true;
    _prvData = static_cast<void *>(pd);
}
//----------------------------------------------------------------------------
//
// Decription: Destructor
//
// Use: public.
//
Barrier::~Barrier() {
    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);
    delete pd;
}
//----------------------------------------------------------------------------
//
// Decription: Reset the barrier to its original state
//
// Use: public.
//
void Barrier::reset() {
    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);
    pd->cnt = 0;
    pd->phase = 0;
}
//----------------------------------------------------------------------------
//
// Decription: Block until numThreads threads have entered the barrier.
//
// Use: public.
//
void Barrier::block(unsigned int numThreads) {

    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);

    if(numThreads != 0) pd->maxcnt = numThreads;
    int my_phase;

    ScopedLock<Mutex> lock(pd->lock);
    if( _valid )
    {
        my_phase = pd->phase;
        ++pd->cnt;

        if (pd->cnt == pd->maxcnt) {             // I am the last one
		    pd->cnt = 0;                         // reset for next use
		    pd->phase = 1 - my_phase;            // toggle phase
		    pd->cond.broadcast();
        }else{
		    while (pd->phase == my_phase ) {
			    pd->cond.wait(&pd->lock);
		    }
	    }
    }
}

void Barrier::invalidate()
{
    Win32BarrierPrivateData *pd =
            static_cast<Win32BarrierPrivateData*>(_prvData);

	pd->lock.lock();
	_valid = false;
	pd->lock.unlock();
	release();
}

//----------------------------------------------------------------------------
//
// Description: Release the barrier, now.
//
// Use: public.
//
void Barrier::release() {

    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);

    int my_phase;

    ScopedLock<Mutex> lock(pd->lock);
    my_phase = pd->phase;

    pd->cnt = 0;                         // reset for next use
    pd->phase = 1 - my_phase;            // toggle phase
    pd->cond.broadcast();

}

//----------------------------------------------------------------------------
//
// Description: Return the number of threads currently blocked in the barrier
//
// Use: public
//
int Barrier::numThreadsCurrentlyBlocked() {

    Win32BarrierPrivateData *pd =
        static_cast<Win32BarrierPrivateData*>(_prvData);

    int numBlocked = -1;
    ScopedLock<Mutex> lock(pd->lock);
    numBlocked = pd->cnt;
    return numBlocked;

}
<|endoftext|>


<commit_before>#include "AliRun.h"
#include "AliRunLoader.h"

#include "AliVZEROTrigger.h"

//______________________________________________________________________
ClassImp(AliVZEROTrigger)
////////////////////////////////////////////////////////////////////////
//
// Version 1
//
// AliVZEROTrigger:
//
////////////////////////////////////////////////////////////////////////

//______________________________________________________________________
AliVZEROTrigger::AliVZEROTrigger()
  :AliTriggerDetector(),
   fAdcThresHold(0.0),
   fTimeWindowWidth(50.0)

{
   SetName("VZERO");
   CreateInputs();

   SetAdcThreshold();
   SetTimeWindowWidth();
}

//______________________________________________________________________
void AliVZEROTrigger::CreateInputs()
{
   // inputs

   // Do not create inputs again!!
   if( fInputs.GetEntriesFast() > 0 ) return;

   fInputs.AddLast( new AliTriggerInput( "VZERO_LEFT", "At least one hit in the left VZERO", 0x01 ) );
   fInputs.AddLast( new AliTriggerInput( "VZERO_RIGHT","At least one hit in the right VZERO", 0x02 ) );
   fInputs.AddLast( new AliTriggerInput( "VZERO_AND",  "At least one hit in the each (left and right) VZERO", 0x04 ) );
   fInputs.AddLast( new AliTriggerInput( "VZERO_OR",   "At least one hit in the one (left one right) VZERO", 0x08 ) );

   fInputs.AddLast( new AliTriggerInput( "VZERO_BEAMGAS", "Beam gas VZERO trigger ", 0x010 ) );
}

//______________________________________________________________________
void AliVZEROTrigger::Trigger()
{

  //  ********** Get run loader for the current event **********
  AliRunLoader* runLoader = gAlice->GetRunLoader();

  AliVZEROLoader* loader = (AliVZEROLoader* )runLoader->GetLoader( "VZEROLoader" );

  loader->LoadDigits("READ");
  TTree* vzeroDigitsTree = loader->TreeD();
  if (!vzeroDigitsTree) return;

  TClonesArray* vzeroDigits = new TClonesArray("AliVZEROdigit",1000);
  TBranch* digitBranch = vzeroDigitsTree->GetBranch("VZERODigit");
  digitBranch->SetAddress(&vzeroDigits);

  // number of hits in left/right
  Int_t nLeftDig  = 0;
  Int_t nRightDig = 0;

  // first time
  Float_t firstTimeLeft  = 9999.0;
  Float_t firstTimeRight = 9999.0;
  Float_t TimeHalfWidth  = fTimeWindowWidth/2.0;

  printf(" Window V0C = %f %f \n", 30.0-TimeHalfWidth,  30.0+TimeHalfWidth );
  printf(" Window V0A = %f %f \n", 114.0-TimeHalfWidth, 114.0+TimeHalfWidth);

  // loop over vzero entries
  Int_t nEntries = (Int_t)vzeroDigitsTree->GetEntries();
  for (Int_t e=0; e<nEntries; e++) {
    vzeroDigitsTree->GetEvent(e);

    Int_t nDigits = vzeroDigits->GetEntriesFast();

    for (Int_t d=0; d<nDigits; d++) {
      //      vzeroDigitsTree->GetEvent(d);
      AliVZEROdigit* digit = (AliVZEROdigit*)vzeroDigits->At(d);

      Int_t   PMNumber   = digit->PMNumber();
      Float_t adc        = digit->ADC();
      Float_t tdc        = digit->Time(); // in 100 of picoseconds

      if (PMNumber<=31 && adc>fAdcThresHold) {
        printf(" Time  V0C = %f \n", tdc );
	if (tdc>(30.0-TimeHalfWidth) && tdc<(30.0+TimeHalfWidth)) nRightDig++;
//        nRightDig++;
	if (tdc<firstTimeRight) firstTimeRight = tdc;
      }
      if (PMNumber>=32 && adc>fAdcThresHold) {
        printf(" Time  V0A = %f \n", tdc );
	if (tdc>(114.0-TimeHalfWidth) && tdc<(114.0+TimeHalfWidth)) nLeftDig++;
//        nLeftDig++;
	if (tdc<firstTimeLeft) firstTimeLeft = tdc;
      }

    } // end of loop over digits
  } // end of loop over events in digits tree

  // Beam gas trigger set from the time difference. The time it takes
  // to travel between the two counters is ~14.3 ns = 143 * 100 ps.
  //  NB: this should be defined
  // from time windows relative to the time of the bunch crossing!
  // beam gas comming from the left ...

  if (TMath::Abs(TMath::Abs(firstTimeLeft - firstTimeRight)-143) < 20) // time window of 2 ns
    SetInput( "VZERO_BEAMGAS" );

  if (nLeftDig > 0)
      SetInput( "VZERO_LEFT" );

  if (nRightDig > 0)
      SetInput( "VZERO_RIGHT" );

  if (nLeftDig>0 || nRightDig>0) {
      SetInput( "VZERO_OR" );

    if (nLeftDig>0 && nRightDig>0) {
        SetInput( "VZERO_AND" );
    }
  }

//  AliDebug(1,Form("VZERO PMs fired: %d (left) %d (right)", nLeftDig, nRightDig));
  printf("%d %d \n", nLeftDig, nRightDig);

  return;
}

<commit_msg>Working prints removed<commit_after>#include "AliRun.h"
#include "AliRunLoader.h"

#include "AliVZEROTrigger.h"

//______________________________________________________________________
ClassImp(AliVZEROTrigger)
////////////////////////////////////////////////////////////////////////
//
// Version 1
//
// AliVZEROTrigger:
//
////////////////////////////////////////////////////////////////////////

//______________________________________________________________________
AliVZEROTrigger::AliVZEROTrigger()
  :AliTriggerDetector(),
   fAdcThresHold(0.0),
   fTimeWindowWidth(50.0)

{
   SetName("VZERO");
   CreateInputs();

   SetAdcThreshold();
   SetTimeWindowWidth();
}

//______________________________________________________________________
void AliVZEROTrigger::CreateInputs()
{
   // inputs

   // Do not create inputs again!!
   if( fInputs.GetEntriesFast() > 0 ) return;

   fInputs.AddLast( new AliTriggerInput( "VZERO_LEFT", "At least one hit in the left VZERO", 0x01 ) );
   fInputs.AddLast( new AliTriggerInput( "VZERO_RIGHT","At least one hit in the right VZERO", 0x02 ) );
   fInputs.AddLast( new AliTriggerInput( "VZERO_AND",  "At least one hit in the each (left and right) VZERO", 0x04 ) );
   fInputs.AddLast( new AliTriggerInput( "VZERO_OR",   "At least one hit in the one (left one right) VZERO", 0x08 ) );

   fInputs.AddLast( new AliTriggerInput( "VZERO_BEAMGAS", "Beam gas VZERO trigger ", 0x010 ) );
}

//______________________________________________________________________
void AliVZEROTrigger::Trigger()
{

  //  ********** Get run loader for the current event **********
  AliRunLoader* runLoader = gAlice->GetRunLoader();

  AliVZEROLoader* loader = (AliVZEROLoader* )runLoader->GetLoader( "VZEROLoader" );

  loader->LoadDigits("READ");
  TTree* vzeroDigitsTree = loader->TreeD();
  if (!vzeroDigitsTree) return;

  TClonesArray* vzeroDigits = new TClonesArray("AliVZEROdigit",1000);
  TBranch* digitBranch = vzeroDigitsTree->GetBranch("VZERODigit");
  digitBranch->SetAddress(&vzeroDigits);

  // number of hits in left/right
  Int_t nLeftDig  = 0;
  Int_t nRightDig = 0;

  // first time
  Float_t firstTimeLeft  = 9999.0;
  Float_t firstTimeRight = 9999.0;
  Float_t TimeHalfWidth  = fTimeWindowWidth/2.0;

  // loop over vzero entries
  Int_t nEntries = (Int_t)vzeroDigitsTree->GetEntries();
  for (Int_t e=0; e<nEntries; e++) {
    vzeroDigitsTree->GetEvent(e);

    Int_t nDigits = vzeroDigits->GetEntriesFast();

    for (Int_t d=0; d<nDigits; d++) {
      //      vzeroDigitsTree->GetEvent(d);
      AliVZEROdigit* digit = (AliVZEROdigit*)vzeroDigits->At(d);

      Int_t   PMNumber   = digit->PMNumber();
      Float_t adc        = digit->ADC();
      Float_t tdc        = digit->Time(); // in 100 of picoseconds

      if (PMNumber<=31 && adc>fAdcThresHold) {
	if (tdc>(30.0-TimeHalfWidth) && tdc<(30.0+TimeHalfWidth)) nRightDig++;
	if (tdc<firstTimeRight) firstTimeRight = tdc;
      }
      if (PMNumber>=32 && adc>fAdcThresHold) {
 	if (tdc>(114.0-TimeHalfWidth) && tdc<(114.0+TimeHalfWidth)) nLeftDig++;
	if (tdc<firstTimeLeft) firstTimeLeft = tdc;
      }

    } // end of loop over digits
  } // end of loop over events in digits tree

  // Beam gas trigger set from the time difference. The time it takes
  // to travel between the two counters is ~14.3 ns = 143 * 100 ps.
  //  NB: this should be defined
  // from time windows relative to the time of the bunch crossing!
  // beam gas comming from the left ...

  if (TMath::Abs(TMath::Abs(firstTimeLeft - firstTimeRight)-143) < 20) // time window of 2 ns
    SetInput( "VZERO_BEAMGAS" );

  if (nLeftDig > 0)
      SetInput( "VZERO_LEFT" );

  if (nRightDig > 0)
      SetInput( "VZERO_RIGHT" );

  if (nLeftDig>0 || nRightDig>0) {
      SetInput( "VZERO_OR" );

    if (nLeftDig>0 && nRightDig>0) {
        SetInput( "VZERO_AND" );
    }
  }

  AliDebug(1,Form("VZERO PMs fired: %d (left) %d (right)", nLeftDig, nRightDig));

  return;
}

<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/common/spd_access/gpio_adc_i2c_addr_get.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2020                        */
/* [+] 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 gpio_adc_i2c_addr_get.H
/// @brief Function to get GPIO/ADC i2c addresses given target REL_POS
///
// *HWP HWP Owner: Mark Pizzutillo <mark.pizzutillo@ibm.com>
// *HWP HWP Owner: Dan Crowell <dcrowell@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef __GPIO_ADC_I2C_ADDR_GET__
#define __GPIO_ADC_I2C_ADDR_GET__

#include <vector>

// Mapping from REL_POS ID to GPIO/ADC address
static const std::vector<uint8_t> GPIO_ADC_I2C_ADDR_VECTOR =
{
    0x20, // 0 = ADC1
    0x2E, // 1 = ADC2
    0x70, // 2 = GPIO1
    0x7E, // 3 = GPIO2
};

///
/// @brief Get the GPIO/ADC i2c address for the given REL_POS
///
/// @param[in] i_rel_pos REL_POS of GENERICI2CSLAVE target (0-3)
/// @return uint8_t I2C address of the device for the given rel pos
///
inline uint8_t get_gpio_adc_i2c_addr(const uint8_t i_rel_pos)
{
    // Out of range, just return 0. Failsafe so we don't segfault
    // The caller is responsible for calling this with a valid ID
    if (i_rel_pos >= GPIO_ADC_I2C_ADDR_VECTOR.size())
    {
        return 0;
    }

    return GPIO_ADC_I2C_ADDR_VECTOR[i_rel_pos];
}

#endif
<commit_msg>Add gpio function that can take SPD blob and detect DIMM type<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/common/spd_access/gpio_adc_i2c_addr_get.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2022                        */
/* [+] 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 gpio_adc_i2c_addr_get.H
/// @brief Function to get GPIO/ADC i2c addresses given target REL_POS
///
// *HWP HWP Owner: Mark Pizzutillo <mark.pizzutillo@ibm.com>
// *HWP HWP Owner: Dan Crowell <dcrowell@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef __GPIO_ADC_I2C_ADDR_GET__
#define __GPIO_ADC_I2C_ADDR_GET__

#include <vector>

// Mapping from REL_POS ID to GPIO/ADC address
static const std::vector<uint8_t> GPIO_ADC_I2C_ADDR_VECTOR =
{
    0x20, // 0 = ADC1
    0x2E, // 1 = ADC2
    0x70, // 2 = GPIO1
    0x7E, // 3 = GPIO2
};

// 4U DDIMM bytes
constexpr uint8_t MEM_DDR4  = 0xC;
constexpr uint8_t MEM_DDIMM = 0xA;
constexpr uint8_t MEM_4U    = 0x80;
// SPD bytes to check the various details of the DIMM
constexpr uint16_t SPD_DDR_BYTE       = 2;
constexpr uint16_t SPD_DIMM_TYPE_BYTE = 3;
constexpr uint16_t SPD_DIMM_SIZE_BYTE = 193;

///
/// @brief Get the GPIO/ADC i2c address for the given REL_POS
///
/// @param[in] i_rel_pos REL_POS of GENERICI2CSLAVE target (0-3)
/// @return uint8_t I2C address of the device for the given rel pos
///
inline uint8_t get_gpio_adc_i2c_addr(const uint8_t i_rel_pos)
{
    // Out of range, just return 0. Failsafe so we don't segfault
    // The caller is responsible for calling this with a valid ID
    if (i_rel_pos >= GPIO_ADC_I2C_ADDR_VECTOR.size())
    {
        return 0;
    }

    return GPIO_ADC_I2C_ADDR_VECTOR[i_rel_pos];
}

///
/// @brief Get the GPIO/ADC i2c address for the given REL_POS
///
/// @param[in] i_spd SPD binary
/// @param[in] i_rel_pos REL_POS of GENERICI2CSLAVE target (0-3)
/// @return uint8_t I2C address of the device for the given rel pos
///
inline uint8_t get_gpio_adc_i2c_addr(uint8_t const* const i_spd, const uint8_t i_rel_pos)
{
    // Out of range, just return 0. Failsafe so we don't segfault
    // The caller is responsible for calling this with a valid ID
    if (i_rel_pos >= GPIO_ADC_I2C_ADDR_VECTOR.size())
    {
        return 0;
    }

    // Check the SPD to see which type of DIMM this is. GPIO devices only exist for 4U DDIMMs.
    if ( !((i_spd[SPD_DDR_BYTE] == MEM_DDR4)
           && (i_spd[SPD_DIMM_TYPE_BYTE] == MEM_DDIMM)
           && (i_spd[SPD_DIMM_SIZE_BYTE] == MEM_4U)))
    {
        // This is not a DDR4 4U DDIMM which means there isn't a GPIO device. Return 0 and let caller handle.
        return 0;
    }

    return GPIO_ADC_I2C_ADDR_VECTOR[i_rel_pos];
}

#endif
<|endoftext|>


<commit_before>//===-- FormatManager.cpp -------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Core/FormatManager.h"

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes

using namespace lldb;
using namespace lldb_private;

struct FormatInfo
{
    Format format;
    const char format_char; // One or more format characters that can be used for this format.
    const char *format_name;    // Long format name that can be used to specify the current format
};

static FormatInfo
g_format_infos[] =
{
    { eFormatDefault        , '\0'  , "default"             },
    { eFormatBoolean        , 'B'   , "boolean"             },
    { eFormatBinary         , 'b'   , "binary"              },
    { eFormatBytes          , 'y'   , "bytes"               },
    { eFormatBytesWithASCII , 'Y'   , "bytes with ASCII"    },
    { eFormatChar           , 'c'   , "character"           },
    { eFormatCharPrintable  , 'C'   , "printable character" },
    { eFormatComplexFloat   , 'F'   , "complex float"       },
    { eFormatCString        , 's'   , "c-string"            },
    { eFormatDecimal        , 'i'   , "signed decimal"      },
    { eFormatEnum           , 'E'   , "enumeration"         },
    { eFormatHex            , 'x'   , "hex"                 },
    { eFormatFloat          , 'f'   , "float"               },
    { eFormatOctal          , 'o'   , "octal"               },
    { eFormatOSType         , 'O'   , "OSType"              },
    { eFormatUnicode16      , 'U'   , "unicode16"           },
    { eFormatUnicode32      , '\0'  , "unicode32"           },
    { eFormatUnsigned       , 'u'   , "unsigned decimal"    },
    { eFormatPointer        , 'p'   , "pointer"             },
    { eFormatVectorOfChar   , '\0'  , "char[]"              },
    { eFormatVectorOfSInt8  , '\0'  , "int8_t[]"            },
    { eFormatVectorOfUInt8  , '\0'  , "uint8_t[]"           },
    { eFormatVectorOfSInt16 , '\0'  , "int16_t[]"           },
    { eFormatVectorOfUInt16 , '\0'  , "uint16_t[]"          },
    { eFormatVectorOfSInt32 , '\0'  , "int16_t[]"           },
    { eFormatVectorOfUInt32 , '\0'  , "uint16_t[]"          },
    { eFormatVectorOfSInt64 , '\0'  , "int16_t[]"           },
    { eFormatVectorOfUInt64 , '\0'  , "uint16_t[]"          },
    { eFormatVectorOfFloat32, '\0'  , "float32[]"           },
    { eFormatVectorOfFloat64, '\0'  , "float64[]"           },
    { eFormatVectorOfUInt128, '\0'  , "uint128_t[]"         },
    { eFormatComplexInteger , 'I'   , "complex integer"     },
    { eFormatCharArray      , 'a'   , "character array"     }
};

static uint32_t
g_num_format_infos = sizeof(g_format_infos)/sizeof(FormatInfo);

static bool
GetFormatFromFormatChar (char format_char, Format &format)
{
    for (uint32_t i=0; i<g_num_format_infos; ++i)
    {
        if (g_format_infos[i].format_char == format_char)
        {
            format = g_format_infos[i].format;
            return true;
        }
    }
    format = eFormatInvalid;
    return false;
}

static bool
GetFormatFromFormatName (const char *format_name, bool partial_match_ok, Format &format)
{
    uint32_t i;
    for (i=0; i<g_num_format_infos; ++i)
    {
        if (strcasecmp (g_format_infos[i].format_name, format_name) == 0)
        {
            format = g_format_infos[i].format;
            return true;
        }
    }

    if (partial_match_ok)
    {
        for (i=0; i<g_num_format_infos; ++i)
        {
            if (strcasestr (g_format_infos[i].format_name, format_name) == g_format_infos[i].format_name)
            {
                format = g_format_infos[i].format;
                return true;
            }
        }
    }
    format = eFormatInvalid;
    return false;
}

bool
FormatManager::GetFormatFromCString (const char *format_cstr,
                                     bool partial_match_ok,
                                     lldb::Format &format)
{
    bool success = false;
    if (format_cstr && format_cstr[0])
    {
        if (format_cstr[1] == '\0')
        {
            success = GetFormatFromFormatChar (format_cstr[0], format);
            if (success)
                return true;
        }

        success = GetFormatFromFormatName (format_cstr, partial_match_ok, format);
    }
    if (!success)
        format = eFormatInvalid;
    return success;
}

char
FormatManager::GetFormatAsFormatChar (lldb::Format format)
{
    for (uint32_t i=0; i<g_num_format_infos; ++i)
    {
        if (g_format_infos[i].format == format)
            return g_format_infos[i].format_char;
    }
    return '\0';
}

const char *
FormatManager::GetFormatAsCString (Format format)
{
    if (format >= eFormatDefault && format < kNumFormats)
        return g_format_infos[format].format_name;
    return NULL;
}

template<>
bool
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Get(const char* key,
                                                                                SummaryFormat::SharedPointer& value)
{
    Mutex::Locker(m_map_mutex);
    MapIterator pos, end = m_map.end();
    for (pos = m_map.begin(); pos != end; pos++)
    {
        lldb::RegularExpressionSP regex = pos->first;
        if (regex->Execute(key))
        {
            value = pos->second;
            return true;
        }
    }
    return false;
}

template<>
bool
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Delete(const char* type)
{
    Mutex::Locker(m_map_mutex);
    MapIterator pos, end = m_map.end();
    for (pos = m_map.begin(); pos != end; pos++)
    {
        lldb::RegularExpressionSP regex = pos->first;
        if ( ::strcmp(type,regex->GetText()) == 0)
        {
            m_map.erase(pos);
            return true;
        }
    }
    return false;
}
<commit_msg>Fixed some format names<commit_after>//===-- FormatManager.cpp -------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Core/FormatManager.h"

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes

using namespace lldb;
using namespace lldb_private;

struct FormatInfo
{
    Format format;
    const char format_char; // One or more format characters that can be used for this format.
    const char *format_name;    // Long format name that can be used to specify the current format
};

static FormatInfo
g_format_infos[] =
{
    { eFormatDefault        , '\0'  , "default"             },
    { eFormatBoolean        , 'B'   , "boolean"             },
    { eFormatBinary         , 'b'   , "binary"              },
    { eFormatBytes          , 'y'   , "bytes"               },
    { eFormatBytesWithASCII , 'Y'   , "bytes with ASCII"    },
    { eFormatChar           , 'c'   , "character"           },
    { eFormatCharPrintable  , 'C'   , "printable character" },
    { eFormatComplexFloat   , 'F'   , "complex float"       },
    { eFormatCString        , 's'   , "c-string"            },
    { eFormatDecimal        , 'i'   , "signed decimal"      },
    { eFormatEnum           , 'E'   , "enumeration"         },
    { eFormatHex            , 'x'   , "hex"                 },
    { eFormatFloat          , 'f'   , "float"               },
    { eFormatOctal          , 'o'   , "octal"               },
    { eFormatOSType         , 'O'   , "OSType"              },
    { eFormatUnicode16      , 'U'   , "unicode16"           },
    { eFormatUnicode32      , '\0'  , "unicode32"           },
    { eFormatUnsigned       , 'u'   , "unsigned decimal"    },
    { eFormatPointer        , 'p'   , "pointer"             },
    { eFormatVectorOfChar   , '\0'  , "char[]"              },
    { eFormatVectorOfSInt8  , '\0'  , "int8_t[]"            },
    { eFormatVectorOfUInt8  , '\0'  , "uint8_t[]"           },
    { eFormatVectorOfSInt16 , '\0'  , "int16_t[]"           },
    { eFormatVectorOfUInt16 , '\0'  , "uint16_t[]"          },
    { eFormatVectorOfSInt32 , '\0'  , "int32_t[]"           },
    { eFormatVectorOfUInt32 , '\0'  , "uint32_t[]"          },
    { eFormatVectorOfSInt64 , '\0'  , "int64_t[]"           },
    { eFormatVectorOfUInt64 , '\0'  , "uint64_t[]"          },
    { eFormatVectorOfFloat32, '\0'  , "float32[]"           },
    { eFormatVectorOfFloat64, '\0'  , "float64[]"           },
    { eFormatVectorOfUInt128, '\0'  , "uint128_t[]"         },
    { eFormatComplexInteger , 'I'   , "complex integer"     },
    { eFormatCharArray      , 'a'   , "character array"     }
};

static uint32_t
g_num_format_infos = sizeof(g_format_infos)/sizeof(FormatInfo);

static bool
GetFormatFromFormatChar (char format_char, Format &format)
{
    for (uint32_t i=0; i<g_num_format_infos; ++i)
    {
        if (g_format_infos[i].format_char == format_char)
        {
            format = g_format_infos[i].format;
            return true;
        }
    }
    format = eFormatInvalid;
    return false;
}

static bool
GetFormatFromFormatName (const char *format_name, bool partial_match_ok, Format &format)
{
    uint32_t i;
    for (i=0; i<g_num_format_infos; ++i)
    {
        if (strcasecmp (g_format_infos[i].format_name, format_name) == 0)
        {
            format = g_format_infos[i].format;
            return true;
        }
    }

    if (partial_match_ok)
    {
        for (i=0; i<g_num_format_infos; ++i)
        {
            if (strcasestr (g_format_infos[i].format_name, format_name) == g_format_infos[i].format_name)
            {
                format = g_format_infos[i].format;
                return true;
            }
        }
    }
    format = eFormatInvalid;
    return false;
}

bool
FormatManager::GetFormatFromCString (const char *format_cstr,
                                     bool partial_match_ok,
                                     lldb::Format &format)
{
    bool success = false;
    if (format_cstr && format_cstr[0])
    {
        if (format_cstr[1] == '\0')
        {
            success = GetFormatFromFormatChar (format_cstr[0], format);
            if (success)
                return true;
        }

        success = GetFormatFromFormatName (format_cstr, partial_match_ok, format);
    }
    if (!success)
        format = eFormatInvalid;
    return success;
}

char
FormatManager::GetFormatAsFormatChar (lldb::Format format)
{
    for (uint32_t i=0; i<g_num_format_infos; ++i)
    {
        if (g_format_infos[i].format == format)
            return g_format_infos[i].format_char;
    }
    return '\0';
}

const char *
FormatManager::GetFormatAsCString (Format format)
{
    if (format >= eFormatDefault && format < kNumFormats)
        return g_format_infos[format].format_name;
    return NULL;
}

template<>
bool
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Get(const char* key,
                                                                                SummaryFormat::SharedPointer& value)
{
    Mutex::Locker(m_map_mutex);
    MapIterator pos, end = m_map.end();
    for (pos = m_map.begin(); pos != end; pos++)
    {
        lldb::RegularExpressionSP regex = pos->first;
        if (regex->Execute(key))
        {
            value = pos->second;
            return true;
        }
    }
    return false;
}

template<>
bool
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Delete(const char* type)
{
    Mutex::Locker(m_map_mutex);
    MapIterator pos, end = m_map.end();
    for (pos = m_map.begin(); pos != end; pos++)
    {
        lldb::RegularExpressionSP regex = pos->first;
        if ( ::strcmp(type,regex->GetText()) == 0)
        {
            m_map.erase(pos);
            return true;
        }
    }
    return false;
}
<|endoftext|>


<commit_before>#include <iostream>
#include "cmdline.hpp"
#include "cmd.hpp"
#include "semicolon.hpp"
#include "pound.hpp"
#include "or.hpp"
#include "and.hpp"
#include <vector>
#include <string>
#include <cstring>
#include <boost/tokenizer.hpp>
#include <locale>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
using namespace boost;

//ALL COMMENTED CODE WAS USED FOR DEBUGGING PURPOSES, WITH THE EXCEPTION OF THE CODE OUTSIDE IF MAIN, WHICH IS SCRAPPED PREVIOUS ATTEMPTS.

int main()
{
char uname[100];
string uInput = "";
char* ulgn = getlogin();
gethostname(uname, 100);
puts(uname);

cout << "Begginning Terminal" << endl;
cout << ulgn << "@" << uname << "$ ";
while (getline(cin, uInput))
{

	if (!uInput.empty() && uInput.at(0) != '#')
	{
		vector<char> substr;			// USED TO HOLD PARSERS
		tokenizer<> tok(uInput);		// USED TO HOLD COMMANDS
		bool isValid = true;			// USED IN && AND || TO DETERMINE IF PREVIOUS COMMAND WAS VALID

		string otemp;				//TEMP STRING IN ORDER TO CORRECTLY ADDED THE "||" SYMBOL TO SUBSTR
		string atemp;				//TEMP STRING IN ORDER TO CORRECTLY ADDED THE "&&" SYMBOL TO SUBSTR

		for (string::iterator i = uInput.begin(); i != uInput.end(); i++) // ITERATES THROUGH USER INPUT IN ORDER TO FIND PARSERS
		{
			if ((*i) == ';')
			{
				substr.push_back((*i)); // IF SYMBOL == ';' ADDED TO SUBSTR
			}
			else if ((*i) == '|')
			{
				otemp.push_back('|'); // PUSH BACK THE CHAR '|' TO ATEMP
				if (otemp == "||")
				{
					substr.push_back((*i)); //IF OTEMP = "||" THEN ADD A OR SYMBOL TO SUBSTR, USED TO MAKE SURE USER INPUT "||' AND NOT "|'
					otemp.clear(); // CLEAR OTEMP FOR NEXT RUN
				}
			}
			else if ((*i) == '&')
			{
				atemp.push_back('&'); // PUSH BACK THE CHAR '&' TO ATEMP
				if (atemp == "&&")
				{
					substr.push_back((*i)); //IF OTEMP = "&" THEN ADD A OR SYMBOL TO SUBSTR, USED TO MAKE SURE USER INPUT "&&' AND NOT "&'
					atemp.clear(); // CLEAR ATEMP FOR NEXT RUN
				}
			}
			else if ((*i) == '#')
			{
				substr.push_back((*i));
				break; // STOPS PARSING ALL TOGETHER IF '#' IS DETECTED
			}
		}
	//DEBUGGING TOOLS
	/*	if (substr.size() != 1)
		{
			for (unsigned i = 0; i < substr.size(); i++)
			{
				if (substr.at(i) == substr.at(i+1))
				{
					substr.erase(substr.begin() + (i+1));
				}
			}
		}

		cout << "substr: " << endl;
		for (unsigned i = 0; i < substr.size(); i++)
		{
			cout << substr.at(i) << " ";
		}
		cout << endl;

	//	cout << "TOKENIZER" << endl;

		for (tokenizer<>::iterator k = tok.begin(); k != tok.end(); k++)
		{
		//	cout << "K " << (*k) << endl;
			if ((*k) == "quit")
			{
				return 0;
			}
		}
	*/
	// END DEBUGGING TOOLS
		tokenizer<>::iterator i = tok.begin(); // STARTING TO PARSE COMMANDS
		if ((*i) == "quit")
		{
			return 0; //IF FIRST COMMAND IS QUIT EXIT IMMEDIATLY
		}
		Cmd* first = new Cmd((*i)); // BECAUSE FIRST COMMAND DOES NOT HAVE A PARSER IN FRONT OF IT WE HARDCODED IT

		isValid = first->execute((*i)); // SET ISVALID TO WHETHER OR NOT THE COMMAND WAS VALID OR NOT FOR POSSIBLE NEXT COMMAND}
		i++; // INCREMENTED TOKENIZER ITERATOR

		if (i != tok.end()) // IF ONLY ONE COMMAND THEN WILL NOT RUN
		{
			for (unsigned j = 0; j < substr.size(); j++)	//ITERATING THROUGH THE PARSER VECTOR
			{
				Cmd* uCmd = new Cmd((*i));		// CREATE NEW COMMANDS FOR EACH PARSER
				switch(substr.at(j))			// CASE USED TO DETERMINE WHICH PARSER WAS PASSED IN BY USER
				{
					case ';':
					{
		//				cout << "HIT CASE SEMICOLON" << endl;
						Semicolon* sHolder = new Semicolon(isValid, uCmd);	// CREATE SEMICOLON OBJECT WHEN SEMICOLON IS DETECTED;
						isValid = sHolder->execute((*i));			// EXECUTES COMMAND AND CHECKS/SETS VALIDITY
					//	delete sHolder;
						break;
					}
					case '|':
					{
		//				cout << "HIT CASE OR" << endl;
						Or* oHolder = new Or(isValid, uCmd); 	//CREATE OR OBJECT WHEN "|" SYMBOL IS DETECTED
						isValid = oHolder->execute(*i);		//EXECUTES COMMAND AND CHECKS/SETS VALIDITY
						//delete oHolder;
						break;
					}
					case '&':
					{
		//				cout << "HIT CASE AND" << endl;
						And* aHolder = new And(isValid, uCmd);	//CREATE AND OBJECT WHEN "&" SYMBOL IS DETECTED
						isValid = aHolder->execute((*i));	// EXECUTES COMMAND AND CHECKS/SETS VALIDITY
						//delete aHolder;
						break;
					}
					default:
					{
						j = substr.size();	// IF HASH DETECTED BREAK OUT OF THE LOOP
						break;
					}
				}
				i++;	//INCREMENT TOKENIZER CLASS TO NEXT COMMAND TO MATCH NEXT PARSER
			}
	}
	uInput.clear(); //CLEARED FOR NEXT USER INPUT
	substr.clear();	//CLEARED FOR NEXT USER INPUT
	cout << ulgn << "@" << uname << "$ ";
	}

}

	return 0;
}

// OLD CODE KEPT JUST IN CASE
/*for (int i = 0; i < uInput.size(); i++)
{
	if (uInput.at(i) != ' ')
	{
		newInput.push_back(uInput.at(i));

	}
	if (uInput[i] == ';' || uInput[i] == '#')
 	{
		newInput.erase(newInput.end()-1);
		char* temp = new char[newInput.length()+1];
		temp = strcpy(temp, newInput.c_str());
		substr.push_back(temp);
		newInput.clear();
		newInput.push_back(uInput.at(i));
	}
	else if ((uInput[i] == '|' && uInput[i+1] == '|') ||(uInput[i] == '&' && uInput[i+1] == '&'))
	{
		newInput.erase(newInput.end()-1);
	//	newInput.erase(newInput.end()-1);
		newInput.push_back(uInput.at(i+1));
		char* temp = new char[newInput.length()+1];
		temp = strcpy(temp, newInput.c_str());
		substr.push_back(temp);
		newInput.clear();
		newInput.push_back(uInput.at(i));
		newInput.push_back(uInput.at(i+1));
//		newInput.erase(newInput.end()-1);
		i++;
	}
}

char* temp = new char[newInput.length()+1];
temp = strcpy(temp, newInput.c_str());
substr.push_back(temp);
newInput.clear();

substr.push_back(NULL);
*/

/*
	Cmd* A = new Cmd("ls");
	Cmd* B = new Cmd("asdf");
	Semicolon* C = new Semicolon(false,A);
	Pound* D = new Pound(false, B);
	Or* E = new Or(false, A);
	if (E->isValid)
	{
		cout << "GOOD " << endl;
	}
	else
	{
		cout << "ERROR" << endl;
	}
*/
<commit_msg>updated README.md and cmd.cpp<commit_after>#include <iostream>
#include "cmdline.hpp"
#include "cmd.hpp"
#include "semicolon.hpp"
#include "pound.hpp"
#include "or.hpp"
#include "and.hpp"
#include <vector>
#include <string>
#include <cstring>
#include <boost/tokenizer.hpp>
#include <locale>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
using namespace boost;

//ALL COMMENTED CODE WAS USED FOR DEBUGGING PURPOSES, WITH THE EXCEPTION OF THE CODE OUTSIDE IF MAIN, WHICH IS SCRAPPED PREVIOUS ATTEMPTS.

int main()
{
    char uname[100];
    string uInput = "";
    char* ulgn = getlogin();
    gethostname(uname, 100);
    puts(uname);

    cout << "Beginning Terminal" << endl;
    cout << ulgn << "@" << uname << "$ ";
    while (getline(cin, uInput))
    {
		if (!uInput.empty() && uInput.at(0) != '#')
	    {
		    vector<char> substr;			// USED TO HOLD PARSERS
		    tokenizer<> tok(uInput);		// USED TO HOLD COMMANDS
		    bool isValid = true;			// USED IN && AND || TO DETERMINE IF PREVIOUS COMMAND WAS VALID

		    string otemp;				//TEMP STRING IN ORDER TO CORRECTLY ADDED THE "||" SYMBOL TO SUBSTR
		    string atemp;				//TEMP STRING IN ORDER TO CORRECTLY ADDED THE "&&" SYMBOL TO SUBSTR

		    for (string::iterator i = uInput.begin(); i != uInput.end(); i++) // ITERATES THROUGH USER INPUT IN ORDER TO FIND PARSERS
		    {
			    if ((*i) == ';')
			    {
				    substr.push_back((*i)); // IF SYMBOL == ';' ADDED TO SUBSTR
			    }
			    else if ((*i) == '|')
			    {
				    otemp.push_back('|'); // PUSH BACK THE CHAR '|' TO ATEMP
				    if (otemp == "||")
				    {
					    substr.push_back((*i)); //IF OTEMP = "||" THEN ADD A OR SYMBOL TO SUBSTR, USED TO MAKE SURE USER INPUT "||' AND NOT "|'
					    otemp.clear(); // CLEAR OTEMP FOR NEXT RUN
				    }
			    }
			    else if ((*i) == '&')
			    {
				    atemp.push_back('&'); // PUSH BACK THE CHAR '&' TO ATEMP
				    if (atemp == "&&")
				    {
					    substr.push_back((*i)); //IF OTEMP = "&" THEN ADD A OR SYMBOL TO SUBSTR, USED TO MAKE SURE USER INPUT "&&' AND NOT "&'
					    atemp.clear(); // CLEAR ATEMP FOR NEXT RUN
				    }
			    }
			    else if ((*i) == '#')
			    {
				    substr.push_back((*i));
				    break; // STOPS PARSING ALL TOGETHER IF '#' IS DETECTED
			    }
		    }
	//DEBUGGING TOOLS
	/*	if (substr.size() != 1)
		{
			for (unsigned i = 0; i < substr.size(); i++)
			{
				if (substr.at(i) == substr.at(i+1))
				{
					substr.erase(substr.begin() + (i+1));
				}
			}
		}

		cout << "substr: " << endl;
		for (unsigned i = 0; i < substr.size(); i++)
		{
			cout << substr.at(i) << " ";
		}
		cout << endl;

	//	cout << "TOKENIZER" << endl;

		for (tokenizer<>::iterator k = tok.begin(); k != tok.end(); k++)
		{
		//	cout << "K " << (*k) << endl;
			if ((*k) == "quit")
			{
				return 0;
			}
		}
	*/
	// END DEBUGGING TOOLS
		    tokenizer<>::iterator i = tok.begin(); // STARTING TO PARSE COMMANDS
		    if ((*i) == "quit")
		    {
			    return 0; //IF FIRST COMMAND IS QUIT EXIT IMMEDIATLY
		    }
		    Cmd* first = new Cmd((*i)); // BECAUSE FIRST COMMAND DOES NOT HAVE A PARSER IN FRONT OF IT WE HARDCODED IT
		    isValid = first->execute((*i)); // SET ISVALID TO WHETHER OR NOT THE COMMAND WAS VALID OR NOT FOR POSSIBLE NEXT COMMAND}
		    i++; // INCREMENTED TOKENIZER ITERATOR

		    if (i != tok.end()) // IF ONLY ONE COMMAND THEN WILL NOT RUN
		    {
			    for (unsigned j = 0; j < substr.size(); j++)	//ITERATING THROUGH THE PARSER VECTOR
			    {
				    Cmd* uCmd = new Cmd((*i));		// CREATE NEW COMMANDS FOR EACH PARSER
				    switch(substr.at(j))			// CASE USED TO DETERMINE WHICH PARSER WAS PASSED IN BY USER
				    {
					    case ';':
					    {
		//				cout << "HIT CASE SEMICOLON" << endl;
						    Semicolon* sHolder = new Semicolon(isValid, uCmd);	// CREATE SEMICOLON OBJECT WHEN SEMICOLON IS DETECTED;
						    isValid = sHolder->execute((*i));			// EXECUTES COMMAND AND CHECKS/SETS VALIDITY
					//	delete sHolder;
						    break;
					}
					    case '|':
					    {
		//				    cout << "HIT CASE OR" << endl;
						    Or* oHolder = new Or(isValid, uCmd); 	//CREATE OR OBJECT WHEN "|" SYMBOL IS DETECTED
						    isValid = oHolder->execute(*i);		//EXECUTES COMMAND AND CHECKS/SETS VALIDITY
						    //delete oHolder;
						    break;
					    }
					    case '&':
					    {
		//				    cout << "HIT CASE AND" << endl;
						    And* aHolder = new And(isValid, uCmd);	//CREATE AND OBJECT WHEN "&" SYMBOL IS DETECTED
						    isValid = aHolder->execute((*i));	// EXECUTES COMMAND AND CHECKS/SETS VALIDITY
						    //delete aHolder;
						    break;
					    }
					    default:
					    {
						    j = substr.size();	// IF HASH DETECTED BREAK OUT OF THE LOOP
						    break;
					    }
				    }
				    i++;	//INCREMENT TOKENIZER CLASS TO NEXT COMMAND TO MATCH NEXT PARSER
			    }
	        }
	        uInput.clear(); //CLEARED FOR NEXT USER INPUT
	        substr.clear();	//CLEARED FOR NEXT USER INPUT
	        cout << ulgn << "@" << uname << "$ ";
	    }

    }

	    return 0;
}

// OLD CODE KEPT JUST IN CASE
/*for (int i = 0; i < uInput.size(); i++)
{
	if (uInput.at(i) != ' ')
	{
		newInput.push_back(uInput.at(i));

	}
	if (uInput[i] == ';' || uInput[i] == '#')
 	{
		newInput.erase(newInput.end()-1);
		char* temp = new char[newInput.length()+1];
		temp = strcpy(temp, newInput.c_str());
		substr.push_back(temp);
		newInput.clear();
		newInput.push_back(uInput.at(i));
	}
	else if ((uInput[i] == '|' && uInput[i+1] == '|') ||(uInput[i] == '&' && uInput[i+1] == '&'))
	{
		newInput.erase(newInput.end()-1);
	//	newInput.erase(newInput.end()-1);
		newInput.push_back(uInput.at(i+1));
		char* temp = new char[newInput.length()+1];
		temp = strcpy(temp, newInput.c_str());
		substr.push_back(temp);
		newInput.clear();
		newInput.push_back(uInput.at(i));
		newInput.push_back(uInput.at(i+1));
//		newInput.erase(newInput.end()-1);
		i++;
	}
}

char* temp = new char[newInput.length()+1];
temp = strcpy(temp, newInput.c_str());
substr.push_back(temp);
newInput.clear();

substr.push_back(NULL);
*/

/*
	Cmd* A = new Cmd("ls");
	Cmd* B = new Cmd("asdf");
	Semicolon* C = new Semicolon(false,A);
	Pound* D = new Pound(false, B);
	Or* E = new Or(false, A);
	if (E->isValid)
	{
		cout << "GOOD " << endl;
	}
	else
	{
		cout << "ERROR" << endl;
	}
*/
<|endoftext|>


<commit_before>#define MS_CLASS "RTC::NackGenerator"
// #define MS_LOG_DEV

#include "RTC/NackGenerator.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"

namespace RTC
{
	/* Static. */

	constexpr uint32_t MaxPacketAge{ 2500 };
	constexpr size_t MaxNackPackets{ 300 };
	constexpr uint32_t DefaultRtt{ 100 };
	constexpr uint8_t MaxNackRetries{ 3 };
	constexpr uint64_t TimerInterval{ 50 };

	/* Instance methods. */

	NackGenerator::NackGenerator(Listener* listener) : listener(listener), rtt(DefaultRtt)
	{
		MS_TRACE();

		// Set the timer.
		this->timer = new Timer(this);
	}

	NackGenerator::~NackGenerator()
	{
		MS_TRACE();

		// Close the timer.
		this->timer->Destroy();
	}

	void NackGenerator::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		uint32_t seq32 = packet->GetExtendedSequenceNumber();

		if (!this->started)
		{
			this->lastSeq32 = seq32;
			this->started   = true;

			return;
		}

		// Obviously never nacked, so ignore.
		if (seq32 == this->lastSeq32)
		{
			return;
		}
		if (seq32 == this->lastSeq32 + 1)
		{
			this->lastSeq32++;

			return;
		}

		// May be an out of order packet or a retransmitted packet (without RTX).
		if (seq32 < this->lastSeq32)
		{
			auto it = this->nackList.find(seq32);

			// It was a nacked packet.
			if (it != this->nackList.end())
			{
				MS_DEBUG_TAG(
				  rtx,
				  "NACKed packet received [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
				  packet->GetSsrc(),
				  packet->GetSequenceNumber());

				this->nackList.erase(it);
			}
			// Out of order packet.
			else
			{
				MS_DEBUG_TAG(
				  rtx,
				  "out of order RTX packet received [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
				  packet->GetSsrc(),
				  packet->GetSequenceNumber());
			}

			return;
		}

		// Otherwise we may have lost some packets.
		AddPacketsToNackList(this->lastSeq32 + 1, seq32);
		this->lastSeq32 = seq32;

		// Check if there are any nacks that are waiting for this seq number.
		std::vector<uint16_t> nackBatch = GetNackBatch(NackFilter::SEQ);

		if (!nackBatch.empty())
			this->listener->OnNackGeneratorNackRequired(nackBatch);

		MayRunTimer();
	}

	void NackGenerator::AddPacketsToNackList(uint32_t seq32Start, uint32_t seq32End)
	{
		MS_TRACE();

		// Remove old packets.
		auto it = this->nackList.lower_bound(seq32End - MaxPacketAge);

		this->nackList.erase(this->nackList.begin(), it);

		// If the nack list is too large, clear it and request a full frame.
		uint32_t numNewNacks = seq32End - seq32Start;

		if (this->nackList.size() + numNewNacks > MaxNackPackets)
		{
			MS_DEBUG_TAG(rtx, "NACK list too large, clearing it and requesting a full frame");

			this->nackList.clear();
			this->listener->OnNackGeneratorFullFrameRequired();

			return;
		}

		for (uint32_t seq32 = seq32Start; seq32 != seq32End; ++seq32)
		{
			// NOTE: Let the packet become out of order for a while without requesting
			// it into a NACK.
			// TODO: To be done.
			uint32_t sendAtSeqNum = seq32 + 0;

			NackInfo nackInfo(seq32, sendAtSeqNum);

			MS_ASSERT(
			  this->nackList.find(seq32) == this->nackList.end(), "packet already in the NACK list");

			this->nackList[seq32] = nackInfo;
		}
	}

	std::vector<uint16_t> NackGenerator::GetNackBatch(NackFilter filter)
	{
		uint64_t now = DepLibUV::GetTime();
		std::vector<uint16_t> nackBatch;
		auto it = this->nackList.begin();

		while (it != this->nackList.end())
		{
			NackInfo& nackInfo = it->second;
			uint16_t seq       = nackInfo.seq32 % (1 << 16);

			if (filter == NackFilter::SEQ && nackInfo.sentAtTime == 0 && this->lastSeq32 >= nackInfo.sendAtSeqNum)
			{
				nackInfo.retries++;
				nackInfo.sentAtTime = now;

				if (nackInfo.retries >= MaxNackRetries)
				{
					MS_WARN_TAG(
					  rtx,
					  "sequence number removed from the NACK list due to max retries [seq:%" PRIu16 "]",
					  seq);

					it = this->nackList.erase(it);
				}
				else
				{
					nackBatch.emplace_back(seq);
					++it;
				}

				continue;
			}

			if (filter == NackFilter::TIME && nackInfo.sentAtTime + this->rtt < now)
			{
				nackInfo.retries++;
				nackInfo.sentAtTime = now;

				if (nackInfo.retries >= MaxNackRetries)
				{
					MS_WARN_TAG(
					  rtx,
					  "sequence number removed from the NACK list due to max retries [seq:%" PRIu16 "]",
					  seq);

					it = this->nackList.erase(it);
				}
				else
				{
					nackBatch.emplace_back(seq);
					++it;
				}

				continue;
			}

			++it;
		}

		return nackBatch;
	}

	inline void NackGenerator::MayRunTimer() const
	{
		if (!this->nackList.empty())
			this->timer->Start(TimerInterval);
	}

	inline void NackGenerator::OnTimer(Timer* /*timer*/)
	{
		MS_TRACE();

		std::vector<uint16_t> nackBatch = GetNackBatch(NackFilter::TIME);

		if (!nackBatch.empty())
			this->listener->OnNackGeneratorNackRequired(nackBatch);

		MayRunTimer();
	}
} // namespace RTC
<commit_msg>NackGenerator: improve debug<commit_after>#define MS_CLASS "RTC::NackGenerator"
// #define MS_LOG_DEV

#include "RTC/NackGenerator.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"

namespace RTC
{
	/* Static. */

	constexpr uint32_t MaxPacketAge{ 2500 };
	constexpr size_t MaxNackPackets{ 300 };
	constexpr uint32_t DefaultRtt{ 100 };
	constexpr uint8_t MaxNackRetries{ 3 };
	constexpr uint64_t TimerInterval{ 50 };

	/* Instance methods. */

	NackGenerator::NackGenerator(Listener* listener) : listener(listener), rtt(DefaultRtt)
	{
		MS_TRACE();

		// Set the timer.
		this->timer = new Timer(this);
	}

	NackGenerator::~NackGenerator()
	{
		MS_TRACE();

		// Close the timer.
		this->timer->Destroy();
	}

	void NackGenerator::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		uint32_t seq32 = packet->GetExtendedSequenceNumber();

		if (!this->started)
		{
			this->lastSeq32 = seq32;
			this->started   = true;

			return;
		}

		// Obviously never nacked, so ignore.
		if (seq32 == this->lastSeq32)
		{
			return;
		}
		if (seq32 == this->lastSeq32 + 1)
		{
			this->lastSeq32++;

			return;
		}

		// May be an out of order packet, or already handled retransmitted packet,
		// or a retransmitted packet.
		if (seq32 < this->lastSeq32)
		{
			auto it = this->nackList.find(seq32);

			// It was a nacked packet.
			if (it != this->nackList.end())
			{
				MS_DEBUG_TAG(
				  rtx,
				  "NACKed packet received [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
				  packet->GetSsrc(),
				  packet->GetSequenceNumber());

				this->nackList.erase(it);
			}
			// Out of order packet or already handled NACKed packet.
			else
			{
				MS_DEBUG_TAG(
				  rtx,
				  "ignoring out of order packet or already handled NACKed packet [ssrc:%" PRIu32
				  ", seq:%" PRIu16 "]",
				  packet->GetSsrc(),
				  packet->GetSequenceNumber());
			}

			return;
		}

		// Otherwise we may have lost some packets.
		AddPacketsToNackList(this->lastSeq32 + 1, seq32);
		this->lastSeq32 = seq32;

		// Check if there are any nacks that are waiting for this seq number.
		std::vector<uint16_t> nackBatch = GetNackBatch(NackFilter::SEQ);

		if (!nackBatch.empty())
			this->listener->OnNackGeneratorNackRequired(nackBatch);

		MayRunTimer();
	}

	void NackGenerator::AddPacketsToNackList(uint32_t seq32Start, uint32_t seq32End)
	{
		MS_TRACE();

		// Remove old packets.
		auto it = this->nackList.lower_bound(seq32End - MaxPacketAge);

		this->nackList.erase(this->nackList.begin(), it);

		// If the nack list is too large, clear it and request a full frame.
		uint32_t numNewNacks = seq32End - seq32Start;

		if (this->nackList.size() + numNewNacks > MaxNackPackets)
		{
			MS_DEBUG_TAG(rtx, "NACK list too large, clearing it and requesting a full frame");

			this->nackList.clear();
			this->listener->OnNackGeneratorFullFrameRequired();

			return;
		}

		for (uint32_t seq32 = seq32Start; seq32 != seq32End; ++seq32)
		{
			// NOTE: Let the packet become out of order for a while without requesting
			// it into a NACK.
			// TODO: To be done.
			uint32_t sendAtSeqNum = seq32 + 0;

			NackInfo nackInfo(seq32, sendAtSeqNum);

			MS_ASSERT(
			  this->nackList.find(seq32) == this->nackList.end(), "packet already in the NACK list");

			this->nackList[seq32] = nackInfo;
		}
	}

	std::vector<uint16_t> NackGenerator::GetNackBatch(NackFilter filter)
	{
		uint64_t now = DepLibUV::GetTime();
		std::vector<uint16_t> nackBatch;
		auto it = this->nackList.begin();

		while (it != this->nackList.end())
		{
			NackInfo& nackInfo = it->second;
			uint16_t seq       = nackInfo.seq32 % (1 << 16);

			if (filter == NackFilter::SEQ && nackInfo.sentAtTime == 0 && this->lastSeq32 >= nackInfo.sendAtSeqNum)
			{
				nackInfo.retries++;
				nackInfo.sentAtTime = now;

				if (nackInfo.retries >= MaxNackRetries)
				{
					MS_WARN_TAG(
					  rtx,
					  "sequence number removed from the NACK list due to max retries [seq:%" PRIu16 "]",
					  seq);

					it = this->nackList.erase(it);
				}
				else
				{
					nackBatch.emplace_back(seq);
					++it;
				}

				continue;
			}

			if (filter == NackFilter::TIME && nackInfo.sentAtTime + this->rtt < now)
			{
				nackInfo.retries++;
				nackInfo.sentAtTime = now;

				if (nackInfo.retries >= MaxNackRetries)
				{
					MS_WARN_TAG(
					  rtx,
					  "sequence number removed from the NACK list due to max retries [seq:%" PRIu16 "]",
					  seq);

					it = this->nackList.erase(it);
				}
				else
				{
					nackBatch.emplace_back(seq);
					++it;
				}

				continue;
			}

			++it;
		}

		return nackBatch;
	}

	inline void NackGenerator::MayRunTimer() const
	{
		if (!this->nackList.empty())
			this->timer->Start(TimerInterval);
	}

	inline void NackGenerator::OnTimer(Timer* /*timer*/)
	{
		MS_TRACE();

		std::vector<uint16_t> nackBatch = GetNackBatch(NackFilter::TIME);

		if (!nackBatch.empty())
			this->listener->OnNackGeneratorNackRequired(nackBatch);

		MayRunTimer();
	}
} // namespace RTC
<|endoftext|>


<commit_before>#define MS_CLASS "RTC::RtpStreamSend"
// #define MS_LOG_DEV

#include "RTC/RtpStreamSend.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"
#include "Utils.hpp"

namespace RTC
{
	/* Static. */

	static constexpr uint32_t RtpSeqMod{ 1 << 16 };
	// Don't retransmit packets older than this (ms).
	// TODO: This must be tunned.
	static constexpr uint32_t MaxRetransmissionDelay{ 4000 };
	static constexpr uint32_t DefaultRtt{ 100 };

	/* Instance methods. */

	RtpStreamSend::RtpStreamSend(RTC::RtpStream::Params& params, size_t bufferSize)
	  : RtpStream::RtpStream(params), storage(bufferSize)
	{
		MS_TRACE();
	}

	RtpStreamSend::~RtpStreamSend()
	{
		MS_TRACE();

		// Clear the RTP buffer.
		ClearRetransmissionBuffer();
	}

	bool RtpStreamSend::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Call the parent method.
		if (!RtpStream::ReceivePacket(packet))
			return false;

		// If bufferSize was given, store the packet into the buffer.
		if (!this->storage.empty())
			StorePacket(packet);

		return true;
	}

	void RtpStreamSend::ReceiveRtcpReceiverReport(RTC::RTCP::ReceiverReport* report)
	{
		MS_TRACE();

		/* Calculate RTT. */

		// Get the compact NTP representation of the current timestamp.
		Utils::Time::Ntp nowNtp{};
		Utils::Time::CurrentTimeNtp(nowNtp);
		uint32_t nowCompactNtp = (nowNtp.seconds & 0x0000FFFF) << 16;

		nowCompactNtp |= (nowNtp.fractions & 0xFFFF0000) >> 16;

		uint32_t lastSr = report->GetLastSenderReport();
		uint32_t dlsr   = report->GetDelaySinceLastSenderReport();
		// RTT in 1/2^16 seconds.
		uint32_t rtt = nowCompactNtp - dlsr - lastSr;

		// RTT in milliseconds.
		this->rtt = ((rtt >> 16) * 1000);
		this->rtt += (static_cast<float>(rtt & 0x0000FFFF) / 65536) * 1000;

		this->totalLost    = report->GetTotalLost();
		this->fractionLost = report->GetFractionLost();
		this->jitter       = report->GetJitter();
	}

	// This method looks for the requested RTP packets and inserts them into the
	// given container (and set to null the next container position).
	void RtpStreamSend::RequestRtpRetransmission(
	  uint16_t seq, uint16_t bitmask, std::vector<RTC::RtpPacket*>& container)
	{
		MS_TRACE();

		// 17: 16 bit mask + the initial sequence number.
		static constexpr size_t MaxRequestedPackets{ 17 };

		// Ensure the container's first element is 0.
		container[0] = nullptr;

		// If NACK is not supported, exit.
		if (!this->params.useNack)
		{
			MS_WARN_TAG(rtx, "NACK not negotiated");

			return;
		}

		// If the buffer is empty just return.
		if (this->buffer.empty())
			return;

		// Convert the given sequence numbers to 32 bits.
		uint32_t firstSeq32 = uint32_t{ seq } + this->cycles;
		uint32_t lastSeq32  = firstSeq32 + MaxRequestedPackets - 1;

		// Number of requested packets cannot be greater than the container size - 1.
		MS_ASSERT(container.size() - 1 >= MaxRequestedPackets, "RtpPacket container is too small");

		auto bufferIt             = this->buffer.begin();
		auto bufferItReverse      = this->buffer.rbegin();
		uint32_t bufferFirstSeq32 = (*bufferIt).seq32;
		uint32_t bufferLastSeq32  = (*bufferItReverse).seq32;
		bool inRange              = true;

		// Requested packet range not found.
		if (firstSeq32 > bufferLastSeq32 || lastSeq32 < bufferFirstSeq32)
		{
			// Let's try with sequence numbers in the previous 16 cycle.
			if (this->cycles > 0)
			{
				firstSeq32 -= RtpSeqMod;
				lastSeq32 -= RtpSeqMod;

				// Try again.
				if (firstSeq32 > bufferLastSeq32 || lastSeq32 < bufferFirstSeq32)
				{
					firstSeq32 += RtpSeqMod;
					lastSeq32 += RtpSeqMod;
					inRange = false;
				}
			}
			// Otherwise just return.
			else
			{
				inRange = false;
			}
		}

		if (!inRange)
		{
			MS_WARN_TAG(
			  rtx,
			  "requested packet range not in the buffer [seq:%" PRIu16 ", seq32:%" PRIu32
			  ", bufferFirstSeq32:%" PRIu32 ", bufferLastSeq32:%" PRIu32 "]",
			  seq,
			  firstSeq32,
			  bufferFirstSeq32,
			  bufferLastSeq32);

			return;
		}

		// Look for each requested packet.
		uint64_t now   = DepLibUV::GetTime();
		uint32_t rtt   = (this->rtt != 0u ? this->rtt : DefaultRtt);
		uint32_t seq32 = firstSeq32;
		bool requested{ true };
		size_t containerIdx{ 0 };

		// Some variables for debugging.
		uint16_t origBitmask = bitmask;
		uint16_t sentBitmask{ 0b0000000000000000 };
		bool isFirstPacket{ true };
		bool firstPacketSent{ false };
		uint8_t bitmaskCounter{ 0 };
		bool tooOldPacketFound{ false };

		while (requested || bitmask != 0)
		{
			bool sent = false;

			if (requested)
			{
				for (; bufferIt != this->buffer.end(); ++bufferIt)
				{
					auto currentSeq32 = (*bufferIt).seq32;

					// Found.
					if (currentSeq32 == seq32)
					{
						auto currentPacket = (*bufferIt).packet;
						// Calculate how the elapsed time between the max timestampt seen and
						// the requested packet's timestampt (in ms).
						uint32_t diffTs = this->maxPacketTs - currentPacket->GetTimestamp();
						uint32_t diffMs = diffTs * 1000 / this->params.clockRate;

						// Just provide the packet if no older than MaxRetransmissionDelay ms.
						if (diffMs > MaxRetransmissionDelay)
						{
							if (!tooOldPacketFound)
							{
								// TODO: May we ask for a key frame in this case?

								MS_WARN_TAG(
								  rtx,
								  "ignoring retransmission for too old packet "
								  "[seq:%" PRIu16 ", max age:%" PRIu32 "ms, packet age:%" PRIu32 "ms]",
								  currentPacket->GetSequenceNumber(),
								  MaxRetransmissionDelay,
								  diffMs);

								tooOldPacketFound = true;
							}

							break;
						}

						// Don't resent the packet if it was resent in the last RTT ms.
						uint32_t resentAtTime = (*bufferIt).resentAtTime;

						if ((resentAtTime != 0u) && now - resentAtTime < static_cast<uint64_t>(rtt))
						{
							MS_WARN_TAG(
							  rtx,
							  "ignoring retransmission for a packet already resent in the last RTT ms "
							  "[seq:%" PRIu16 ", rtt:%" PRIu32 "]",
							  currentPacket->GetSequenceNumber(),
							  rtt);

							break;
						}

						// Store the packet in the container and then increment its index.
						container[containerIdx++] = currentPacket;

						// Save when this packet was resent.
						(*bufferIt).resentAtTime = now;

						sent = true;
						if (isFirstPacket)
							firstPacketSent = true;

						break;
					}

					// It can not be after this packet.
					if (currentSeq32 > seq32)
						break;
				}
			}

			requested = (bitmask & 1) != 0;
			bitmask >>= 1;
			++seq32;

			if (!isFirstPacket)
			{
				sentBitmask |= (sent ? 1 : 0) << bitmaskCounter;
				++bitmaskCounter;
			}
			else
			{
				isFirstPacket = false;
			}
		}

		// If not all the requested packets was sent, log it.
		if (!firstPacketSent || origBitmask != sentBitmask)
		{
			MS_DEBUG_TAG(
			  rtx,
			  "could not resend all packets [seq:%" PRIu16
			  ", first:%s, "
			  "bitmask:" MS_UINT16_TO_BINARY_PATTERN ", sent bitmask:" MS_UINT16_TO_BINARY_PATTERN "]",
			  seq,
			  firstPacketSent ? "yes" : "no",
			  MS_UINT16_TO_BINARY(origBitmask),
			  MS_UINT16_TO_BINARY(sentBitmask));
		}
		else
		{
			MS_DEBUG_TAG(
			  rtx,
			  "all packets resent [seq:%" PRIu16 ", bitmask:" MS_UINT16_TO_BINARY_PATTERN "]",
			  seq,
			  MS_UINT16_TO_BINARY(origBitmask));
		}

		// Set the next container element to null.
		container[containerIdx] = nullptr;
	}

	RTC::RTCP::SenderReport* RtpStreamSend::GetRtcpSenderReport(uint64_t now)
	{
		MS_TRACE();

		if (this->counter.GetPacketCount() == 0u)
			return nullptr;

		auto report = new RTC::RTCP::SenderReport();

		report->SetPacketCount(this->counter.GetPacketCount());
		report->SetOctetCount(this->counter.GetBytes());

		Utils::Time::Ntp ntp{};
		Utils::Time::CurrentTimeNtp(ntp);

		report->SetNtpSec(ntp.seconds);
		report->SetNtpFrac(ntp.fractions);

		// Calculate RTP timestamp diff between now and last received RTP packet.
		auto diffMs = static_cast<uint32_t>(now - this->maxPacketMs);
		uint32_t diffTs = diffMs * this->params.clockRate / 1000;

		report->SetRtpTs(this->maxPacketTs + diffTs);

		return report;
	}

	void RtpStreamSend::ClearRetransmissionBuffer()
	{
		MS_TRACE();

		// Delete cloned packets.
		for (auto& bufferItem : this->buffer)
		{
			delete bufferItem.packet;
		}

		// Clear list.
		this->buffer.clear();
	}

	inline void RtpStreamSend::StorePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		if (packet->GetSize() > RTC::MtuSize)
		{
			MS_WARN_TAG(
			  rtp,
			  "packet too big [ssrc:%" PRIu32 ", seq:%" PRIu16 ", size:%zu]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber(),
			  packet->GetSize());

			return;
		}

		// Sum the packet seq number and the number of 16 bits cycles.
		uint32_t packetSeq32 = packet->GetExtendedSequenceNumber();
		BufferItem bufferItem;

		bufferItem.seq32 = packetSeq32;

		// If empty do it easy.
		if (this->buffer.empty())
		{
			auto store = this->storage[0].store;

			bufferItem.packet = packet->Clone(store);
			this->buffer.push_back(bufferItem);

			return;
		}

		// Otherwise, do the stuff.

		Buffer::iterator newBufferIt;
		uint8_t* store{ nullptr };

		// Iterate the buffer in reverse order and find the proper place to store the
		// packet.
		auto bufferItReverse = this->buffer.rbegin();
		for (; bufferItReverse != this->buffer.rend(); ++bufferItReverse)
		{
			auto currentSeq32 = (*bufferItReverse).seq32;

			if (packetSeq32 > currentSeq32)
			{
				// Get a forward iterator pointing to the same element.
				auto it = bufferItReverse.base();

				newBufferIt = this->buffer.insert(it, bufferItem);

				// Exit the loop.
				break;
			}
		}
		// If the packet was older than anything in the buffer, just ignore it.
		// NOTE: This should never happen.
		if (bufferItReverse == this->buffer.rend())
		{
			MS_WARN_TAG(
			  rtp,
			  "ignoring packet older than anything in the buffer [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber());

			return;
		}

		// If the buffer is not full use the next free storage item.
		if (this->buffer.size() - 1 < this->storage.size())
		{
			store = this->storage[this->buffer.size() - 1].store;
		}
		// Otherwise remove the first packet of the buffer and replace its storage area.
		else
		{
			auto& firstBufferItem = *(this->buffer.begin());
			auto firstPacket      = firstBufferItem.packet;

			// Store points to the store used by the first packet.
			store = const_cast<uint8_t*>(firstPacket->GetData());
			// Free the first packet.
			delete firstPacket;
			// Remove the first element in the list.
			this->buffer.pop_front();
		}

		// Update the new buffer item so it points to the cloned packed.
		(*newBufferIt).packet = packet->Clone(store);
	}

	void RtpStreamSend::CheckHealth()
	{
		MS_TRACE();
	}

	void RtpStreamSend::SetRtx(uint8_t payloadType, uint32_t ssrc)
	{
		MS_TRACE();

		this->hasRtx         = true;
		this->rtxPayloadType = payloadType;
		this->rtxSsrc        = ssrc;
		this->rtxSeq         = Utils::Crypto::GetRandomUInt(0u, 0xFFFF);
	}

	void RtpStreamSend::RtxEncode(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		MS_ASSERT(this->hasRtx, "RTX not enabled on this stream");

		packet->RtxEncode(this->rtxPayloadType, this->rtxSsrc, ++this->rtxSeq);
	}

} // namespace RTC
<commit_msg>Fix uint32_t casting that was causing a wrong calculation<commit_after>#define MS_CLASS "RTC::RtpStreamSend"
// #define MS_LOG_DEV

#include "RTC/RtpStreamSend.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"
#include "Utils.hpp"

namespace RTC
{
	/* Static. */

	static constexpr uint32_t RtpSeqMod{ 1 << 16 };
	// Don't retransmit packets older than this (ms).
	// TODO: This must be tunned.
	static constexpr uint32_t MaxRetransmissionDelay{ 4000 };
	static constexpr uint32_t DefaultRtt{ 100 };

	/* Instance methods. */

	RtpStreamSend::RtpStreamSend(RTC::RtpStream::Params& params, size_t bufferSize)
	  : RtpStream::RtpStream(params), storage(bufferSize)
	{
		MS_TRACE();
	}

	RtpStreamSend::~RtpStreamSend()
	{
		MS_TRACE();

		// Clear the RTP buffer.
		ClearRetransmissionBuffer();
	}

	bool RtpStreamSend::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Call the parent method.
		if (!RtpStream::ReceivePacket(packet))
			return false;

		// If bufferSize was given, store the packet into the buffer.
		if (!this->storage.empty())
			StorePacket(packet);

		return true;
	}

	void RtpStreamSend::ReceiveRtcpReceiverReport(RTC::RTCP::ReceiverReport* report)
	{
		MS_TRACE();

		/* Calculate RTT. */

		// Get the compact NTP representation of the current timestamp.
		Utils::Time::Ntp nowNtp{};
		Utils::Time::CurrentTimeNtp(nowNtp);
		uint32_t nowCompactNtp = (nowNtp.seconds & 0x0000FFFF) << 16;

		nowCompactNtp |= (nowNtp.fractions & 0xFFFF0000) >> 16;

		uint32_t lastSr = report->GetLastSenderReport();
		uint32_t dlsr   = report->GetDelaySinceLastSenderReport();
		// RTT in 1/2^16 seconds.
		uint32_t rtt = nowCompactNtp - dlsr - lastSr;

		// RTT in milliseconds.
		this->rtt = ((rtt >> 16) * 1000);
		this->rtt += (static_cast<float>(rtt & 0x0000FFFF) / 65536) * 1000;

		this->totalLost    = report->GetTotalLost();
		this->fractionLost = report->GetFractionLost();
		this->jitter       = report->GetJitter();
	}

	// This method looks for the requested RTP packets and inserts them into the
	// given container (and set to null the next container position).
	void RtpStreamSend::RequestRtpRetransmission(
	  uint16_t seq, uint16_t bitmask, std::vector<RTC::RtpPacket*>& container)
	{
		MS_TRACE();

		// 17: 16 bit mask + the initial sequence number.
		static constexpr size_t MaxRequestedPackets{ 17 };

		// Ensure the container's first element is 0.
		container[0] = nullptr;

		// If NACK is not supported, exit.
		if (!this->params.useNack)
		{
			MS_WARN_TAG(rtx, "NACK not negotiated");

			return;
		}

		// If the buffer is empty just return.
		if (this->buffer.empty())
			return;

		// Convert the given sequence numbers to 32 bits.
		uint32_t firstSeq32 = uint32_t{ seq } + this->cycles;
		uint32_t lastSeq32  = firstSeq32 + MaxRequestedPackets - 1;

		// Number of requested packets cannot be greater than the container size - 1.
		MS_ASSERT(container.size() - 1 >= MaxRequestedPackets, "RtpPacket container is too small");

		auto bufferIt             = this->buffer.begin();
		auto bufferItReverse      = this->buffer.rbegin();
		uint32_t bufferFirstSeq32 = (*bufferIt).seq32;
		uint32_t bufferLastSeq32  = (*bufferItReverse).seq32;
		bool inRange              = true;

		// Requested packet range not found.
		if (firstSeq32 > bufferLastSeq32 || lastSeq32 < bufferFirstSeq32)
		{
			// Let's try with sequence numbers in the previous 16 cycle.
			if (this->cycles > 0)
			{
				firstSeq32 -= RtpSeqMod;
				lastSeq32 -= RtpSeqMod;

				// Try again.
				if (firstSeq32 > bufferLastSeq32 || lastSeq32 < bufferFirstSeq32)
				{
					firstSeq32 += RtpSeqMod;
					lastSeq32 += RtpSeqMod;
					inRange = false;
				}
			}
			// Otherwise just return.
			else
			{
				inRange = false;
			}
		}

		if (!inRange)
		{
			MS_WARN_TAG(
			  rtx,
			  "requested packet range not in the buffer [seq:%" PRIu16 ", seq32:%" PRIu32
			  ", bufferFirstSeq32:%" PRIu32 ", bufferLastSeq32:%" PRIu32 "]",
			  seq,
			  firstSeq32,
			  bufferFirstSeq32,
			  bufferLastSeq32);

			return;
		}

		// Look for each requested packet.
		uint64_t now   = DepLibUV::GetTime();
		uint32_t rtt   = (this->rtt != 0u ? this->rtt : DefaultRtt);
		uint32_t seq32 = firstSeq32;
		bool requested{ true };
		size_t containerIdx{ 0 };

		// Some variables for debugging.
		uint16_t origBitmask = bitmask;
		uint16_t sentBitmask{ 0b0000000000000000 };
		bool isFirstPacket{ true };
		bool firstPacketSent{ false };
		uint8_t bitmaskCounter{ 0 };
		bool tooOldPacketFound{ false };

		while (requested || bitmask != 0)
		{
			bool sent = false;

			if (requested)
			{
				for (; bufferIt != this->buffer.end(); ++bufferIt)
				{
					auto currentSeq32 = (*bufferIt).seq32;

					// Found.
					if (currentSeq32 == seq32)
					{
						auto currentPacket = (*bufferIt).packet;
						// Calculate how the elapsed time between the max timestampt seen and
						// the requested packet's timestampt (in ms).
						uint32_t diffTs = this->maxPacketTs - currentPacket->GetTimestamp();
						uint32_t diffMs = diffTs * 1000 / this->params.clockRate;

						// Just provide the packet if no older than MaxRetransmissionDelay ms.
						if (diffMs > MaxRetransmissionDelay)
						{
							if (!tooOldPacketFound)
							{
								// TODO: May we ask for a key frame in this case?

								MS_WARN_TAG(
								  rtx,
								  "ignoring retransmission for too old packet "
								  "[seq:%" PRIu16 ", max age:%" PRIu32 "ms, packet age:%" PRIu32 "ms]",
								  currentPacket->GetSequenceNumber(),
								  MaxRetransmissionDelay,
								  diffMs);

								tooOldPacketFound = true;
							}

							break;
						}

						// Don't resent the packet if it was resent in the last RTT ms.
						auto resentAtTime = (*bufferIt).resentAtTime;

						if ((resentAtTime != 0u) && now - resentAtTime < static_cast<uint64_t>(rtt))
						{
							MS_WARN_TAG(
							  rtx,
							  "ignoring retransmission for a packet already resent in the last RTT ms "
							  "[seq:%" PRIu16 ", rtt:%" PRIu32 "]",
							  currentPacket->GetSequenceNumber(),
							  rtt);

							break;
						}

						// Store the packet in the container and then increment its index.
						container[containerIdx++] = currentPacket;

						// Save when this packet was resent.
						(*bufferIt).resentAtTime = now;

						sent = true;
						if (isFirstPacket)
							firstPacketSent = true;

						break;
					}

					// It can not be after this packet.
					if (currentSeq32 > seq32)
						break;
				}
			}

			requested = (bitmask & 1) != 0;
			bitmask >>= 1;
			++seq32;

			if (!isFirstPacket)
			{
				sentBitmask |= (sent ? 1 : 0) << bitmaskCounter;
				++bitmaskCounter;
			}
			else
			{
				isFirstPacket = false;
			}
		}

		// If not all the requested packets was sent, log it.
		if (!firstPacketSent || origBitmask != sentBitmask)
		{
			MS_DEBUG_TAG(
			  rtx,
			  "could not resend all packets [seq:%" PRIu16
			  ", first:%s, "
			  "bitmask:" MS_UINT16_TO_BINARY_PATTERN ", sent bitmask:" MS_UINT16_TO_BINARY_PATTERN "]",
			  seq,
			  firstPacketSent ? "yes" : "no",
			  MS_UINT16_TO_BINARY(origBitmask),
			  MS_UINT16_TO_BINARY(sentBitmask));
		}
		else
		{
			MS_DEBUG_TAG(
			  rtx,
			  "all packets resent [seq:%" PRIu16 ", bitmask:" MS_UINT16_TO_BINARY_PATTERN "]",
			  seq,
			  MS_UINT16_TO_BINARY(origBitmask));
		}

		// Set the next container element to null.
		container[containerIdx] = nullptr;
	}

	RTC::RTCP::SenderReport* RtpStreamSend::GetRtcpSenderReport(uint64_t now)
	{
		MS_TRACE();

		if (this->counter.GetPacketCount() == 0u)
			return nullptr;

		auto report = new RTC::RTCP::SenderReport();

		report->SetPacketCount(this->counter.GetPacketCount());
		report->SetOctetCount(this->counter.GetBytes());

		Utils::Time::Ntp ntp{};
		Utils::Time::CurrentTimeNtp(ntp);

		report->SetNtpSec(ntp.seconds);
		report->SetNtpFrac(ntp.fractions);

		// Calculate RTP timestamp diff between now and last received RTP packet.
		auto diffMs = static_cast<uint32_t>(now - this->maxPacketMs);
		uint32_t diffTs = diffMs * this->params.clockRate / 1000;

		report->SetRtpTs(this->maxPacketTs + diffTs);

		return report;
	}

	void RtpStreamSend::ClearRetransmissionBuffer()
	{
		MS_TRACE();

		// Delete cloned packets.
		for (auto& bufferItem : this->buffer)
		{
			delete bufferItem.packet;
		}

		// Clear list.
		this->buffer.clear();
	}

	inline void RtpStreamSend::StorePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		if (packet->GetSize() > RTC::MtuSize)
		{
			MS_WARN_TAG(
			  rtp,
			  "packet too big [ssrc:%" PRIu32 ", seq:%" PRIu16 ", size:%zu]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber(),
			  packet->GetSize());

			return;
		}

		// Sum the packet seq number and the number of 16 bits cycles.
		uint32_t packetSeq32 = packet->GetExtendedSequenceNumber();
		BufferItem bufferItem;

		bufferItem.seq32 = packetSeq32;

		// If empty do it easy.
		if (this->buffer.empty())
		{
			auto store = this->storage[0].store;

			bufferItem.packet = packet->Clone(store);
			this->buffer.push_back(bufferItem);

			return;
		}

		// Otherwise, do the stuff.

		Buffer::iterator newBufferIt;
		uint8_t* store{ nullptr };

		// Iterate the buffer in reverse order and find the proper place to store the
		// packet.
		auto bufferItReverse = this->buffer.rbegin();
		for (; bufferItReverse != this->buffer.rend(); ++bufferItReverse)
		{
			auto currentSeq32 = (*bufferItReverse).seq32;

			if (packetSeq32 > currentSeq32)
			{
				// Get a forward iterator pointing to the same element.
				auto it = bufferItReverse.base();

				newBufferIt = this->buffer.insert(it, bufferItem);

				// Exit the loop.
				break;
			}
		}
		// If the packet was older than anything in the buffer, just ignore it.
		// NOTE: This should never happen.
		if (bufferItReverse == this->buffer.rend())
		{
			MS_WARN_TAG(
			  rtp,
			  "ignoring packet older than anything in the buffer [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber());

			return;
		}

		// If the buffer is not full use the next free storage item.
		if (this->buffer.size() - 1 < this->storage.size())
		{
			store = this->storage[this->buffer.size() - 1].store;
		}
		// Otherwise remove the first packet of the buffer and replace its storage area.
		else
		{
			auto& firstBufferItem = *(this->buffer.begin());
			auto firstPacket      = firstBufferItem.packet;

			// Store points to the store used by the first packet.
			store = const_cast<uint8_t*>(firstPacket->GetData());
			// Free the first packet.
			delete firstPacket;
			// Remove the first element in the list.
			this->buffer.pop_front();
		}

		// Update the new buffer item so it points to the cloned packed.
		(*newBufferIt).packet = packet->Clone(store);
	}

	void RtpStreamSend::CheckHealth()
	{
		MS_TRACE();
	}

	void RtpStreamSend::SetRtx(uint8_t payloadType, uint32_t ssrc)
	{
		MS_TRACE();

		this->hasRtx         = true;
		this->rtxPayloadType = payloadType;
		this->rtxSsrc        = ssrc;
		this->rtxSeq         = Utils::Crypto::GetRandomUInt(0u, 0xFFFF);
	}

	void RtpStreamSend::RtxEncode(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		MS_ASSERT(this->hasRtx, "RTX not enabled on this stream");

		packet->RtxEncode(this->rtxPayloadType, this->rtxSsrc, ++this->rtxSeq);
	}

} // namespace RTC
<|endoftext|>


<commit_before>#include "keymanager.h"

#include <stdexcept>

#include <boost/move/make_unique.hpp>
#include <boost/scoped_array.hpp>

KeyManager::KeyManager(const boost::shared_ptr<INvStorage> &backend, const Config &config)
    : backend_(backend),
      config_(config)
#ifdef BUILD_P11
      ,
      p11_(config.p11)
#endif
{
}

void KeyManager::loadKeys() {
  if (config_.tls.pkey_source == kFile) {
    std::string pkey;
    backend_->loadTlsPkey(&pkey);
    if (!pkey.empty()) {
      if (tmp_pkey_file == nullptr) {
        tmp_pkey_file = boost::movelib::make_unique<TemporaryFile>("tls-pkey");
      }
      tmp_pkey_file->PutContents(pkey);
    }
  }
  if (config_.tls.cert_source == kFile) {
    std::string cert;
    backend_->loadTlsCert(&cert);
    if (!cert.empty()) {
      if (tmp_cert_file == nullptr) {
        tmp_cert_file = boost::movelib::make_unique<TemporaryFile>("tls-cert");
      }
      tmp_cert_file->PutContents(cert);
    }
  }
  if (config_.tls.ca_source == kFile) {
    std::string ca;
    backend_->loadTlsCa(&ca);
    if (!ca.empty()) {
      if (tmp_ca_file == nullptr) {
        tmp_ca_file = boost::movelib::make_unique<TemporaryFile>("tls-ca");
      }
      tmp_ca_file->PutContents(ca);
    }
  }
}

std::string KeyManager::getPkeyFile() const {
  std::string pkey_file;
#ifdef BUILD_P11
  if (config_.tls.pkey_source == kPkcs11) {
    pkey_file = p11_->getTlsPkeyId();
  }
#endif
  if (config_.tls.pkey_source == kFile) {
    if (tmp_pkey_file && !boost::filesystem::is_empty(tmp_pkey_file->PathString())) {
      pkey_file = tmp_pkey_file->PathString();
    }
  }
  return pkey_file;
}

std::string KeyManager::getCertFile() const {
  std::string cert_file;
#ifdef BUILD_P11
  if (config_.tls.cert_source == kPkcs11) {
    cert_file = p11_->getTlsCertId();
  }
#endif
  if (config_.tls.cert_source == kFile) {
    if (tmp_cert_file && !boost::filesystem::is_empty(tmp_cert_file->PathString())) {
      cert_file = tmp_cert_file->PathString();
    }
  }
  return cert_file;
}

std::string KeyManager::getCaFile() const {
  std::string ca_file;
#ifdef BUILD_P11
  if (config_.tls.ca_source == kPkcs11) {
    ca_file = p11_->getTlsCacertId();
  }
#endif
  if (config_.tls.ca_source == kFile) {
    if (tmp_ca_file && !boost::filesystem::is_empty(tmp_ca_file->PathString())) {
      ca_file = tmp_ca_file->PathString();
    }
  }
  return ca_file;
}

std::string KeyManager::getPkey() const {
  std::string pkey;
#ifdef BUILD_P11
  if (config_.tls.pkey_source == kPkcs11) {
    pkey = p11_->getTlsPkeyId();
  }
#endif
  if (config_.tls.pkey_source == kFile) {
    backend_->loadTlsPkey(&pkey);
  }
  return pkey;
}

std::string KeyManager::getCert() const {
  std::string cert;
#ifdef BUILD_P11
  if (config_.tls.cert_source == kPkcs11) {
    cert = p11_->getTlsCertId();
  }
#endif
  if (config_.tls.cert_source == kFile) {
    backend_->loadTlsCert(&cert);
  }
  return cert;
}

std::string KeyManager::getCa() const {
  std::string ca;
#ifdef BUILD_P11
  if (config_.tls.ca_source == kPkcs11) {
    ca = p11_->getTlsCacertId();
  }
#endif
  if (config_.tls.ca_source == kFile) {
    backend_->loadTlsCa(&ca);
  }
  return ca;
}

std::string KeyManager::getCN() const {
  std::string not_found_cert_message = "Certificate is not found, can't extract device_id";
  std::string cert;
  if (config_.tls.cert_source == kFile) {
    if (!backend_->loadTlsCert(&cert)) {
      throw std::runtime_error(not_found_cert_message);
    }
  } else {  // kPkcs11
#ifdef BUILD_P11
    if (!p11_->readTlsCert(&cert)) {
      throw std::runtime_error(not_found_cert_message);
    }
#else
    throw std::runtime_error("Aktualizr was built without PKCS#11 support, can't extract device_id");
#endif
  }

  BIO *bio = BIO_new_mem_buf(const_cast<char *>(cert.c_str()), (int)cert.size());
  X509 *x = PEM_read_bio_X509(bio, NULL, 0, NULL);
  BIO_free_all(bio);
  if (!x) throw std::runtime_error("Could not parse certificate");

  int len = X509_NAME_get_text_by_NID(X509_get_subject_name(x), NID_commonName, NULL, 0);
  if (len < 0) {
    X509_free(x);
    throw std::runtime_error("Could not get CN from certificate");
  }
  boost::scoped_array<char> buf(new char[len + 1]);
  X509_NAME_get_text_by_NID(X509_get_subject_name(x), NID_commonName, buf.get(), len + 1);
  std::string cn(buf.get());
  X509_free(x);
  return cn;
}

void KeyManager::copyCertsToCurl(HttpInterface *http) {
  std::string pkey = getPkey();
  std::string cert = getCert();
  std::string ca = getCa();

  if (pkey.size() && cert.size() && ca.size()) {
    http->setCerts(ca, config_.tls.ca_source, cert, config_.tls.cert_source, pkey, config_.tls.pkey_source);
  }
}

Json::Value KeyManager::signTuf(const Json::Value &in_data) {
  ENGINE *crypto_engine = NULL;
  std::string private_key;
#ifdef BUILD_P11
  if (config_.uptane.key_source == kPkcs11) crypto_engine = p11_->getEngine();
#endif
  if (config_.uptane.key_source == kFile) {
    backend_->loadPrimaryPrivate(&private_key);
  }
  std::string b64sig =
      Utils::toBase64(Crypto::RSAPSSSign(crypto_engine, private_key, Json::FastWriter().write(in_data)));
  Json::Value signature;
  signature["method"] = "rsassa-pss";
  signature["sig"] = b64sig;

  Json::Value out_data;
  signature["keyid"] = Crypto::getKeyId(getUptanePublicKey());
  out_data["signed"] = in_data;
  out_data["signatures"] = Json::Value(Json::arrayValue);
  out_data["signatures"].append(signature);
  return out_data;
}

std::string KeyManager::getUptanePublicKey() {
  std::string primary_public;
  if (config_.uptane.key_source == kFile) {
    if (!backend_->loadPrimaryPublic(&primary_public)) {
      throw std::runtime_error("Could not get uptane public key!");
    }
  } else {
#ifdef BUILD_P11
    // dummy read to check if the key is present
    if (!p11_->readUptanePublicKey(&primary_public)) {
      throw std::runtime_error("Could not get uptane public key!");
    }
#else
    throw std::runtime_error("Aktualizr was built without pkcs11 support!");
#endif
  }
  return primary_public;
}

std::string KeyManager::generateUptaneKeyPair() {
  std::string primary_public;

  if (config_.uptane.key_source == kFile) {
    std::string primary_private;
    if (!backend_->loadPrimaryKeys(&primary_public, &primary_private)) {
      if (Crypto::generateRSAKeyPair(&primary_public, &primary_private)) {
        backend_->storePrimaryKeys(primary_public, primary_private);
      }
    }
    if (primary_public.empty() && primary_private.empty()) {
      throw std::runtime_error("Could not get uptane keys");
    }
  } else {
#ifdef BUILD_P11
    // dummy read to check if the key is present
    if (!p11_->readUptanePublicKey(&primary_public)) {
      p11_->generateUptaneKeyPair();
    }
    // really read the key
    if (primary_public.empty() && !p11_->readUptanePublicKey(&primary_public)) {
      throw std::runtime_error("Could not get uptane keys");
    }
    return primary_public;
#else
    throw std::runtime_error("Aktualizr was built without pkcs11 support!");
#endif
  }
  return primary_public;
}
<commit_msg>Pass p11 key id to RSAPSSSign<commit_after>#include "keymanager.h"

#include <stdexcept>

#include <boost/move/make_unique.hpp>
#include <boost/scoped_array.hpp>

KeyManager::KeyManager(const boost::shared_ptr<INvStorage> &backend, const Config &config)
    : backend_(backend),
      config_(config)
#ifdef BUILD_P11
      ,
      p11_(config.p11)
#endif
{
}

void KeyManager::loadKeys() {
  if (config_.tls.pkey_source == kFile) {
    std::string pkey;
    backend_->loadTlsPkey(&pkey);
    if (!pkey.empty()) {
      if (tmp_pkey_file == nullptr) {
        tmp_pkey_file = boost::movelib::make_unique<TemporaryFile>("tls-pkey");
      }
      tmp_pkey_file->PutContents(pkey);
    }
  }
  if (config_.tls.cert_source == kFile) {
    std::string cert;
    backend_->loadTlsCert(&cert);
    if (!cert.empty()) {
      if (tmp_cert_file == nullptr) {
        tmp_cert_file = boost::movelib::make_unique<TemporaryFile>("tls-cert");
      }
      tmp_cert_file->PutContents(cert);
    }
  }
  if (config_.tls.ca_source == kFile) {
    std::string ca;
    backend_->loadTlsCa(&ca);
    if (!ca.empty()) {
      if (tmp_ca_file == nullptr) {
        tmp_ca_file = boost::movelib::make_unique<TemporaryFile>("tls-ca");
      }
      tmp_ca_file->PutContents(ca);
    }
  }
}

std::string KeyManager::getPkeyFile() const {
  std::string pkey_file;
#ifdef BUILD_P11
  if (config_.tls.pkey_source == kPkcs11) {
    pkey_file = p11_->getTlsPkeyId();
  }
#endif
  if (config_.tls.pkey_source == kFile) {
    if (tmp_pkey_file && !boost::filesystem::is_empty(tmp_pkey_file->PathString())) {
      pkey_file = tmp_pkey_file->PathString();
    }
  }
  return pkey_file;
}

std::string KeyManager::getCertFile() const {
  std::string cert_file;
#ifdef BUILD_P11
  if (config_.tls.cert_source == kPkcs11) {
    cert_file = p11_->getTlsCertId();
  }
#endif
  if (config_.tls.cert_source == kFile) {
    if (tmp_cert_file && !boost::filesystem::is_empty(tmp_cert_file->PathString())) {
      cert_file = tmp_cert_file->PathString();
    }
  }
  return cert_file;
}

std::string KeyManager::getCaFile() const {
  std::string ca_file;
#ifdef BUILD_P11
  if (config_.tls.ca_source == kPkcs11) {
    ca_file = p11_->getTlsCacertId();
  }
#endif
  if (config_.tls.ca_source == kFile) {
    if (tmp_ca_file && !boost::filesystem::is_empty(tmp_ca_file->PathString())) {
      ca_file = tmp_ca_file->PathString();
    }
  }
  return ca_file;
}

std::string KeyManager::getPkey() const {
  std::string pkey;
#ifdef BUILD_P11
  if (config_.tls.pkey_source == kPkcs11) {
    pkey = p11_->getTlsPkeyId();
  }
#endif
  if (config_.tls.pkey_source == kFile) {
    backend_->loadTlsPkey(&pkey);
  }
  return pkey;
}

std::string KeyManager::getCert() const {
  std::string cert;
#ifdef BUILD_P11
  if (config_.tls.cert_source == kPkcs11) {
    cert = p11_->getTlsCertId();
  }
#endif
  if (config_.tls.cert_source == kFile) {
    backend_->loadTlsCert(&cert);
  }
  return cert;
}

std::string KeyManager::getCa() const {
  std::string ca;
#ifdef BUILD_P11
  if (config_.tls.ca_source == kPkcs11) {
    ca = p11_->getTlsCacertId();
  }
#endif
  if (config_.tls.ca_source == kFile) {
    backend_->loadTlsCa(&ca);
  }
  return ca;
}

std::string KeyManager::getCN() const {
  std::string not_found_cert_message = "Certificate is not found, can't extract device_id";
  std::string cert;
  if (config_.tls.cert_source == kFile) {
    if (!backend_->loadTlsCert(&cert)) {
      throw std::runtime_error(not_found_cert_message);
    }
  } else {  // kPkcs11
#ifdef BUILD_P11
    if (!p11_->readTlsCert(&cert)) {
      throw std::runtime_error(not_found_cert_message);
    }
#else
    throw std::runtime_error("Aktualizr was built without PKCS#11 support, can't extract device_id");
#endif
  }

  BIO *bio = BIO_new_mem_buf(const_cast<char *>(cert.c_str()), (int)cert.size());
  X509 *x = PEM_read_bio_X509(bio, NULL, 0, NULL);
  BIO_free_all(bio);
  if (!x) throw std::runtime_error("Could not parse certificate");

  int len = X509_NAME_get_text_by_NID(X509_get_subject_name(x), NID_commonName, NULL, 0);
  if (len < 0) {
    X509_free(x);
    throw std::runtime_error("Could not get CN from certificate");
  }
  boost::scoped_array<char> buf(new char[len + 1]);
  X509_NAME_get_text_by_NID(X509_get_subject_name(x), NID_commonName, buf.get(), len + 1);
  std::string cn(buf.get());
  X509_free(x);
  return cn;
}

void KeyManager::copyCertsToCurl(HttpInterface *http) {
  std::string pkey = getPkey();
  std::string cert = getCert();
  std::string ca = getCa();

  if (pkey.size() && cert.size() && ca.size()) {
    http->setCerts(ca, config_.tls.ca_source, cert, config_.tls.cert_source, pkey, config_.tls.pkey_source);
  }
}

Json::Value KeyManager::signTuf(const Json::Value &in_data) {
  ENGINE *crypto_engine = NULL;
  std::string private_key;
#ifdef BUILD_P11
  if (config_.uptane.key_source == kPkcs11) {
    crypto_engine = p11_->getEngine();
    private_key = config_.p11.uptane_key_id;
  }
#endif
  if (config_.uptane.key_source == kFile) {
    backend_->loadPrimaryPrivate(&private_key);
  }
  std::string b64sig =
      Utils::toBase64(Crypto::RSAPSSSign(crypto_engine, private_key, Json::FastWriter().write(in_data)));
  Json::Value signature;
  signature["method"] = "rsassa-pss";
  signature["sig"] = b64sig;

  Json::Value out_data;
  signature["keyid"] = Crypto::getKeyId(getUptanePublicKey());
  out_data["signed"] = in_data;
  out_data["signatures"] = Json::Value(Json::arrayValue);
  out_data["signatures"].append(signature);
  return out_data;
}

std::string KeyManager::getUptanePublicKey() {
  std::string primary_public;
  if (config_.uptane.key_source == kFile) {
    if (!backend_->loadPrimaryPublic(&primary_public)) {
      throw std::runtime_error("Could not get uptane public key!");
    }
  } else {
#ifdef BUILD_P11
    // dummy read to check if the key is present
    if (!p11_->readUptanePublicKey(&primary_public)) {
      throw std::runtime_error("Could not get uptane public key!");
    }
#else
    throw std::runtime_error("Aktualizr was built without pkcs11 support!");
#endif
  }
  return primary_public;
}

std::string KeyManager::generateUptaneKeyPair() {
  std::string primary_public;

  if (config_.uptane.key_source == kFile) {
    std::string primary_private;
    if (!backend_->loadPrimaryKeys(&primary_public, &primary_private)) {
      if (Crypto::generateRSAKeyPair(&primary_public, &primary_private)) {
        backend_->storePrimaryKeys(primary_public, primary_private);
      }
    }
    if (primary_public.empty() && primary_private.empty()) {
      throw std::runtime_error("Could not get uptane keys");
    }
  } else {
#ifdef BUILD_P11
    // dummy read to check if the key is present
    if (!p11_->readUptanePublicKey(&primary_public)) {
      p11_->generateUptaneKeyPair();
    }
    // really read the key
    if (primary_public.empty() && !p11_->readUptanePublicKey(&primary_public)) {
      throw std::runtime_error("Could not get uptane keys");
    }
    return primary_public;
#else
    throw std::runtime_error("Aktualizr was built without pkcs11 support!");
#endif
  }
  return primary_public;
}
<|endoftext|>