<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

// Generator using Herwig as an external generator
// The main Herwig options are accessable for the user through this interface.
// Uses the THerwig implementation of TGenerator.

#include "AliGenHerwig.h"
#include "AliHerwigRndm.h"
#include "AliRun.h"

#include <TParticle.h>
#include "THerwig6.h"

#include "Riostream.h"
#include "AliMC.h"

ClassImp(AliGenHerwig)

AliGenHerwig::AliGenHerwig()
{
// Constructor
}

AliGenHerwig::AliGenHerwig(Int_t npart)
    :AliGenMC(npart)
{
    SetBeamMomenta();
    SetTarget();
    SetProjectile();
    SetStrucFunc(kGRVLO98);
    fKeep=0;
    fTrigger=0;
    fDecaysOff=1;
    fSelectAll=0;
    fFlavor=0;
    fPtHardMin=0.;
    fPtRMS=0.0;
    fEnSoft=1.0;
    fMaxPr=10;
    fMaxErrors=1000;
    // Set random number generator
    AliHerwigRndm::SetHerwigRandom(GetRandom());
}

AliGenHerwig::AliGenHerwig(const AliGenHerwig & Herwig)
    :AliGenMC(Herwig)
{
// Copy constructor
    Herwig.Copy(*this);
}

AliGenHerwig::~AliGenHerwig()
{
// Destructor
}

void AliGenHerwig::Init()
{
// Initialisation
  fTarget.Resize(8);
  fProjectile.Resize(8);
  SetMC(new THerwig6());
  fHerwig=(THerwig6*) fMCEvGen;
  // initialize common blocks
  fHerwig->Initialize(fProjectile, fTarget, fMomentum1, fMomentum2, fProcess);
  // reset parameters according to user needs
  InitPDF();
  fHerwig->SetPTMIN(fPtHardMin);
  fHerwig->SetPTRMS(fPtRMS);
  fHerwig->SetMAXPR(fMaxPr);
  fHerwig->SetMAXER(fMaxErrors);
  fHerwig->SetENSOF(fEnSoft);
  // compute parameter dependent constants
  fHerwig->PrepareRun();
}

void AliGenHerwig::InitPDF()
{
  switch(fStrucFunc)
    {
    case kGRVLO:
      fModPDF=5;
      fAutPDF="GRV";
      break;
    case kGRVHO:
      fModPDF=6;
      fAutPDF="GRV";
      break;
    case kGRVLO98:
      fModPDF=12;
      fAutPDF="GRV";
      break;
    case kMRSDminus:
      fModPDF=31;
      fAutPDF="MRS";
      break;
    case kMRSD0:
      fModPDF=30;
      fAutPDF="MRS";
      break;
    case kMRSG:
      fModPDF=41;
      fAutPDF="MRS";
      break;
    case kMRSTcgLO:
      fModPDF=72;
      fAutPDF="MRS";
      break;
    case kCTEQ4M:
      fModPDF=34;
      fAutPDF="CTEQ";
      break;
    case kCTEQ5L:
      fModPDF=46;
      fAutPDF="CTEQ";
      break;
    default:
      cerr << "This structure function is not inplemented " << fStrucFunc << endl;
      break;
    }
  fAutPDF.Resize(20);
  fHerwig->SetMODPDF(1,fModPDF);
  fHerwig->SetMODPDF(2,fModPDF);
  fHerwig->SetAUTPDF(1,fAutPDF);
  fHerwig->SetAUTPDF(2,fAutPDF);
}

void AliGenHerwig::Generate()
{
  // Generate one event

  Float_t polar[3] =   {0,0,0};
  Float_t origin[3]=   {0,0,0};
  Float_t origin0[3]=  {0,0,0};
  Float_t p[4], random[6];

  static TClonesArray *particles;
  //  converts from mm/c to s
  const Float_t kconv=0.001/2.999792458e8;
  //
  Int_t nt=0;
  Int_t jev=0;
  Int_t j, kf, ks, imo;
  kf=0;

  if(!particles) particles=new TClonesArray("TParticle",10000);

  fTrials=0;
  for (j=0;j<3;j++) origin0[j]=fOrigin[j];
  if(fVertexSmear==kPerEvent) {
    Rndm(random,6);
    for (j=0;j<3;j++) {
      origin0[j]+=fOsigma[j]*TMath::Cos(2*random[2*j]*TMath::Pi())*
	TMath::Sqrt(-2*TMath::Log(random[2*j+1]));
    }
  }

  while(1)
    {
	fHerwig->GenerateEvent();
	fTrials++;
	fHerwig->ImportParticles(particles,"All");
	Int_t np = particles->GetEntriesFast()-1;
	printf("Particles from Herwig %d \n", np);

	if (np == 0 ) continue;

	Int_t nc=0;

	Int_t * newPos = new Int_t[np];
	for (Int_t i = 0; i<np; i++) *(newPos+i)=-1;

	for (Int_t i = 0; i<np; i++) {
	    TParticle *  iparticle       = (TParticle *) particles->At(i);
	    imo = iparticle->GetFirstMother();
	    kf        = iparticle->GetPdgCode();
	    ks        = iparticle->GetStatusCode();
	    if (ks != 3 &&
		KinematicSelection(iparticle,0))
	    {
		nc++;
		p[0]=iparticle->Px();
		p[1]=iparticle->Py();
		p[2]=iparticle->Pz();
		p[3]=iparticle->Energy();
		origin[0]=origin0[0]+iparticle->Vx()/10;
		origin[1]=origin0[1]+iparticle->Vy()/10;
		origin[2]=origin0[2]+iparticle->Vz()/10;
		Float_t tof = kconv*iparticle->T();
		Int_t   iparent = (imo > -1) ? newPos[imo] : -1;
		Int_t   trackIt = (ks == 1) && fTrackIt;
		PushTrack(trackIt, iparent, kf,
			  p[0], p[1], p[2], p[3],
			  origin[0], origin[1], origin[2],
			  tof,
			  polar[0], polar[1], polar[2],
			  kPPrimary, nt, 1., ks);
		KeepTrack(nt);
		newPos[i]=nt;
	    } // end of if: selection of particle
	} // end of for: particle loop
	if (newPos) delete[] newPos;
	printf("\n I've put %i particles on the stack \n",nc);
	//      MakeHeader();
	printf("nc: %d %d\n", nc, fNpart);

	if (nc > 0) {
	    jev+=nc;
	    if (jev >= fNpart || fNpart == -1) {
		fKineBias=Float_t(fNpart)/Float_t(fTrials);
		printf("\n Trials: %i %i %i\n",fTrials, fNpart, jev);
		break;
	    }
	}
    }
  SetHighWaterMark(nt);
//  adjust weight due to kinematic selection
  AdjustWeights();
//  get cross-section
  fXsection=fHerwig->GetAVWGT();
}

void AliGenHerwig::AdjustWeights()
{
// Adjust the weights after generation of all events
    TParticle *part;
    Int_t ntrack=gAlice->GetMCApp()->GetNtrack();
    for (Int_t i=0; i<ntrack; i++) {
        part= gAlice->GetMCApp()->Particle(i);
        part->SetWeight(part->GetWeight()*fKineBias);
    }
}

void AliGenHerwig::KeepFullEvent()
{
    fKeep=1;
}

Bool_t AliGenHerwig::DaughtersSelection(TParticle* iparticle, TClonesArray* particles)
{
//
// Looks recursively if one of the daughters has been selected
//
//    printf("\n Consider daughters %d:",iparticle->GetPdgCode());
    Int_t imin=-1;
    Int_t imax=-1;
    Int_t i;
    Bool_t hasDaughters= (iparticle->GetFirstDaughter() >=0);
    Bool_t selected=kFALSE;
    if (hasDaughters) {
	imin=iparticle->GetFirstDaughter();
	imax=iparticle->GetLastDaughter();
	for (i=imin; i<= imax; i++){
	    TParticle *  jparticle       = (TParticle *) particles->At(i);
	    Int_t ip=jparticle->GetPdgCode();
	    if (KinematicSelection(jparticle,0)&&SelectFlavor(ip)) {
		selected=kTRUE; break;
	    }
	    if (DaughtersSelection(jparticle, particles)) {selected=kTRUE; break; }
	}
    } else {
	return kFALSE;
    }

    return selected;
}

Bool_t AliGenHerwig::SelectFlavor(Int_t pid)
{
// Select flavor of particle
// 0: all
// 4: charm and beauty
// 5: beauty
    if (fFlavor == 0) return kTRUE;

    Int_t ifl=TMath::Abs(pid/100);
    if (ifl > 10) ifl/=10;
    return (fFlavor == ifl);
}

Bool_t AliGenHerwig::Stable(TParticle*  particle)
{
// Return true for a stable particle
//
    Int_t kf = TMath::Abs(particle->GetPdgCode());

    if ( (particle->GetFirstDaughter() < 0 ) || (kf == 1000*fFlavor+122))

    {
	return kTRUE;
    } else {
	return kFALSE;
    }
}

void AliGenHerwig::FinishRun()
{
  fHerwig->Hwefin();
}

AliGenHerwig& AliGenHerwig::operator=(const  AliGenHerwig& rhs)
{
// Assignment operator
    rhs.Copy(*this);
    return (*this);
}

<commit_msg>Initialization of data members in the default constructor<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

// Generator using Herwig as an external generator
// The main Herwig options are accessable for the user through this interface.
// Uses the THerwig implementation of TGenerator.

#include "AliGenHerwig.h"
#include "AliHerwigRndm.h"
#include "AliRun.h"

#include <TParticle.h>
#include "THerwig6.h"

#include "Riostream.h"
#include "AliMC.h"

ClassImp(AliGenHerwig)

  AliGenHerwig::AliGenHerwig() :
    AliGenMC(),
    fAutPDF("GRV"),
    fModPDF(5),
    fStrucFunc(kGRVHO),
    fKeep(0),
    fDecaysOff(1),
    fTrigger(0),
    fSelectAll(0),
    fFlavor(0),
    fEnergyCMS(14000),
    fMomentum1(7000),
    fMomentum2(7000),
    fKineBias(1),
    fTrials(0),
    fXsection(0),
    fHerwig(0x0),
    fProcess(0),
    fPtHardMin(0),
    fPtRMS(0),
    fMaxPr(10),
    fMaxErrors(1000),
    fEnSoft(1)
{
// Constructor
}

AliGenHerwig::AliGenHerwig(Int_t npart)
    :AliGenMC(npart)
{
    SetBeamMomenta();
    SetTarget();
    SetProjectile();
    SetStrucFunc(kGRVLO98);
    fKeep=0;
    fTrigger=0;
    fDecaysOff=1;
    fSelectAll=0;
    fFlavor=0;
    fPtHardMin=0.;
    fPtRMS=0.0;
    fEnSoft=1.0;
    fMaxPr=10;
    fMaxErrors=1000;
    // Set random number generator
    AliHerwigRndm::SetHerwigRandom(GetRandom());
}

AliGenHerwig::AliGenHerwig(const AliGenHerwig & Herwig)
    :AliGenMC(Herwig)
{
// Copy constructor
    Herwig.Copy(*this);
}

AliGenHerwig::~AliGenHerwig()
{
// Destructor
}

void AliGenHerwig::Init()
{
// Initialisation
  fTarget.Resize(8);
  fProjectile.Resize(8);
  SetMC(new THerwig6());
  fHerwig=(THerwig6*) fMCEvGen;
  // initialize common blocks
  fHerwig->Initialize(fProjectile, fTarget, fMomentum1, fMomentum2, fProcess);
  // reset parameters according to user needs
  InitPDF();
  fHerwig->SetPTMIN(fPtHardMin);
  fHerwig->SetPTRMS(fPtRMS);
  fHerwig->SetMAXPR(fMaxPr);
  fHerwig->SetMAXER(fMaxErrors);
  fHerwig->SetENSOF(fEnSoft);
  // compute parameter dependent constants
  fHerwig->PrepareRun();
}

void AliGenHerwig::InitPDF()
{
  switch(fStrucFunc)
    {
    case kGRVLO:
      fModPDF=5;
      fAutPDF="GRV";
      break;
    case kGRVHO:
      fModPDF=6;
      fAutPDF="GRV";
      break;
    case kGRVLO98:
      fModPDF=12;
      fAutPDF="GRV";
      break;
    case kMRSDminus:
      fModPDF=31;
      fAutPDF="MRS";
      break;
    case kMRSD0:
      fModPDF=30;
      fAutPDF="MRS";
      break;
    case kMRSG:
      fModPDF=41;
      fAutPDF="MRS";
      break;
    case kMRSTcgLO:
      fModPDF=72;
      fAutPDF="MRS";
      break;
    case kCTEQ4M:
      fModPDF=34;
      fAutPDF="CTEQ";
      break;
    case kCTEQ5L:
      fModPDF=46;
      fAutPDF="CTEQ";
      break;
    default:
      cerr << "This structure function is not inplemented " << fStrucFunc << endl;
      break;
    }
  fAutPDF.Resize(20);
  fHerwig->SetMODPDF(1,fModPDF);
  fHerwig->SetMODPDF(2,fModPDF);
  fHerwig->SetAUTPDF(1,fAutPDF);
  fHerwig->SetAUTPDF(2,fAutPDF);
}

void AliGenHerwig::Generate()
{
  // Generate one event

  Float_t polar[3] =   {0,0,0};
  Float_t origin[3]=   {0,0,0};
  Float_t origin0[3]=  {0,0,0};
  Float_t p[4], random[6];

  static TClonesArray *particles;
  //  converts from mm/c to s
  const Float_t kconv=0.001/2.999792458e8;
  //
  Int_t nt=0;
  Int_t jev=0;
  Int_t j, kf, ks, imo;
  kf=0;

  if(!particles) particles=new TClonesArray("TParticle",10000);

  fTrials=0;
  for (j=0;j<3;j++) origin0[j]=fOrigin[j];
  if(fVertexSmear==kPerEvent) {
    Rndm(random,6);
    for (j=0;j<3;j++) {
      origin0[j]+=fOsigma[j]*TMath::Cos(2*random[2*j]*TMath::Pi())*
	TMath::Sqrt(-2*TMath::Log(random[2*j+1]));
    }
  }

  while(1)
    {
	fHerwig->GenerateEvent();
	fTrials++;
	fHerwig->ImportParticles(particles,"All");
	Int_t np = particles->GetEntriesFast()-1;
	printf("Particles from Herwig %d \n", np);

	if (np == 0 ) continue;

	Int_t nc=0;

	Int_t * newPos = new Int_t[np];
	for (Int_t i = 0; i<np; i++) *(newPos+i)=-1;

	for (Int_t i = 0; i<np; i++) {
	    TParticle *  iparticle       = (TParticle *) particles->At(i);
	    imo = iparticle->GetFirstMother();
	    kf        = iparticle->GetPdgCode();
	    ks        = iparticle->GetStatusCode();
	    if (ks != 3 &&
		KinematicSelection(iparticle,0))
	    {
		nc++;
		p[0]=iparticle->Px();
		p[1]=iparticle->Py();
		p[2]=iparticle->Pz();
		p[3]=iparticle->Energy();
		origin[0]=origin0[0]+iparticle->Vx()/10;
		origin[1]=origin0[1]+iparticle->Vy()/10;
		origin[2]=origin0[2]+iparticle->Vz()/10;
		Float_t tof = kconv*iparticle->T();
		Int_t   iparent = (imo > -1) ? newPos[imo] : -1;
		Int_t   trackIt = (ks == 1) && fTrackIt;
		PushTrack(trackIt, iparent, kf,
			  p[0], p[1], p[2], p[3],
			  origin[0], origin[1], origin[2],
			  tof,
			  polar[0], polar[1], polar[2],
			  kPPrimary, nt, 1., ks);
		KeepTrack(nt);
		newPos[i]=nt;
	    } // end of if: selection of particle
	} // end of for: particle loop
	if (newPos) delete[] newPos;
	printf("\n I've put %i particles on the stack \n",nc);
	//      MakeHeader();
	printf("nc: %d %d\n", nc, fNpart);

	if (nc > 0) {
	    jev+=nc;
	    if (jev >= fNpart || fNpart == -1) {
		fKineBias=Float_t(fNpart)/Float_t(fTrials);
		printf("\n Trials: %i %i %i\n",fTrials, fNpart, jev);
		break;
	    }
	}
    }
  SetHighWaterMark(nt);
//  adjust weight due to kinematic selection
  AdjustWeights();
//  get cross-section
  fXsection=fHerwig->GetAVWGT();
}

void AliGenHerwig::AdjustWeights()
{
// Adjust the weights after generation of all events
    TParticle *part;
    Int_t ntrack=gAlice->GetMCApp()->GetNtrack();
    for (Int_t i=0; i<ntrack; i++) {
        part= gAlice->GetMCApp()->Particle(i);
        part->SetWeight(part->GetWeight()*fKineBias);
    }
}

void AliGenHerwig::KeepFullEvent()
{
    fKeep=1;
}

Bool_t AliGenHerwig::DaughtersSelection(TParticle* iparticle, TClonesArray* particles)
{
//
// Looks recursively if one of the daughters has been selected
//
//    printf("\n Consider daughters %d:",iparticle->GetPdgCode());
    Int_t imin=-1;
    Int_t imax=-1;
    Int_t i;
    Bool_t hasDaughters= (iparticle->GetFirstDaughter() >=0);
    Bool_t selected=kFALSE;
    if (hasDaughters) {
	imin=iparticle->GetFirstDaughter();
	imax=iparticle->GetLastDaughter();
	for (i=imin; i<= imax; i++){
	    TParticle *  jparticle       = (TParticle *) particles->At(i);
	    Int_t ip=jparticle->GetPdgCode();
	    if (KinematicSelection(jparticle,0)&&SelectFlavor(ip)) {
		selected=kTRUE; break;
	    }
	    if (DaughtersSelection(jparticle, particles)) {selected=kTRUE; break; }
	}
    } else {
	return kFALSE;
    }

    return selected;
}

Bool_t AliGenHerwig::SelectFlavor(Int_t pid)
{
// Select flavor of particle
// 0: all
// 4: charm and beauty
// 5: beauty
    if (fFlavor == 0) return kTRUE;

    Int_t ifl=TMath::Abs(pid/100);
    if (ifl > 10) ifl/=10;
    return (fFlavor == ifl);
}

Bool_t AliGenHerwig::Stable(TParticle*  particle)
{
// Return true for a stable particle
//
    Int_t kf = TMath::Abs(particle->GetPdgCode());

    if ( (particle->GetFirstDaughter() < 0 ) || (kf == 1000*fFlavor+122))

    {
	return kTRUE;
    } else {
	return kFALSE;
    }
}

void AliGenHerwig::FinishRun()
{
  fHerwig->Hwefin();
}

AliGenHerwig& AliGenHerwig::operator=(const  AliGenHerwig& rhs)
{
// Assignment operator
    rhs.Copy(*this);
    return (*this);
}

<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/slobrok/sbmirror.h>
#include <vespa/config/common/configsystem.h>
#include <vespa/config/common/exceptions.h>
#include <vespa/fnet/frt/frt.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/time.h>
#include <vespa/fastos/app.h>
#include <sys/time.h>
#include <thread>
#include <cstdlib>

#include <vespa/log/log.h>
LOG_SETUP("vespa-proton-cmd");

namespace pandora::rtc_cmd {

class App : public FastOS_Application
{
private:
    App(const App &);
    App& operator=(const App &);

    std::unique_ptr<fnet::frt::StandaloneFRT> _frt;
    FRT_Target     *_target;
    FRT_RPCRequest *_req;

public:
    App() : _frt(),
            _target(nullptr),
            _req(nullptr) {}
    virtual ~App()
    {
        assert(!_frt);
        assert(_target == nullptr);
        assert(_req == nullptr);
    }

    int usage()
    {
        fprintf(stderr, "usage: %s <port|spec|--local|--id=name> <cmd> [args]\n", _argv[0]);
        fprintf(stderr, "die\n");
        fprintf(stderr, "getProtonStatus\n");
        fprintf(stderr, "getState\n");
        fprintf(stderr, "monitor\n");
        fprintf(stderr, "triggerFlush\n");
        fprintf(stderr, "prepareRestart\n");
        return 1;
    }

    void initRPC()
    {
        _frt = std::make_unique<fnet::frt::StandaloneFRT>();
        _req = _frt->supervisor().AllocRPCRequest();
    }

    void invokeRPC(bool print, double timeout=5.0)
    {
        if (_req == nullptr)
            return;

        _target->InvokeSync(_req, timeout);
        if (print || _req->IsError())
            _req->Print(0);
    }

    void finiRPC()
    {
        if (_req != nullptr) {
            _req->SubRef();
            _req = nullptr;
        }
        if (_target != nullptr) {
            _target->SubRef();
            _target = nullptr;
        }
        if (_frt) {
            _frt.reset();
        }
    }

    void
    monitorLoop();

    void
    scanSpecs(slobrok::api::MirrorAPI::SpecList &specs,
              const std::string &me,
              std::string &service,
              std::string &spec,
              int &found)
    {
        for (size_t j = 0; j < specs.size(); ++j) {
            if (specs[j].first == service)
                continue;
            if (specs[j].second.compare(0, me.length(), me) == 0) {
                service = specs[j].first;
                spec = specs[j].second;
                printf("found local RTC '%s' with connection spec %s\n",
                       specs[j].first.c_str(), spec.c_str());
                ++found;
            }
        }
    }

    std::string findRTC() {
        std::string me = "tcp/";
        me += vespalib::HostName::get().c_str();
        me += ":";

        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";
        std::string rtcPattern2 = "*/search/cluster.*/*/realtimecontroller";
        std::string rtcPattern3 = "*/search/*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                fprintf(stderr,
                        "ERROR: no data from service location broker\n");
                std::_Exit(1);
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(rtcPattern);
            slobrok::api::MirrorAPI::SpecList specs2 = sbmirror.lookup(rtcPattern2);
            slobrok::api::MirrorAPI::SpecList specs3 = sbmirror.lookup(rtcPattern3);

            int found = 0;
            std::string service;
            std::string spec;

            printf("looking for RTCs matching '%s' (length %d)\n",
                   me.c_str(), (int)me.length());
            scanSpecs(specs, me, service, spec, found);
            scanSpecs(specs2, me, service, spec, found);
            scanSpecs(specs3, me, service, spec, found);
            if (found > 1) {
                fprintf(stderr, "found more than one local RTC, you must use --id=<name>\n");
                std::_Exit(1);
            }
            if (found < 1) {
                fprintf(stderr, "found no local RTC, you must use --id=<name> (list follows):\n");
                for (size_t j = 0; j < specs.size(); ++j) {
                    printf("RTC name %s with connection spec %s\n",
                           specs[j].first.c_str(), specs[j].second.c_str());
                }
                std::_Exit(1);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            fprintf(stderr, "ERROR: failed to get service location broker configuration\n");
            std::_Exit(1);
        }
        return "";
    }

    std::string findRTC(std::string id) {
        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                throw std::runtime_error("ERROR: no data from service location broker");
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(id);

            int found = 0;
            std::string spec;

            for (size_t j = 0; j < specs.size(); ++j) {
                std::string name = specs[j].first;
                spec = specs[j].second;
                printf("found RTC '%s' with connection spec %s\n",
                       name.c_str(), spec.c_str());
                ++found;
            }
            if (found > 1) {
                throw std::runtime_error("found more than one RTC, use a more specific id");
            }
            if (found < 1) {
                specs = sbmirror.lookup(rtcPattern);

                std::string msg = vespalib::make_string("found no RTC named '%s' (list follows):\n", id.c_str());
                for (size_t j = 0; j < specs.size(); ++j) {
                    msg += vespalib::make_string("RTC name %s with connection spec %s\n", specs[j].first.c_str(), specs[j].second.c_str());
                }
                throw std::runtime_error(msg);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            throw std::runtime_error("ERROR: failed to get service location broker configuration");
        }
        return "";
    }

    int Main() override
    {
        if (_argc < 3) {
            return usage();
        }

        config::ConfigSystem configSystem;
        if (!configSystem.isUp()) {
            fprintf(stderr, "Config system is not up. Verify that vespa is started.");
            return 3;
        }
        try {
            initRPC();
        } catch (vespalib::Exception &e) {
            fprintf(stderr, "Exception in network initialization: %s", e.what());
            return 2;
        }
        int port = 0;
        std::string spec = _argv[1];

        try {
            if (spec == "--local") {
                spec = findRTC();
            } else if (spec.compare(0, 5, "--id=") == 0) {
                spec = findRTC(spec.substr(5));
            } else {
                port = atoi(_argv[1]);
            }
        } catch (const std::runtime_error & e) {
            fprintf(stderr, "%s", e.what());
            finiRPC();
            return 1;
        } catch (const config::ConfigTimeoutException & e) {
            fprintf(stderr, "Getting config timed out: %s", e.what());
            finiRPC();
            return 2;
        }

        if (port == 0 && spec.compare(0, 4, "tcp/") != 0) {
            finiRPC();
            return usage();
        }

        if (port != 0) {
            _target = _frt->supervisor().GetTarget(port);
        } else {
            _target = _frt->supervisor().GetTarget(spec.c_str());
        }

        bool invoked = false;

        if (strcmp(_argv[2], "getState") == 0 &&
                   _argc >= 3) {
            _req->SetMethodName("pandora.rtc.getState");

            FRT_Values &params = *_req->GetParams();

            params.AddInt32(_argc > 3 ? atoi(_argv[3]) : 0);
            params.AddInt32(_argc > 4 ? atoi(_argv[4]) : 0);
            invokeRPC(false);
            invoked = true;

            FRT_Values &rvals = *_req->GetReturn();

            if (!_req->IsError()) {
                FRT_Value &names = rvals.GetValue(0);
                FRT_Value &values = rvals.GetValue(1);
                FRT_Value &gencnt = rvals.GetValue(2);

                for (unsigned int i = 0;
                     i < names._string_array._len &&
                                      i < values._string_array._len;
                     i++)
                {
                    printf("\"%s\", \"%s\"\n",
                           names._string_array._pt[i]._str,
                           values._string_array._pt[i]._str);
                }
                printf("gencnt=%u\n",
                       static_cast<unsigned int>(gencnt._intval32));
            }
        } else if (strcmp(_argv[2], "getProtonStatus") == 0 &&
                   _argc >= 3) {

            _req->SetMethodName("proton.getStatus");
            FRT_Values &params = *_req->GetParams();
            params.AddString(_argc > 3 ? _argv[3] : "");
            invokeRPC(false);
            invoked = true;
            FRT_Values &rvals = *_req->GetReturn();
            if (!_req->IsError()) {
                FRT_Value &components = rvals.GetValue(0);
                FRT_Value &states = rvals.GetValue(1);
                FRT_Value &internalStates = rvals.GetValue(2);
                FRT_Value &messages = rvals.GetValue(3);
                for (unsigned int i = 0; i < components._string_array._len &&
                                         i < states._string_array._len &&
                                         i < internalStates.
                                               _string_array._len &&
                                         i < messages._string_array._len;
                                       i++) {
                    printf("\"%s\",\"%s\",\"%s\",\"%s\"\n",
                           components._string_array._pt[i]._str,
                           states._string_array._pt[i]._str,
                           internalStates._string_array._pt[i]._str,
                           messages._string_array._pt[i]._str);
                }

            }
        } else if (strcmp(_argv[2], "triggerFlush") == 0) {
            _req->SetMethodName("proton.triggerFlush");
            invokeRPC(false, 86400.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: flush trigger enabled\n");
            }
        } else if (strcmp(_argv[2], "prepareRestart") == 0) {
            _req->SetMethodName("proton.prepareRestart");
            invokeRPC(false, 86400.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: prepareRestart enabled\n");
            }
        } else if (strcmp(_argv[2], "die") == 0) {
            _req->SetMethodName("pandora.rtc.die");

        } else if (strcmp(_argv[2], "monitor") == 0) {
            invoked = true;
            monitorLoop();
        } else {
            finiRPC();
            return usage();
        }
        if (!invoked)
            invokeRPC(true);
        finiRPC();
        return 0;
    }
};

void
App::monitorLoop()
{
    for (;;) {
        FRT_RPCRequest *req = _frt->supervisor().AllocRPCRequest();
        req->SetMethodName("pandora.rtc.getIncrementalState");
        FRT_Values &params = *req->GetParams();
        params.AddInt32(2000);
        _target->InvokeSync(req, 1200.0);

        if (req->IsError()) {
            req->Print(0);
            req->SubRef();
            break;
        }
        FRT_Values &rvals = *req->GetReturn();
        FRT_Value &names = rvals.GetValue(0);
        FRT_Value &values = rvals.GetValue(1);
        struct timeval tnow;
        gettimeofday(&tnow, nullptr);

        for (unsigned int i = 0;
             i < names._string_array._len &&
                              i < values._string_array._len;
             i++)
        {
            time_t now;
            struct tm *nowtm;

            now = tnow.tv_sec;
            nowtm = gmtime(&now);
            fprintf(stdout,
                    "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ "
                    "%010d.%06d ==> ",
                    nowtm->tm_year + 1900,
                    nowtm->tm_mon + 1,
                    nowtm->tm_mday,
                    nowtm->tm_hour,
                    nowtm->tm_min,
                    nowtm->tm_sec,
                    (int)tnow.tv_usec,
                    (int)tnow.tv_sec,
                    (int) tnow.tv_usec);
            printf("\"%s\", \"%s\"\n",
                   names._string_array._pt[i]._str,
                   values._string_array._pt[i]._str);
        }
        fflush(stdout);
        req->SubRef();
    }
}

} // namespace pandora::rtc_cmd

int main(int argc, char **argv)
{
    pandora::rtc_cmd::App app;
    return app.Entry(argc, argv);
}
<commit_msg>allocate 10 minutes for proton.prepareRestart<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/slobrok/sbmirror.h>
#include <vespa/config/common/configsystem.h>
#include <vespa/config/common/exceptions.h>
#include <vespa/fnet/frt/frt.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/time.h>
#include <vespa/fastos/app.h>
#include <sys/time.h>
#include <thread>
#include <cstdlib>

#include <vespa/log/log.h>
LOG_SETUP("vespa-proton-cmd");

namespace pandora::rtc_cmd {

class App : public FastOS_Application
{
private:
    App(const App &);
    App& operator=(const App &);

    std::unique_ptr<fnet::frt::StandaloneFRT> _frt;
    FRT_Target     *_target;
    FRT_RPCRequest *_req;

public:
    App() : _frt(),
            _target(nullptr),
            _req(nullptr) {}
    virtual ~App()
    {
        assert(!_frt);
        assert(_target == nullptr);
        assert(_req == nullptr);
    }

    int usage()
    {
        fprintf(stderr, "usage: %s <port|spec|--local|--id=name> <cmd> [args]\n", _argv[0]);
        fprintf(stderr, "die\n");
        fprintf(stderr, "getProtonStatus\n");
        fprintf(stderr, "getState\n");
        fprintf(stderr, "monitor\n");
        fprintf(stderr, "triggerFlush\n");
        fprintf(stderr, "prepareRestart\n");
        return 1;
    }

    void initRPC()
    {
        _frt = std::make_unique<fnet::frt::StandaloneFRT>();
        _req = _frt->supervisor().AllocRPCRequest();
    }

    void invokeRPC(bool print, double timeout=5.0)
    {
        if (_req == nullptr)
            return;

        _target->InvokeSync(_req, timeout);
        if (print || _req->IsError())
            _req->Print(0);
    }

    void finiRPC()
    {
        if (_req != nullptr) {
            _req->SubRef();
            _req = nullptr;
        }
        if (_target != nullptr) {
            _target->SubRef();
            _target = nullptr;
        }
        if (_frt) {
            _frt.reset();
        }
    }

    void
    monitorLoop();

    void
    scanSpecs(slobrok::api::MirrorAPI::SpecList &specs,
              const std::string &me,
              std::string &service,
              std::string &spec,
              int &found)
    {
        for (size_t j = 0; j < specs.size(); ++j) {
            if (specs[j].first == service)
                continue;
            if (specs[j].second.compare(0, me.length(), me) == 0) {
                service = specs[j].first;
                spec = specs[j].second;
                printf("found local RTC '%s' with connection spec %s\n",
                       specs[j].first.c_str(), spec.c_str());
                ++found;
            }
        }
    }

    std::string findRTC() {
        std::string me = "tcp/";
        me += vespalib::HostName::get().c_str();
        me += ":";

        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";
        std::string rtcPattern2 = "*/search/cluster.*/*/realtimecontroller";
        std::string rtcPattern3 = "*/search/*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                fprintf(stderr,
                        "ERROR: no data from service location broker\n");
                std::_Exit(1);
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(rtcPattern);
            slobrok::api::MirrorAPI::SpecList specs2 = sbmirror.lookup(rtcPattern2);
            slobrok::api::MirrorAPI::SpecList specs3 = sbmirror.lookup(rtcPattern3);

            int found = 0;
            std::string service;
            std::string spec;

            printf("looking for RTCs matching '%s' (length %d)\n",
                   me.c_str(), (int)me.length());
            scanSpecs(specs, me, service, spec, found);
            scanSpecs(specs2, me, service, spec, found);
            scanSpecs(specs3, me, service, spec, found);
            if (found > 1) {
                fprintf(stderr, "found more than one local RTC, you must use --id=<name>\n");
                std::_Exit(1);
            }
            if (found < 1) {
                fprintf(stderr, "found no local RTC, you must use --id=<name> (list follows):\n");
                for (size_t j = 0; j < specs.size(); ++j) {
                    printf("RTC name %s with connection spec %s\n",
                           specs[j].first.c_str(), specs[j].second.c_str());
                }
                std::_Exit(1);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            fprintf(stderr, "ERROR: failed to get service location broker configuration\n");
            std::_Exit(1);
        }
        return "";
    }

    std::string findRTC(std::string id) {
        std::string rtcPattern = "search/cluster.*/c*/r*/realtimecontroller";

        try {
            slobrok::ConfiguratorFactory sbcfg("admin/slobrok.0");
            slobrok::api::MirrorAPI sbmirror(_frt->supervisor(), sbcfg);
            for (int timeout = 1; timeout < 20; timeout++) {
                if (!sbmirror.ready()) {
                    std::this_thread::sleep_for(50ms*timeout);
                }
            }
            if (!sbmirror.ready()) {
                throw std::runtime_error("ERROR: no data from service location broker");
            }
            slobrok::api::MirrorAPI::SpecList specs = sbmirror.lookup(id);

            int found = 0;
            std::string spec;

            for (size_t j = 0; j < specs.size(); ++j) {
                std::string name = specs[j].first;
                spec = specs[j].second;
                printf("found RTC '%s' with connection spec %s\n",
                       name.c_str(), spec.c_str());
                ++found;
            }
            if (found > 1) {
                throw std::runtime_error("found more than one RTC, use a more specific id");
            }
            if (found < 1) {
                specs = sbmirror.lookup(rtcPattern);

                std::string msg = vespalib::make_string("found no RTC named '%s' (list follows):\n", id.c_str());
                for (size_t j = 0; j < specs.size(); ++j) {
                    msg += vespalib::make_string("RTC name %s with connection spec %s\n", specs[j].first.c_str(), specs[j].second.c_str());
                }
                throw std::runtime_error(msg);
            }
            return spec;
        } catch (config::InvalidConfigException& e) {
            throw std::runtime_error("ERROR: failed to get service location broker configuration");
        }
        return "";
    }

    int Main() override
    {
        if (_argc < 3) {
            return usage();
        }

        config::ConfigSystem configSystem;
        if (!configSystem.isUp()) {
            fprintf(stderr, "Config system is not up. Verify that vespa is started.");
            return 3;
        }
        try {
            initRPC();
        } catch (vespalib::Exception &e) {
            fprintf(stderr, "Exception in network initialization: %s", e.what());
            return 2;
        }
        int port = 0;
        std::string spec = _argv[1];

        try {
            if (spec == "--local") {
                spec = findRTC();
            } else if (spec.compare(0, 5, "--id=") == 0) {
                spec = findRTC(spec.substr(5));
            } else {
                port = atoi(_argv[1]);
            }
        } catch (const std::runtime_error & e) {
            fprintf(stderr, "%s", e.what());
            finiRPC();
            return 1;
        } catch (const config::ConfigTimeoutException & e) {
            fprintf(stderr, "Getting config timed out: %s", e.what());
            finiRPC();
            return 2;
        }

        if (port == 0 && spec.compare(0, 4, "tcp/") != 0) {
            finiRPC();
            return usage();
        }

        if (port != 0) {
            _target = _frt->supervisor().GetTarget(port);
        } else {
            _target = _frt->supervisor().GetTarget(spec.c_str());
        }

        bool invoked = false;

        if (strcmp(_argv[2], "getState") == 0 &&
                   _argc >= 3) {
            _req->SetMethodName("pandora.rtc.getState");

            FRT_Values &params = *_req->GetParams();

            params.AddInt32(_argc > 3 ? atoi(_argv[3]) : 0);
            params.AddInt32(_argc > 4 ? atoi(_argv[4]) : 0);
            invokeRPC(false);
            invoked = true;

            FRT_Values &rvals = *_req->GetReturn();

            if (!_req->IsError()) {
                FRT_Value &names = rvals.GetValue(0);
                FRT_Value &values = rvals.GetValue(1);
                FRT_Value &gencnt = rvals.GetValue(2);

                for (unsigned int i = 0;
                     i < names._string_array._len &&
                                      i < values._string_array._len;
                     i++)
                {
                    printf("\"%s\", \"%s\"\n",
                           names._string_array._pt[i]._str,
                           values._string_array._pt[i]._str);
                }
                printf("gencnt=%u\n",
                       static_cast<unsigned int>(gencnt._intval32));
            }
        } else if (strcmp(_argv[2], "getProtonStatus") == 0 &&
                   _argc >= 3) {

            _req->SetMethodName("proton.getStatus");
            FRT_Values &params = *_req->GetParams();
            params.AddString(_argc > 3 ? _argv[3] : "");
            invokeRPC(false);
            invoked = true;
            FRT_Values &rvals = *_req->GetReturn();
            if (!_req->IsError()) {
                FRT_Value &components = rvals.GetValue(0);
                FRT_Value &states = rvals.GetValue(1);
                FRT_Value &internalStates = rvals.GetValue(2);
                FRT_Value &messages = rvals.GetValue(3);
                for (unsigned int i = 0; i < components._string_array._len &&
                                         i < states._string_array._len &&
                                         i < internalStates.
                                               _string_array._len &&
                                         i < messages._string_array._len;
                                       i++) {
                    printf("\"%s\",\"%s\",\"%s\",\"%s\"\n",
                           components._string_array._pt[i]._str,
                           states._string_array._pt[i]._str,
                           internalStates._string_array._pt[i]._str,
                           messages._string_array._pt[i]._str);
                }

            }
        } else if (strcmp(_argv[2], "triggerFlush") == 0) {
            _req->SetMethodName("proton.triggerFlush");
            invokeRPC(false, 86400.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: flush trigger enabled\n");
            }
        } else if (strcmp(_argv[2], "prepareRestart") == 0) {
            _req->SetMethodName("proton.prepareRestart");
            invokeRPC(false, 600.0);
            invoked = true;
            if (! _req->IsError()) {
                printf("OK: prepareRestart enabled\n");
            }
        } else if (strcmp(_argv[2], "die") == 0) {
            _req->SetMethodName("pandora.rtc.die");

        } else if (strcmp(_argv[2], "monitor") == 0) {
            invoked = true;
            monitorLoop();
        } else {
            finiRPC();
            return usage();
        }
        if (!invoked)
            invokeRPC(true);
        finiRPC();
        return 0;
    }
};

void
App::monitorLoop()
{
    for (;;) {
        FRT_RPCRequest *req = _frt->supervisor().AllocRPCRequest();
        req->SetMethodName("pandora.rtc.getIncrementalState");
        FRT_Values &params = *req->GetParams();
        params.AddInt32(2000);
        _target->InvokeSync(req, 1200.0);

        if (req->IsError()) {
            req->Print(0);
            req->SubRef();
            break;
        }
        FRT_Values &rvals = *req->GetReturn();
        FRT_Value &names = rvals.GetValue(0);
        FRT_Value &values = rvals.GetValue(1);
        struct timeval tnow;
        gettimeofday(&tnow, nullptr);

        for (unsigned int i = 0;
             i < names._string_array._len &&
                              i < values._string_array._len;
             i++)
        {
            time_t now;
            struct tm *nowtm;

            now = tnow.tv_sec;
            nowtm = gmtime(&now);
            fprintf(stdout,
                    "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ "
                    "%010d.%06d ==> ",
                    nowtm->tm_year + 1900,
                    nowtm->tm_mon + 1,
                    nowtm->tm_mday,
                    nowtm->tm_hour,
                    nowtm->tm_min,
                    nowtm->tm_sec,
                    (int)tnow.tv_usec,
                    (int)tnow.tv_sec,
                    (int) tnow.tv_usec);
            printf("\"%s\", \"%s\"\n",
                   names._string_array._pt[i]._str,
                   values._string_array._pt[i]._str);
        }
        fflush(stdout);
        req->SubRef();
    }
}

} // namespace pandora::rtc_cmd

int main(int argc, char **argv)
{
    pandora::rtc_cmd::App app;
    return app.Entry(argc, argv);
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2017, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file implements a simple CLI for the CoAP service.
 */

#include "cli_coap.hpp"

#if OPENTHREAD_CONFIG_COAP_API_ENABLE

#include <ctype.h>

#include "cli/cli.hpp"
#include "cli/cli_server.hpp"
#include "coap/coap_message.hpp"

namespace ot {
namespace Cli {

const struct Coap::Command Coap::sCommands[] = {
    {"help", &Coap::ProcessHelp},         {"delete", &Coap::ProcessRequest},
    {"get", &Coap::ProcessRequest},       {"parameters", &Coap::ProcessParameters},
    {"post", &Coap::ProcessRequest},      {"put", &Coap::ProcessRequest},
    {"resource", &Coap::ProcessResource}, {"start", &Coap::ProcessStart},
    {"stop", &Coap::ProcessStop},
};

Coap::Coap(Interpreter &aInterpreter)
    : mInterpreter(aInterpreter)
    , mUseDefaultRequestTxParameters(true)
    , mUseDefaultResponseTxParameters(true)
{
    memset(&mResource, 0, sizeof(mResource));
}

void Coap::PrintPayload(otMessage *aMessage) const
{
    uint8_t  buf[kMaxBufferSize];
    uint16_t bytesToPrint;
    uint16_t bytesPrinted = 0;
    uint16_t length       = otMessageGetLength(aMessage) - otMessageGetOffset(aMessage);

    if (length > 0)
    {
        mInterpreter.mServer->OutputFormat(" with payload: ");

        while (length > 0)
        {
            bytesToPrint = (length < sizeof(buf)) ? length : sizeof(buf);
            otMessageRead(aMessage, otMessageGetOffset(aMessage) + bytesPrinted, buf, bytesToPrint);

            mInterpreter.OutputBytes(buf, static_cast<uint8_t>(bytesToPrint));

            length -= bytesToPrint;
            bytesPrinted += bytesToPrint;
        }
    }

    mInterpreter.mServer->OutputFormat("\r\n");
}

otError Coap::ProcessHelp(int argc, char *argv[])
{
    OT_UNUSED_VARIABLE(argc);
    OT_UNUSED_VARIABLE(argv);

    for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++)
    {
        mInterpreter.mServer->OutputFormat("%s\r\n", sCommands[i].mName);
    }

    return OT_ERROR_NONE;
}

otError Coap::ProcessResource(int argc, char *argv[])
{
    otError error = OT_ERROR_NONE;

    if (argc > 1)
    {
        VerifyOrExit(strlen(argv[1]) < kMaxUriLength, error = OT_ERROR_INVALID_ARGS);

        mResource.mUriPath = mUriPath;
        mResource.mContext = this;
        mResource.mHandler = &Coap::HandleRequest;

        strncpy(mUriPath, argv[1], sizeof(mUriPath) - 1);
        SuccessOrExit(error = otCoapAddResource(mInterpreter.mInstance, &mResource));
    }
    else
    {
        mInterpreter.mServer->OutputFormat("%s\r\n", mResource.mUriPath);
    }

exit:
    return OT_ERROR_NONE;
}

otError Coap::ProcessStart(int argc, char *argv[])
{
    OT_UNUSED_VARIABLE(argc);
    OT_UNUSED_VARIABLE(argv);

    return otCoapStart(mInterpreter.mInstance, OT_DEFAULT_COAP_PORT);
}

otError Coap::ProcessStop(int argc, char *argv[])
{
    OT_UNUSED_VARIABLE(argc);
    OT_UNUSED_VARIABLE(argv);

    otCoapRemoveResource(mInterpreter.mInstance, &mResource);

    return otCoapStop(mInterpreter.mInstance);
}

otError Coap::ProcessParameters(int argc, char *argv[])
{
    otError error = OT_ERROR_NONE;

    VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);

    bool *              defaultTxParameters;
    otCoapTxParameters *txParameters;

    if (strcmp(argv[1], "request") == 0)
    {
        txParameters        = &mRequestTxParameters;
        defaultTxParameters = &mUseDefaultRequestTxParameters;
    }
    else if (strcmp(argv[1], "response") == 0)
    {
        txParameters        = &mResponseTxParameters;
        defaultTxParameters = &mUseDefaultResponseTxParameters;
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    if (argc > 2)
    {
        if (strcmp(argv[2], "default") == 0)
        {
            *defaultTxParameters = true;
        }
        else
        {
            unsigned long value;

            VerifyOrExit(argc >= 6, error = OT_ERROR_INVALID_ARGS);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[2], value));
            txParameters->mAckTimeout = static_cast<uint32_t>(value);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[3], value));
            VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
            txParameters->mAckRandomFactorNumerator = static_cast<uint8_t>(value);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[4], value));
            VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
            txParameters->mAckRandomFactorDenominator = static_cast<uint8_t>(value);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[5], value));
            VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
            txParameters->mMaxRetransmit = static_cast<uint8_t>(value);

            VerifyOrExit(txParameters->mAckRandomFactorNumerator > txParameters->mAckRandomFactorDenominator,
                         error = OT_ERROR_INVALID_ARGS);

            *defaultTxParameters = false;
        }
    }

    mInterpreter.mServer->OutputFormat("Transmission parameters for %s:\r\n", argv[1]);
    if (*defaultTxParameters)
    {
        mInterpreter.mServer->OutputFormat("default\r\n");
    }
    else
    {
        mInterpreter.mServer->OutputFormat("ACK_TIMEOUT=%u ms, ACK_RANDOM_FACTOR=%u/%u, MAX_RETRANSMIT=%u\r\n",
                                           txParameters->mAckTimeout, txParameters->mAckRandomFactorNumerator,
                                           txParameters->mAckRandomFactorDenominator, txParameters->mMaxRetransmit);
    }

exit:
    return error;
}

otError Coap::ProcessRequest(int argc, char *argv[])
{
    otError       error   = OT_ERROR_NONE;
    otMessage *   message = NULL;
    otMessageInfo messageInfo;
    uint16_t      payloadLength = 0;

    // Default parameters
    char         coapUri[kMaxUriLength] = "test";
    otCoapType   coapType               = OT_COAP_TYPE_NON_CONFIRMABLE;
    otCoapCode   coapCode               = OT_COAP_CODE_GET;
    otIp6Address coapDestinationIp;

    VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);

    // CoAP-Code
    if (strcmp(argv[0], "get") == 0)
    {
        coapCode = OT_COAP_CODE_GET;
    }
    else if (strcmp(argv[0], "post") == 0)
    {
        coapCode = OT_COAP_CODE_POST;
    }
    else if (strcmp(argv[0], "put") == 0)
    {
        coapCode = OT_COAP_CODE_PUT;
    }
    else if (strcmp(argv[0], "delete") == 0)
    {
        coapCode = OT_COAP_CODE_DELETE;
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    // Destination IPv6 address
    if (argc > 1)
    {
        SuccessOrExit(error = otIp6AddressFromString(argv[1], &coapDestinationIp));
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    // CoAP-URI
    if (argc > 2)
    {
        VerifyOrExit(strlen(argv[2]) < kMaxUriLength, error = OT_ERROR_INVALID_ARGS);
        strncpy(coapUri, argv[2], sizeof(coapUri) - 1);
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    // CoAP-Type
    if (argc > 3)
    {
        if (strcmp(argv[3], "con") == 0)
        {
            coapType = OT_COAP_TYPE_CONFIRMABLE;
        }
    }

    message = otCoapNewMessage(mInterpreter.mInstance, NULL);
    VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);

    otCoapMessageInit(message, coapType, coapCode);
    otCoapMessageGenerateToken(message, ot::Coap::Message::kDefaultTokenLength);
    SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, coapUri));

    if (argc > 4)
    {
        payloadLength = static_cast<uint16_t>(strlen(argv[4]));

        if (payloadLength > 0)
        {
            SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
        }
    }

    // Embed content into message if given
    if (payloadLength > 0)
    {
        SuccessOrExit(error = otMessageAppend(message, argv[4], payloadLength));
    }

    memset(&messageInfo, 0, sizeof(messageInfo));
    messageInfo.mPeerAddr = coapDestinationIp;
    messageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;

    if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET))
    {
        error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo, &Coap::HandleResponse,
                                                this, GetRequestTxParameters());
    }
    else
    {
        error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo, NULL, NULL,
                                                GetResponseTxParameters());
    }

exit:

    if ((error != OT_ERROR_NONE) && (message != NULL))
    {
        otMessageFree(message);
    }

    return error;
}

otError Coap::Process(int argc, char *argv[])
{
    otError error = OT_ERROR_PARSE;

    if (argc < 1)
    {
        ProcessHelp(0, NULL);
        error = OT_ERROR_INVALID_ARGS;
    }
    else
    {
        for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++)
        {
            if (strcmp(argv[0], sCommands[i].mName) == 0)
            {
                error = (this->*sCommands[i].mCommand)(argc, argv);
                break;
            }
        }
    }

    return error;
}

void Coap::HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
    static_cast<Coap *>(aContext)->HandleRequest(aMessage, aMessageInfo);
}

void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
    otError    error           = OT_ERROR_NONE;
    otMessage *responseMessage = NULL;
    otCoapCode responseCode    = OT_COAP_CODE_EMPTY;
    char       responseContent = '0';

    mInterpreter.mServer->OutputFormat("coap request from ");
    mInterpreter.OutputIp6Address(aMessageInfo->mPeerAddr);
    mInterpreter.mServer->OutputFormat(" ");

    switch (otCoapMessageGetCode(aMessage))
    {
    case OT_COAP_CODE_GET:
        mInterpreter.mServer->OutputFormat("GET");
        break;

    case OT_COAP_CODE_DELETE:
        mInterpreter.mServer->OutputFormat("DELETE");
        break;

    case OT_COAP_CODE_PUT:
        mInterpreter.mServer->OutputFormat("PUT");
        break;

    case OT_COAP_CODE_POST:
        mInterpreter.mServer->OutputFormat("POST");
        break;

    default:
        mInterpreter.mServer->OutputFormat("Undefined\r\n");
        ExitNow(error = OT_ERROR_PARSE);
    }

    PrintPayload(aMessage);

    if (otCoapMessageGetType(aMessage) == OT_COAP_TYPE_CONFIRMABLE ||
        otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
    {
        if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
        {
            responseCode = OT_COAP_CODE_CONTENT;
        }
        else
        {
            responseCode = OT_COAP_CODE_VALID;
        }

        responseMessage = otCoapNewMessage(mInterpreter.mInstance, NULL);
        VerifyOrExit(responseMessage != NULL, error = OT_ERROR_NO_BUFS);

        SuccessOrExit(
            error = otCoapMessageInitResponse(responseMessage, aMessage, OT_COAP_TYPE_ACKNOWLEDGMENT, responseCode));

        if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
        {
            SuccessOrExit(error = otCoapMessageSetPayloadMarker(responseMessage));
            SuccessOrExit(error = otMessageAppend(responseMessage, &responseContent, sizeof(responseContent)));
        }

        SuccessOrExit(error = otCoapSendResponseWithParameters(mInterpreter.mInstance, responseMessage, aMessageInfo,
                                                               GetResponseTxParameters()));
    }

exit:

    if (error != OT_ERROR_NONE)
    {
        if (responseMessage != NULL)
        {
            mInterpreter.mServer->OutputFormat("coap send response error %d: %s\r\n", error,
                                               otThreadErrorToString(error));
            otMessageFree(responseMessage);
        }
    }
    else if (responseCode >= OT_COAP_CODE_RESPONSE_MIN)
    {
        mInterpreter.mServer->OutputFormat("coap response sent\r\n");
    }
}

void Coap::HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError)
{
    static_cast<Coap *>(aContext)->HandleResponse(aMessage, aMessageInfo, aError);
}

void Coap::HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError)
{
    if (aError != OT_ERROR_NONE)
    {
        mInterpreter.mServer->OutputFormat("coap receive response error %d: %s\r\n", aError,
                                           otThreadErrorToString(aError));
    }
    else
    {
        mInterpreter.mServer->OutputFormat("coap response from ");
        mInterpreter.OutputIp6Address(aMessageInfo->mPeerAddr);

        PrintPayload(aMessage);
    }
}

} // namespace Cli
} // namespace ot

#endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
<commit_msg>[cli] adjust arg length checking to 'coap parameters' (#4595)<commit_after>/*
 *  Copyright (c) 2017, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file implements a simple CLI for the CoAP service.
 */

#include "cli_coap.hpp"

#if OPENTHREAD_CONFIG_COAP_API_ENABLE

#include <ctype.h>

#include "cli/cli.hpp"
#include "cli/cli_server.hpp"
#include "coap/coap_message.hpp"

namespace ot {
namespace Cli {

const struct Coap::Command Coap::sCommands[] = {
    {"help", &Coap::ProcessHelp},         {"delete", &Coap::ProcessRequest},
    {"get", &Coap::ProcessRequest},       {"parameters", &Coap::ProcessParameters},
    {"post", &Coap::ProcessRequest},      {"put", &Coap::ProcessRequest},
    {"resource", &Coap::ProcessResource}, {"start", &Coap::ProcessStart},
    {"stop", &Coap::ProcessStop},
};

Coap::Coap(Interpreter &aInterpreter)
    : mInterpreter(aInterpreter)
    , mUseDefaultRequestTxParameters(true)
    , mUseDefaultResponseTxParameters(true)
{
    memset(&mResource, 0, sizeof(mResource));
}

void Coap::PrintPayload(otMessage *aMessage) const
{
    uint8_t  buf[kMaxBufferSize];
    uint16_t bytesToPrint;
    uint16_t bytesPrinted = 0;
    uint16_t length       = otMessageGetLength(aMessage) - otMessageGetOffset(aMessage);

    if (length > 0)
    {
        mInterpreter.mServer->OutputFormat(" with payload: ");

        while (length > 0)
        {
            bytesToPrint = (length < sizeof(buf)) ? length : sizeof(buf);
            otMessageRead(aMessage, otMessageGetOffset(aMessage) + bytesPrinted, buf, bytesToPrint);

            mInterpreter.OutputBytes(buf, static_cast<uint8_t>(bytesToPrint));

            length -= bytesToPrint;
            bytesPrinted += bytesToPrint;
        }
    }

    mInterpreter.mServer->OutputFormat("\r\n");
}

otError Coap::ProcessHelp(int argc, char *argv[])
{
    OT_UNUSED_VARIABLE(argc);
    OT_UNUSED_VARIABLE(argv);

    for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++)
    {
        mInterpreter.mServer->OutputFormat("%s\r\n", sCommands[i].mName);
    }

    return OT_ERROR_NONE;
}

otError Coap::ProcessResource(int argc, char *argv[])
{
    otError error = OT_ERROR_NONE;

    if (argc > 1)
    {
        VerifyOrExit(strlen(argv[1]) < kMaxUriLength, error = OT_ERROR_INVALID_ARGS);

        mResource.mUriPath = mUriPath;
        mResource.mContext = this;
        mResource.mHandler = &Coap::HandleRequest;

        strncpy(mUriPath, argv[1], sizeof(mUriPath) - 1);
        SuccessOrExit(error = otCoapAddResource(mInterpreter.mInstance, &mResource));
    }
    else
    {
        mInterpreter.mServer->OutputFormat("%s\r\n", mResource.mUriPath);
    }

exit:
    return OT_ERROR_NONE;
}

otError Coap::ProcessStart(int argc, char *argv[])
{
    OT_UNUSED_VARIABLE(argc);
    OT_UNUSED_VARIABLE(argv);

    return otCoapStart(mInterpreter.mInstance, OT_DEFAULT_COAP_PORT);
}

otError Coap::ProcessStop(int argc, char *argv[])
{
    OT_UNUSED_VARIABLE(argc);
    OT_UNUSED_VARIABLE(argv);

    otCoapRemoveResource(mInterpreter.mInstance, &mResource);

    return otCoapStop(mInterpreter.mInstance);
}

otError Coap::ProcessParameters(int argc, char *argv[])
{
    otError             error = OT_ERROR_NONE;
    bool *              defaultTxParameters;
    otCoapTxParameters *txParameters;

    VerifyOrExit(argc > 1, error = OT_ERROR_INVALID_ARGS);

    if (strcmp(argv[1], "request") == 0)
    {
        txParameters        = &mRequestTxParameters;
        defaultTxParameters = &mUseDefaultRequestTxParameters;
    }
    else if (strcmp(argv[1], "response") == 0)
    {
        txParameters        = &mResponseTxParameters;
        defaultTxParameters = &mUseDefaultResponseTxParameters;
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    if (argc > 2)
    {
        if (strcmp(argv[2], "default") == 0)
        {
            *defaultTxParameters = true;
        }
        else
        {
            unsigned long value;

            VerifyOrExit(argc >= 6, error = OT_ERROR_INVALID_ARGS);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[2], value));
            txParameters->mAckTimeout = static_cast<uint32_t>(value);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[3], value));
            VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
            txParameters->mAckRandomFactorNumerator = static_cast<uint8_t>(value);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[4], value));
            VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
            txParameters->mAckRandomFactorDenominator = static_cast<uint8_t>(value);

            SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[5], value));
            VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
            txParameters->mMaxRetransmit = static_cast<uint8_t>(value);

            VerifyOrExit(txParameters->mAckRandomFactorNumerator > txParameters->mAckRandomFactorDenominator,
                         error = OT_ERROR_INVALID_ARGS);

            *defaultTxParameters = false;
        }
    }

    mInterpreter.mServer->OutputFormat("Transmission parameters for %s:\r\n", argv[1]);
    if (*defaultTxParameters)
    {
        mInterpreter.mServer->OutputFormat("default\r\n");
    }
    else
    {
        mInterpreter.mServer->OutputFormat("ACK_TIMEOUT=%u ms, ACK_RANDOM_FACTOR=%u/%u, MAX_RETRANSMIT=%u\r\n",
                                           txParameters->mAckTimeout, txParameters->mAckRandomFactorNumerator,
                                           txParameters->mAckRandomFactorDenominator, txParameters->mMaxRetransmit);
    }

exit:
    return error;
}

otError Coap::ProcessRequest(int argc, char *argv[])
{
    otError       error   = OT_ERROR_NONE;
    otMessage *   message = NULL;
    otMessageInfo messageInfo;
    uint16_t      payloadLength = 0;

    // Default parameters
    char         coapUri[kMaxUriLength] = "test";
    otCoapType   coapType               = OT_COAP_TYPE_NON_CONFIRMABLE;
    otCoapCode   coapCode               = OT_COAP_CODE_GET;
    otIp6Address coapDestinationIp;

    VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);

    // CoAP-Code
    if (strcmp(argv[0], "get") == 0)
    {
        coapCode = OT_COAP_CODE_GET;
    }
    else if (strcmp(argv[0], "post") == 0)
    {
        coapCode = OT_COAP_CODE_POST;
    }
    else if (strcmp(argv[0], "put") == 0)
    {
        coapCode = OT_COAP_CODE_PUT;
    }
    else if (strcmp(argv[0], "delete") == 0)
    {
        coapCode = OT_COAP_CODE_DELETE;
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    // Destination IPv6 address
    if (argc > 1)
    {
        SuccessOrExit(error = otIp6AddressFromString(argv[1], &coapDestinationIp));
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    // CoAP-URI
    if (argc > 2)
    {
        VerifyOrExit(strlen(argv[2]) < kMaxUriLength, error = OT_ERROR_INVALID_ARGS);
        strncpy(coapUri, argv[2], sizeof(coapUri) - 1);
    }
    else
    {
        ExitNow(error = OT_ERROR_INVALID_ARGS);
    }

    // CoAP-Type
    if (argc > 3)
    {
        if (strcmp(argv[3], "con") == 0)
        {
            coapType = OT_COAP_TYPE_CONFIRMABLE;
        }
    }

    message = otCoapNewMessage(mInterpreter.mInstance, NULL);
    VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);

    otCoapMessageInit(message, coapType, coapCode);
    otCoapMessageGenerateToken(message, ot::Coap::Message::kDefaultTokenLength);
    SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, coapUri));

    if (argc > 4)
    {
        payloadLength = static_cast<uint16_t>(strlen(argv[4]));

        if (payloadLength > 0)
        {
            SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
        }
    }

    // Embed content into message if given
    if (payloadLength > 0)
    {
        SuccessOrExit(error = otMessageAppend(message, argv[4], payloadLength));
    }

    memset(&messageInfo, 0, sizeof(messageInfo));
    messageInfo.mPeerAddr = coapDestinationIp;
    messageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;

    if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET))
    {
        error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo, &Coap::HandleResponse,
                                                this, GetRequestTxParameters());
    }
    else
    {
        error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo, NULL, NULL,
                                                GetResponseTxParameters());
    }

exit:

    if ((error != OT_ERROR_NONE) && (message != NULL))
    {
        otMessageFree(message);
    }

    return error;
}

otError Coap::Process(int argc, char *argv[])
{
    otError error = OT_ERROR_PARSE;

    if (argc < 1)
    {
        ProcessHelp(0, NULL);
        error = OT_ERROR_INVALID_ARGS;
    }
    else
    {
        for (size_t i = 0; i < OT_ARRAY_LENGTH(sCommands); i++)
        {
            if (strcmp(argv[0], sCommands[i].mName) == 0)
            {
                error = (this->*sCommands[i].mCommand)(argc, argv);
                break;
            }
        }
    }

    return error;
}

void Coap::HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
    static_cast<Coap *>(aContext)->HandleRequest(aMessage, aMessageInfo);
}

void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
    otError    error           = OT_ERROR_NONE;
    otMessage *responseMessage = NULL;
    otCoapCode responseCode    = OT_COAP_CODE_EMPTY;
    char       responseContent = '0';

    mInterpreter.mServer->OutputFormat("coap request from ");
    mInterpreter.OutputIp6Address(aMessageInfo->mPeerAddr);
    mInterpreter.mServer->OutputFormat(" ");

    switch (otCoapMessageGetCode(aMessage))
    {
    case OT_COAP_CODE_GET:
        mInterpreter.mServer->OutputFormat("GET");
        break;

    case OT_COAP_CODE_DELETE:
        mInterpreter.mServer->OutputFormat("DELETE");
        break;

    case OT_COAP_CODE_PUT:
        mInterpreter.mServer->OutputFormat("PUT");
        break;

    case OT_COAP_CODE_POST:
        mInterpreter.mServer->OutputFormat("POST");
        break;

    default:
        mInterpreter.mServer->OutputFormat("Undefined\r\n");
        ExitNow(error = OT_ERROR_PARSE);
    }

    PrintPayload(aMessage);

    if (otCoapMessageGetType(aMessage) == OT_COAP_TYPE_CONFIRMABLE ||
        otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
    {
        if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
        {
            responseCode = OT_COAP_CODE_CONTENT;
        }
        else
        {
            responseCode = OT_COAP_CODE_VALID;
        }

        responseMessage = otCoapNewMessage(mInterpreter.mInstance, NULL);
        VerifyOrExit(responseMessage != NULL, error = OT_ERROR_NO_BUFS);

        SuccessOrExit(
            error = otCoapMessageInitResponse(responseMessage, aMessage, OT_COAP_TYPE_ACKNOWLEDGMENT, responseCode));

        if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
        {
            SuccessOrExit(error = otCoapMessageSetPayloadMarker(responseMessage));
            SuccessOrExit(error = otMessageAppend(responseMessage, &responseContent, sizeof(responseContent)));
        }

        SuccessOrExit(error = otCoapSendResponseWithParameters(mInterpreter.mInstance, responseMessage, aMessageInfo,
                                                               GetResponseTxParameters()));
    }

exit:

    if (error != OT_ERROR_NONE)
    {
        if (responseMessage != NULL)
        {
            mInterpreter.mServer->OutputFormat("coap send response error %d: %s\r\n", error,
                                               otThreadErrorToString(error));
            otMessageFree(responseMessage);
        }
    }
    else if (responseCode >= OT_COAP_CODE_RESPONSE_MIN)
    {
        mInterpreter.mServer->OutputFormat("coap response sent\r\n");
    }
}

void Coap::HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError)
{
    static_cast<Coap *>(aContext)->HandleResponse(aMessage, aMessageInfo, aError);
}

void Coap::HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError)
{
    if (aError != OT_ERROR_NONE)
    {
        mInterpreter.mServer->OutputFormat("coap receive response error %d: %s\r\n", aError,
                                           otThreadErrorToString(aError));
    }
    else
    {
        mInterpreter.mServer->OutputFormat("coap response from ");
        mInterpreter.OutputIp6Address(aMessageInfo->mPeerAddr);

        PrintPayload(aMessage);
    }
}

} // namespace Cli
} // namespace ot

#endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
<|endoftext|>


<commit_before>#include "Texture3D.h"
#include "Director.h"

using namespace Rendering::Texture;
using namespace Rendering::View;

Texture3D::Texture3D()
	: TextureForm(Type::Tex3D), _texture(nullptr), _size(0, 0, 0), _rtv(nullptr)
{
}

Texture3D::~Texture3D()
{
	Destory();
}

void Texture3D::Initialize(	uint width, uint height, uint depth,
							DXGI_FORMAT typelessFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT uavFormat,
							uint optionBindFlag, uint mipLevels )
{
	_size.x = (float)width;
	_size.y = (float)height;
	_size.z = (float)depth;

	uint bindFlag = ((srvFormat != DXGI_FORMAT_UNKNOWN) ? D3D11_BIND_SHADER_RESOURCE	: 0) |
					((mipLevels > 1) ? D3D11_BIND_RENDER_TARGET	: 0) |	// D3D11_RESOURCE_MISC_GENERATE_MIPS Ϸ
																		// D3D11_BIND_RENDER_TARGET  ¿ Ѵ.
					((uavFormat != DXGI_FORMAT_UNKNOWN) ? D3D11_BIND_UNORDERED_ACCESS	: 0) | optionBindFlag;

	const Device::DirectX* dx = Device::Director::SharedInstance()->GetDirectX();
	ID3D11Device* device = dx->GetDevice();

	D3D11_TEXTURE3D_DESC textureDesc;
	memset(&textureDesc, 0, sizeof(D3D11_TEXTURE3D_DESC));

	// Setup the render target texture description.
	textureDesc.Width			= width;
	textureDesc.Height			= height;
	textureDesc.Depth			= depth;

	textureDesc.MipLevels		= mipLevels;
	textureDesc.MiscFlags		= mipLevels > 1 ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;

	textureDesc.Format			= typelessFormat;
	textureDesc.Usage			= D3D11_USAGE_DEFAULT;
	textureDesc.BindFlags		= bindFlag;
	textureDesc.CPUAccessFlags	= 0;

	//Initialize texture
	{
		HRESULT hr = device->CreateTexture3D(&textureDesc, NULL, &_texture);
		ASSERT_COND_MSG(SUCCEEDED(hr), "Error, not create texture");
	}

	if(bindFlag & D3D11_BIND_SHADER_RESOURCE)
	{
		_srv = new ShaderResourceView;
		_srv->Initialize(_texture, srvFormat, mipLevels, D3D11_SRV_DIMENSION_TEXTURE3D);
	}

	if(bindFlag & D3D11_BIND_RENDER_TARGET)
	{
		D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
		rtvDesc.Format					= srvFormat;
		rtvDesc.ViewDimension			= D3D11_RTV_DIMENSION_TEXTURE3D;
		rtvDesc.Texture3D.MipSlice		= 0;
		rtvDesc.Texture3D.FirstWSlice	= 0;
		rtvDesc.Texture3D.WSize			= depth;
		HRESULT hr = device->CreateRenderTargetView(_texture, &rtvDesc, &_rtv);
		ASSERT_COND_MSG(SUCCEEDED(hr), "Error, can't create render target view");
	}

	if(bindFlag & D3D11_BIND_UNORDERED_ACCESS)
	{
		_uav = new UnorderedAccessView;
		_uav->Initialize(uavFormat, width * height * depth, _texture, D3D11_UAV_DIMENSION_TEXTURE3D, 0, -1);
	}
}

void Texture3D::Destory()
{
	TextureForm::Destroy();

	SAFE_RELEASE(_texture);
	SAFE_RELEASE(_rtv);
}<commit_msg>Texture3D - rtvDesc.Texture3D.WSize = -1로 수정<commit_after>#include "Texture3D.h"
#include "Director.h"

using namespace Rendering::Texture;
using namespace Rendering::View;

Texture3D::Texture3D()
	: TextureForm(Type::Tex3D), _texture(nullptr), _size(0, 0, 0), _rtv(nullptr)
{
}

Texture3D::~Texture3D()
{
	Destory();
}

void Texture3D::Initialize(	uint width, uint height, uint depth,
							DXGI_FORMAT typelessFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT uavFormat,
							uint optionBindFlag, uint mipLevels )
{
	_size.x = (float)width;
	_size.y = (float)height;
	_size.z = (float)depth;

	uint bindFlag = ((srvFormat != DXGI_FORMAT_UNKNOWN) ? D3D11_BIND_SHADER_RESOURCE	: 0) |
					((mipLevels > 1) ? D3D11_BIND_RENDER_TARGET	: 0) |	// D3D11_RESOURCE_MISC_GENERATE_MIPS Ϸ
																		// D3D11_BIND_RENDER_TARGET  ¿ Ѵ.
					((uavFormat != DXGI_FORMAT_UNKNOWN) ? D3D11_BIND_UNORDERED_ACCESS	: 0) | optionBindFlag;

	const Device::DirectX* dx = Device::Director::SharedInstance()->GetDirectX();
	ID3D11Device* device = dx->GetDevice();

	D3D11_TEXTURE3D_DESC textureDesc;
	memset(&textureDesc, 0, sizeof(D3D11_TEXTURE3D_DESC));

	// Setup the render target texture description.
	textureDesc.Width			= width;
	textureDesc.Height			= height;
	textureDesc.Depth			= depth;

	textureDesc.MipLevels		= mipLevels;
	textureDesc.MiscFlags		= mipLevels > 1 ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;

	textureDesc.Format			= typelessFormat;
	textureDesc.Usage			= D3D11_USAGE_DEFAULT;
	textureDesc.BindFlags		= bindFlag;
	textureDesc.CPUAccessFlags	= 0;

	//Initialize texture
	{
		HRESULT hr = device->CreateTexture3D(&textureDesc, NULL, &_texture);
		ASSERT_COND_MSG(SUCCEEDED(hr), "Error, not create texture");
	}

	if(bindFlag & D3D11_BIND_SHADER_RESOURCE)
	{
		_srv = new ShaderResourceView;
		_srv->Initialize(_texture, srvFormat, mipLevels, D3D11_SRV_DIMENSION_TEXTURE3D);
	}

	if(bindFlag & D3D11_BIND_RENDER_TARGET)
	{
		D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
		rtvDesc.Format					= srvFormat;
		rtvDesc.ViewDimension			= D3D11_RTV_DIMENSION_TEXTURE3D;
		rtvDesc.Texture3D.MipSlice		= 0;
		rtvDesc.Texture3D.FirstWSlice	= 0;
		rtvDesc.Texture3D.WSize			= -1;
		HRESULT hr = device->CreateRenderTargetView(_texture, &rtvDesc, &_rtv);
		ASSERT_COND_MSG(SUCCEEDED(hr), "Error, can't create render target view");
	}

	if(bindFlag & D3D11_BIND_UNORDERED_ACCESS)
	{
		_uav = new UnorderedAccessView;
		_uav->Initialize(uavFormat, width * height * depth, _texture, D3D11_UAV_DIMENSION_TEXTURE3D, 0, -1);
	}
}

void Texture3D::Destory()
{
	TextureForm::Destroy();

	SAFE_RELEASE(_texture);
	SAFE_RELEASE(_rtv);
}<|endoftext|>