<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.                  *
**************************************************************************/

//------------------------------------------------------------------------------
// Implementation of the AliPerformanceTask class. It checks reconstruction performance
// for the reconstructed vs MC particle tracks under several conditions. For real data
// the control QA histograms are filled.
//
// The comparison output objects deriving from AliPerformanceObject
// (e.g. AliPerformanceRes, AliPerformanceEff, AliPerformanceDEdx, AliPerformanceDCA ...)
// are stored in the output file (details in description of these classes).
//
// Author: J.Otwinowski 01/04/2009
// Changes by M.Knichel 15/10/2010
//------------------------------------------------------------------------------

#include "iostream"

#include "TChain.h"
#include "TTree.h"
#include "TH1F.h"
#include "TCanvas.h"
#include "TList.h"
#include "TFile.h"
#include "TSystem.h"

#include "AliAnalysisTask.h"
#include "AliAnalysisManager.h"
#include "AliESDEvent.h"
#include "AliESDfriend.h"
#include "AliMCEvent.h"
#include "AliESDInputHandler.h"
#include "AliMCEventHandler.h"
#include "AliESDVertex.h"
#include "AliMagF.h"
#include "AliTracker.h"
#include "AliGeomManager.h"

#include "AliMCInfo.h"
#include "AliESDRecInfo.h"
#include "AliMCInfoCuts.h"
#include "AliRecInfoCuts.h"
#include "AliComparisonObject.h"
#include "AliPerformanceObject.h"
#include "AliTPCPerformanceSummary.h"
#include "AliPerformanceTPC.h"
#include "AliPerformanceDEdx.h"
#include "AliPerformanceTask.h"

using namespace std;

ClassImp(AliPerformanceTask)

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask()
  : AliAnalysisTaskSE("Performance")
  , fESD(0)
  , fESDfriend(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(0)
  , fUseMCInfo(kFALSE)
  , fUseESDfriend(kFALSE)
  , fUseHLT(kFALSE)
{
  // Dummy Constructor
  // should not be used
}

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask(const char *name, const char */*title*/)
  : AliAnalysisTaskSE(name)
  , fESD(0)
  , fESDfriend(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(0)
  , fUseMCInfo(kFALSE)
  , fUseESDfriend(kFALSE)
  , fUseHLT(kFALSE)
{
  // Constructor

  // Define input and output slots here
  DefineOutput(1, TList::Class());
  DefineOutput(2, TTree::Class());

  // create the list for comparison objects
  fCompList = new TList;
}

//_____________________________________________________________________________
AliPerformanceTask::~AliPerformanceTask()
{
  if (fOutput)     delete fOutput;    fOutput   = 0;
  if (fOutputSummary) delete fOutputSummary; fOutputSummary = 0;
  if (fCompList)   delete fCompList;  fCompList = 0;
}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::AddPerformanceObject(AliPerformanceObject *pObj)
{
  // add comparison object to the list
  if(pObj == 0) {
    Printf("ERROR: Could not add comparison object");
    return kFALSE;
  }

  // add object to the list
  fCompList->AddLast(pObj);

return kTRUE;
}

//_____________________________________________________________________________
void AliPerformanceTask::UserCreateOutputObjects()
{
  // Create histograms
  // Called once

  // create output list
  fOutput = new TList;
  fOutput->SetOwner();
  fPitList = fOutput->MakeIterator();

  // create output list
  //fOutputSummary = new TTree;

  // add comparison objects to the output
  AliPerformanceObject *pObj=0;
  Int_t count=0;
  TIterator *pitCompList = fCompList->MakeIterator();
  pitCompList->Reset();
  while(( pObj = (AliPerformanceObject *)pitCompList->Next()) != NULL) {
    fOutput->Add(pObj);
    count++;
  }
  Printf("UserCreateOutputObjects(): Number of output comparison objects: %d \n", count);

  PostData(1, fOutput);
  //PostData(2, fOutputSummary);
}

//_____________________________________________________________________________
void AliPerformanceTask::UserExec(Option_t *)
{
  // Main loop
  // Called for each event

  // Decide whether to use HLT or Offline ESD
  if(fUseHLT){

    AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*>
      (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());

    if (!esdH) {
      printf("ERROR: Could not get ESDInputHandler");
      return;
    }
    fESD = esdH->GetHLTEvent();
  }// end if fUseHLT
  else
    fESD = (AliESDEvent*) (InputEvent());

  if(fUseESDfriend)
    {
      fESDfriend = static_cast<AliESDfriend*>(fESD->FindListObject("AliESDfriend"));
      if(!fESDfriend) {
        Printf("ERROR: ESD friends not available");
      }
    }

  if(fUseMCInfo) {
      fMC = MCEvent();
  }

  //
  AliPerformanceObject *pObj=0;

  if (!fESD) {
    Printf("ERROR: ESD event not available");
    return;
  }

  if (fUseMCInfo && !fMC) {
    Printf("ERROR: MC event not available");
    return;
  }

  if(fUseESDfriend)
  {
    if(!fESDfriend) {
    Printf("ERROR: ESD friends not available");
    }
  }

  // Process comparison
  fPitList->Reset();
  while(( pObj = (AliPerformanceObject *)fPitList->Next()) != NULL) {
    pObj->Exec(fMC,fESD,fESDfriend,fUseMCInfo,fUseESDfriend);
  }

  // Post output data.
  PostData(1, fOutput);
}

//_____________________________________________________________________________
void AliPerformanceTask::Terminate(Option_t *)
{
  // Called once at the end

  // check output data
    fOutputSummary = dynamic_cast<TTree*> (GetOutputData(2));
    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        Printf("ERROR: AliPerformanceTask::FinishTaskOutput(): fOutput data not available  ..." );
        return;
   }
    if (fOutputSummary) { delete fOutputSummary; fOutputSummary=0; }
    AliPerformanceObject* pObj=0;
    AliPerformanceTPC*  pTPC = 0;
    AliPerformanceDEdx* pDEdx = 0;
    TIterator* itOut = fOutput->MakeIterator();
    itOut->Reset();
    while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
        if (!  pTPC) {  pTPC = dynamic_cast<AliPerformanceTPC*>(pObj); }
        if (! pDEdx) { pDEdx = dynamic_cast<AliPerformanceDEdx*>(pObj); }
    }
    TUUID uuid;
    TString tmpFile = gSystem->TempDirectory() + TString("/TPCQASummary.") + uuid.AsString() + TString(".root");
    AliTPCPerformanceSummary::WriteToFile(pTPC, pDEdx, tmpFile.Data());
    TChain* chain = new TChain("tpcQA");
    chain->Add(tmpFile.Data());
    TTree *tree = chain->CopyTree("1");
    if (chain) { delete chain; chain=0; }
    fOutputSummary = tree;

     // Post output data.
     PostData(2, fOutputSummary);

}

//_____________________________________________________________________________
void AliPerformanceTask::FinishTaskOutput()
{
    // called once at the end of each job (on the workernode)
    //
    // projects THnSparse to TH1,2,3

    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        Printf("ERROR: AliPerformanceTask::FinishTaskOutput(): fOutput data not available  ..." );
        return;
   }

      AliPerformanceObject* pObj=0;
      TIterator* itOut = fOutput->MakeIterator();
      itOut->Reset();
      while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
          pObj->SetRunNumber(fCurrentRunNumber);
          pObj->Analyse();
      }

     // Post output data.
     PostData(1, fOutput);
}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::Notify()
{
  static Int_t count = 0;
  count++;
  Printf("Processing %d. file", count);

  return kTRUE;
}
<commit_msg>init OCDB in Terminate necessary for trending (M. Knichel)<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.                  *
**************************************************************************/

//------------------------------------------------------------------------------
// Implementation of the AliPerformanceTask class. It checks reconstruction performance
// for the reconstructed vs MC particle tracks under several conditions. For real data
// the control QA histograms are filled.
//
// The comparison output objects deriving from AliPerformanceObject
// (e.g. AliPerformanceRes, AliPerformanceEff, AliPerformanceDEdx, AliPerformanceDCA ...)
// are stored in the output file (details in description of these classes).
//
// Author: J.Otwinowski 01/04/2009
// Changes by M.Knichel 15/10/2010
//------------------------------------------------------------------------------

#include "iostream"

#include "TChain.h"
#include "TTree.h"
#include "TH1F.h"
#include "TCanvas.h"
#include "TList.h"
#include "TFile.h"
#include "TSystem.h"

#include "AliAnalysisTask.h"
#include "AliAnalysisManager.h"
#include "AliESDEvent.h"
#include "AliESDfriend.h"
#include "AliMCEvent.h"
#include "AliESDInputHandler.h"
#include "AliMCEventHandler.h"
#include "AliESDVertex.h"
#include "AliMagF.h"
#include "AliTracker.h"
#include "AliGeomManager.h"

#include "AliMCInfo.h"
#include "AliESDRecInfo.h"
#include "AliMCInfoCuts.h"
#include "AliRecInfoCuts.h"
#include "AliComparisonObject.h"
#include "AliPerformanceObject.h"
#include "AliTPCPerformanceSummary.h"
#include "AliPerformanceTPC.h"
#include "AliPerformanceDEdx.h"
#include "AliPerformanceTask.h"

using namespace std;

ClassImp(AliPerformanceTask)

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask()
  : AliAnalysisTaskSE("Performance")
  , fESD(0)
  , fESDfriend(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(0)
  , fUseMCInfo(kFALSE)
  , fUseESDfriend(kFALSE)
  , fUseHLT(kFALSE)
{
  // Dummy Constructor
  // should not be used
}

//_____________________________________________________________________________
AliPerformanceTask::AliPerformanceTask(const char *name, const char */*title*/)
  : AliAnalysisTaskSE(name)
  , fESD(0)
  , fESDfriend(0)
  , fMC(0)
  , fOutput(0)
  , fOutputSummary(0)
  , fPitList(0)
  , fCompList(0)
  , fUseMCInfo(kFALSE)
  , fUseESDfriend(kFALSE)
  , fUseHLT(kFALSE)
{
  // Constructor

  // Define input and output slots here
  DefineOutput(1, TList::Class());
  DefineOutput(2, TTree::Class());

  // create the list for comparison objects
  fCompList = new TList;
}

//_____________________________________________________________________________
AliPerformanceTask::~AliPerformanceTask()
{
  if (fOutput)     delete fOutput;    fOutput   = 0;
  if (fOutputSummary) delete fOutputSummary; fOutputSummary = 0;
  if (fCompList)   delete fCompList;  fCompList = 0;
}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::AddPerformanceObject(AliPerformanceObject *pObj)
{
  // add comparison object to the list
  if(pObj == 0) {
    Printf("ERROR: Could not add comparison object");
    return kFALSE;
  }

  // add object to the list
  fCompList->AddLast(pObj);

return kTRUE;
}

//_____________________________________________________________________________
void AliPerformanceTask::UserCreateOutputObjects()
{
  // Create histograms
  // Called once

  // create output list
  fOutput = new TList;
  fOutput->SetOwner();
  fPitList = fOutput->MakeIterator();

  // create output list
  //fOutputSummary = new TTree;

  // add comparison objects to the output
  AliPerformanceObject *pObj=0;
  Int_t count=0;
  TIterator *pitCompList = fCompList->MakeIterator();
  pitCompList->Reset();
  while(( pObj = (AliPerformanceObject *)pitCompList->Next()) != NULL) {
    fOutput->Add(pObj);
    count++;
  }
  Printf("UserCreateOutputObjects(): Number of output comparison objects: %d \n", count);

  PostData(1, fOutput);
  //PostData(2, fOutputSummary);
}

//_____________________________________________________________________________
void AliPerformanceTask::UserExec(Option_t *)
{
  // Main loop
  // Called for each event

  // Decide whether to use HLT or Offline ESD
  if(fUseHLT){

    AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*>
      (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());

    if (!esdH) {
      printf("ERROR: Could not get ESDInputHandler");
      return;
    }
    fESD = esdH->GetHLTEvent();
  }// end if fUseHLT
  else
    fESD = (AliESDEvent*) (InputEvent());

  if(fUseESDfriend)
    {
      fESDfriend = static_cast<AliESDfriend*>(fESD->FindListObject("AliESDfriend"));
      if(!fESDfriend) {
        Printf("ERROR: ESD friends not available");
      }
    }

  if(fUseMCInfo) {
      fMC = MCEvent();
  }

  //
  AliPerformanceObject *pObj=0;

  if (!fESD) {
    Printf("ERROR: ESD event not available");
    return;
  }

  if (fUseMCInfo && !fMC) {
    Printf("ERROR: MC event not available");
    return;
  }

  if(fUseESDfriend)
  {
    if(!fESDfriend) {
    Printf("ERROR: ESD friends not available");
    }
  }

  // Process comparison
  fPitList->Reset();
  while(( pObj = (AliPerformanceObject *)fPitList->Next()) != NULL) {
    pObj->Exec(fMC,fESD,fESDfriend,fUseMCInfo,fUseESDfriend);
  }

  // Post output data.
  PostData(1, fOutput);
}

//_____________________________________________________________________________
void AliPerformanceTask::Terminate(Option_t *)
{
  // Called once at the end

  // check output data
    fOutputSummary = dynamic_cast<TTree*> (GetOutputData(2));
    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        Printf("ERROR: AliPerformanceTask::Terminate(): fOutput data not available  ..." );
        return;
   }
    if (fOutputSummary) { delete fOutputSummary; fOutputSummary=0; }
    AliPerformanceObject* pObj=0;
    AliPerformanceTPC*  pTPC = 0;
    AliPerformanceDEdx* pDEdx = 0;
    TIterator* itOut = fOutput->MakeIterator();
    itOut->Reset();
    while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
        if (!  pTPC) {  pTPC = dynamic_cast<AliPerformanceTPC*>(pObj); }
        if (! pDEdx) { pDEdx = dynamic_cast<AliPerformanceDEdx*>(pObj); }
    }
    if (! AliCDBManager::Instance()->GetDefaultStorage()) { AliCDBManager::Instance()->SetDefaultStorage("raw://"); }
    TUUID uuid;
    TString tmpFile = gSystem->TempDirectory() + TString("/TPCQASummary.") + uuid.AsString() + TString(".root");
    AliTPCPerformanceSummary::WriteToFile(pTPC, pDEdx, tmpFile.Data());
    TChain* chain = new TChain("tpcQA");
    chain->Add(tmpFile.Data());
    TTree *tree = chain->CopyTree("1");
    if (chain) { delete chain; chain=0; }
    fOutputSummary = tree;

     // Post output data.
     PostData(2, fOutputSummary);

}

//_____________________________________________________________________________
void AliPerformanceTask::FinishTaskOutput()
{
    // called once at the end of each job (on the workernode)
    //
    // projects THnSparse to TH1,2,3

    fOutput = dynamic_cast<TList*> (GetOutputData(1));
    if (!fOutput) {
        Printf("ERROR: AliPerformanceTask::FinishTaskOutput(): fOutput data not available  ..." );
        return;
   }

      AliPerformanceObject* pObj=0;
      TIterator* itOut = fOutput->MakeIterator();
      itOut->Reset();
      while(( pObj = dynamic_cast<AliPerformanceObject*>(itOut->Next())) != NULL) {
          pObj->SetRunNumber(fCurrentRunNumber);
          pObj->Analyse();
      }

     // Post output data.
     PostData(1, fOutput);
}

//_____________________________________________________________________________
Bool_t AliPerformanceTask::Notify()
{
  static Int_t count = 0;
  count++;
  Printf("Processing %d. file", count);

  return kTRUE;
}
<|endoftext|>


<commit_before>#include "pybind11/pybind11.h"
#include "pybind11/stl_bind.h"

#define FORCE_IMPORT_ARRAY
#include "RANS3PSed.h"
#include "RANS3PSed2D.h"

#if defined(__GNUC__) && !defined(__clang__)
    namespace workaround
    {
        inline void define_allocators()
        {
            std::allocator<int> a0;
            std::allocator<double> a1;
        }
    }
#endif

namespace py = pybind11;
using proteus::cppRANS3PSed_base;
using proteus::cppRANS3PSed2D_base;

PYBIND11_MODULE(RANS3PSed, m)
{
    xt::import_numpy();

    py::class_<cppRANS3PSed_base>(m, "cppRANS3PSed_base")
        .def(py::init(&proteus::newRANS3PSed))
        .def("calculateResidual", &cppRANS3PSed_base::calculateResidual)
        .def("calculateJacobian", &cppRANS3PSed_base::calculateJacobian)
        .def("calculateVelocityAverage", &cppRANS3PSed_base::calculateVelocityAverage);
}

PYBIND11_MODULE(RANS3PSed2D, m)
{
    xt::import_numpy();

    py::class_<cppRANS3PSed2D_base>(m, "cppRANS3PSed2D_base")
        .def(py::init(&proteus::newRANS3PSed2D))
        .def("calculateResidual", &cppRANS3PSed2D_base::calculateResidual)
        .def("calculateJacobian", &cppRANS3PSed2D_base::calculateJacobian)
        .def("calculateVelocityAverage", &cppRANS3PSed2D_base::calculateVelocityAverage);
}
<commit_msg>Fixed RANS3PSed cpp module name<commit_after>#include "pybind11/pybind11.h"
#include "pybind11/stl_bind.h"

#define FORCE_IMPORT_ARRAY
#include "RANS3PSed.h"
#include "RANS3PSed2D.h"

#if defined(__GNUC__) && !defined(__clang__)
    namespace workaround
    {
        inline void define_allocators()
        {
            std::allocator<int> a0;
            std::allocator<double> a1;
        }
    }
#endif

namespace py = pybind11;
using proteus::cppRANS3PSed_base;
using proteus::cppRANS3PSed2D_base;

PYBIND11_MODULE(cRANS3PSed, m)
{
    xt::import_numpy();

    py::class_<cppRANS3PSed_base>(m, "cppRANS3PSed_base")
        .def(py::init(&proteus::newRANS3PSed))
        .def("calculateResidual", &cppRANS3PSed_base::calculateResidual)
        .def("calculateJacobian", &cppRANS3PSed_base::calculateJacobian)
        .def("calculateVelocityAverage", &cppRANS3PSed_base::calculateVelocityAverage);

    py::class_<cppRANS3PSed2D_base>(m, "cppRANS3PSed2D_base")
        .def(py::init(&proteus::newRANS3PSed2D))
        .def("calculateResidual", &cppRANS3PSed2D_base::calculateResidual)
        .def("calculateJacobian", &cppRANS3PSed2D_base::calculateJacobian)
        .def("calculateVelocityAverage", &cppRANS3PSed2D_base::calculateVelocityAverage);
}
<|endoftext|>


<commit_before>#define BOOST_LOG_DYN_LINK
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/log/trivial.hpp>

#include <openssl/evp.h>

#include "chunky.hpp"

// This is a simple implementation of the WebSocket frame protocol for
// a server. It can be used to communicate with a WebSocket client
// after a successful handshake. The class is stateless, so all
// methods are static and require a stream argument.
class WebSocket {
public:
   typedef std::vector<char> FramePayload;

   enum FrameType {
      continuation = 0x0,
      text         = 0x1,
      binary       = 0x2,
      close        = 0x8,
      ping         = 0x9,
      pong         = 0xa,
      fin          = 0x80
   };

   // Receive frames from the stream continuously.
   template<typename Stream, typename ReadHandler>
   static void receive_frames(Stream& stream, ReadHandler&& handler) {
      receive_frame(
         stream,
         [=, &stream](const boost::system::error_code& error,
             uint8_t type,
             const std::shared_ptr<FramePayload>& payload) {
            if (error) {
               handler(error, 0, std::shared_ptr<FramePayload>());
               return;
            }

            handler(boost::system::error_code(), type, payload);
            if (type != (fin | close))
               receive_frames(stream, handler);
         });
   }

   // Receive frame asynchronously.
   template<typename Stream, typename ReadHandler>
   static void receive_frame(Stream& stream, ReadHandler&& handler) {
      // Read the first two bytes of the frame header.
      auto header = std::make_shared<std::array<char, 14> >();
      boost::asio::async_read(
         stream, boost::asio::mutable_buffers_1(&(*header)[0], 2),
         [=, &stream](const boost::system::error_code& error, size_t) {
            if (error) {
               handler(error, 0, std::shared_ptr<FramePayload>());
               return;
            }

            // Determine the payload size format.
            size_t nLengthBytes = 0;
            size_t nPayloadBytes = (*header)[1] & 0x7f;
            switch (nPayloadBytes) {
            case 126:
               nLengthBytes = 2;
               nPayloadBytes = 0;
               break;
            case 127:
               nLengthBytes = 8;
               nPayloadBytes = 0;
               break;
            }

            // Configure the mask.
            const size_t nMaskBytes = ((*header)[1] & 0x80) ? 4 : 0;
            char* mask = &(*header)[2 + nLengthBytes];
            std::fill(mask, mask + nMaskBytes, 0);

            // Read the payload size and mask.
            boost::asio::async_read(
               stream, boost::asio::mutable_buffers_1(&(*header)[2], nLengthBytes + nMaskBytes),
               [=, &stream](const boost::system::error_code& error, size_t) mutable {
                  if (error) {
                     handler(error, 0, std::shared_ptr<FramePayload>());
                     return;
                  }

                  for (size_t i = 0; i < nLengthBytes; ++i) {
                     nPayloadBytes <<= 8;
                     nPayloadBytes |= static_cast<uint8_t>((*header)[2 + i]);
                  }

                  // Read the payload itself.
                  auto payload = std::make_shared<FramePayload>(nPayloadBytes);
                  boost::asio::async_read(
                     stream, boost::asio::buffer(*payload),
                     [=](const boost::system::error_code& error, size_t) {
                        if (error) {
                           handler(error, 0, std::shared_ptr<FramePayload>());
                           return;
                        }

                        // Unmask the payload buffer.
                        size_t cindex = 0;
                        for (char& c : *payload)
                           c ^= mask[cindex++ & 0x3];

                        // Dispatch the frame.
                        const uint8_t type = static_cast<uint8_t>((*header)[0]);
                        handler(boost::system::error_code(), type, payload);
                     });
               });
         });
   }

   // Send frame asynchronously.
   template<typename Stream, typename ConstBufferSequence, typename WriteHandler>
   static void send_frame(
      Stream& stream,
      uint8_t type,
      const ConstBufferSequence& buffers,
      WriteHandler&& handler) {
      // Build the frame header.
      auto header = std::make_shared<FramePayload>(build_header(type, buffers));

      // Assemble the frame from the header and payload.
      std::vector<boost::asio::const_buffer> frame;
      frame.emplace_back(header->data(), header->size());
      for (const auto& buffer : buffers)
         frame.emplace_back(buffer);

      boost::asio::async_write(
         stream, frame,
         [=](const boost::system::error_code& error, size_t) {
            if (error) {
               handler(error);
               return;
            }

            header.get();
            handler(error);
         });
   }

   // Send frame synchronously returning error via error_code argument.
   template<typename Stream, typename ConstBufferSequence>
   static void send_frame(
      Stream& stream,
      uint8_t type,
      const ConstBufferSequence& buffers,
      boost::system::error_code& error) {
      auto header = build_header(type, buffers);

      // Assemble the frame from the header and payload.
      std::vector<boost::asio::const_buffer> frame;
      frame.emplace_back(header.data(), header.size());
      for (const auto& buffer : buffers)
         frame.emplace_back(buffer);

      boost::asio::write(stream, frame, error);
   }

   // Send frame synchronously returning error via exception.
   template<typename Stream, typename ConstBufferSequence>
   static void send_frame(
      Stream& stream,
      uint8_t type,
      const ConstBufferSequence& buffers) {
      boost::system::error_code error;
      send_frame(stream, type, buffers, error);
      if (error)
         throw boost::system::system_error(error);
   }

   // Transform Sec-WebSocket-Key value to Sec-WebSocket-Accept value.
   static std::string process_key(const std::string& key) {
      EVP_MD_CTX sha1;
      EVP_DigestInit(&sha1, EVP_sha1());
      EVP_DigestUpdate(&sha1, key.data(), key.size());

      static const std::string suffix("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
      EVP_DigestUpdate(&sha1, suffix.data(), suffix.size());

      unsigned int digestSize;
      unsigned char digest[EVP_MAX_MD_SIZE];
      EVP_DigestFinal(&sha1, digest, &digestSize);

      using namespace boost::archive::iterators;
      typedef base64_from_binary<transform_width<const unsigned char*, 6, 8>> Iterator;
      std::string result((Iterator(digest)), (Iterator(digest + digestSize)));
      result.resize((result.size() + 3) & ~size_t(3), '=');
      return result;
   }

private:
   template<typename ConstBufferSequence>
   static FramePayload build_header(uint8_t type, const ConstBufferSequence& buffers) {
      FramePayload header;
      header.push_back(static_cast<char>(type));

      const size_t bufferSize = boost::asio::buffer_size(buffers);
      if (bufferSize < 126) {
         header.push_back(static_cast<char>(bufferSize));
      }
      else if (bufferSize < 65536) {
         header.push_back(static_cast<char>(126));
         header.push_back(static_cast<char>((bufferSize >> 8) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 0) & 0xff));
      }
      else {
         header.push_back(static_cast<char>(127));
         header.push_back(static_cast<char>((bufferSize >> 56) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 48) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 40) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 32) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 24) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 16) & 0xff));
         header.push_back(static_cast<char>((bufferSize >>  8) & 0xff));
         header.push_back(static_cast<char>((bufferSize >>  0) & 0xff));
      }

      return header;
   }
};

// This is a sample WebSocket session function. It manages one
// connection over its stream argument.
static void speak_websocket(const std::shared_ptr<chunky::TCP>& tcp) {
   static const std::vector<std::string> messages = {
      std::string(""),
      std::string(1, 'A'),
      std::string(2, 'B'),
      std::string(4, 'C'),
      std::string(8, 'D'),
      std::string(16, 'E'),
      std::string(32, 'F'),
      std::string(64, 'G'),
      std::string(128, 'H'),
      std::string(256, 'I'),
      std::string(512, 'J'),
      std::string(1024, 'K'),
      std::string(2048, 'L'),
      std::string(4096, 'M'),
      std::string(8192, 'N'),
      std::string(16384, 'O'),
      std::string(32768, 'P'),
      std::string(65536, 'Q'),
      std::string(131072, 'R'),
      std::string(262144, 'S'),
   };

   // Start with a fragmented message.
   WebSocket::send_frame(*tcp, WebSocket::text, boost::asio::buffer(std::string("frag")));
   WebSocket::send_frame(*tcp, WebSocket::continuation, boost::asio::buffer(std::string("ment")));
   WebSocket::send_frame(*tcp, WebSocket::continuation, boost::asio::buffer(std::string("ation")));
   WebSocket::send_frame(*tcp, WebSocket::continuation, boost::asio::buffer(std::string(" test")));
   WebSocket::send_frame(*tcp, WebSocket::fin | WebSocket::continuation, boost::asio::null_buffers());

   // Iterate through the array of test messages with this index.
   auto index = std::make_shared<int>(0);

   // Receive frames until an error or close.
   WebSocket::receive_frames(
      *tcp,
      [=](const boost::system::error_code& error,
          uint8_t type,
          const std::shared_ptr<WebSocket::FramePayload>& payload) {
         if (error) {
            BOOST_LOG_TRIVIAL(error) << error.message();
            return;
         }

         try {
            switch(type & 0x7f) {
            case WebSocket::continuation:
            case WebSocket::text:
            case WebSocket::binary:
               BOOST_LOG_TRIVIAL(info) << boost::format("%02x %6d %s")
                  % static_cast<unsigned int>(type)
                  % payload->size()
                  % std::string(payload->begin(), payload->begin() + std::min(payload->size(), size_t(20)));

               // Send the next test message (or close) when the
               // incoming message is complete.
               if (type & WebSocket::fin) {
                  if (*index < messages.size()) {
                     WebSocket::send_frame(
                        *tcp,
                        WebSocket::fin | WebSocket::text,
                        boost::asio::buffer(messages[(*index)++]),
                        [](const boost::system::error_code& error) {
                           if (error) {
                              BOOST_LOG_TRIVIAL(error) << error.message();
                              return;
                           }
                        });
                  }
                  else
                     WebSocket::send_frame(*tcp, WebSocket::fin | WebSocket::close, boost::asio::null_buffers());
               }
               break;
            case WebSocket::ping:
               BOOST_LOG_TRIVIAL(info) << "WebSocket::ping";
               WebSocket::send_frame(*tcp, WebSocket::fin | WebSocket::pong, boost::asio::buffer(*payload));
               break;
            case WebSocket::pong:
               BOOST_LOG_TRIVIAL(info) << "WebSocket::pong";
               break;
            case WebSocket::close:
               BOOST_LOG_TRIVIAL(info) << "WebSocket::close";
               break;
            }
         }
         catch (const std::exception& e) {
            BOOST_LOG_TRIVIAL(error) << e.what();
         }
      });
}

int main() {
   chunky::SimpleHTTPServer server;

   // Simple web page that opens a WebSocket on the server.
   server.add_handler("/", [](const std::shared_ptr<chunky::HTTP>& http) {
         http->response_status() = 200;
         http->response_headers()["Content-Type"] = "text/html";

         // The client will simply echo messages the server sends.
         static const std::string html =
            "<!DOCTYPE html>"
            "<title>chunky WebSocket</title>"
            "
chunky WebSocket
"
            "\n";

         boost::system::error_code error;
         boost::asio::write(*http, boost::asio::buffer(html), error);
         if (error) {
            BOOST_LOG_TRIVIAL(error) << error.message();
            return;
         }

         http->finish(error);
      });

   // Perform the WebSocket handshake on /ws.
   server.add_handler("/ws", [](const std::shared_ptr<chunky::HTTP>& http) {
         BOOST_LOG_TRIVIAL(info) << boost::format("%s %s")
            % http->request_method()
            % http->request_resource();

         auto key = http->request_headers().find("Sec-WebSocket-Key");
         if (key != http->request_headers().end()) {
            http->response_status() = 101; // Switching Protocols
            http->response_headers()["Upgrade"] = "websocket";
            http->response_headers()["Connection"] = "Upgrade";
            http->response_headers()["Sec-WebSocket-Accept"] = WebSocket::process_key(key->second);
         }
         else {
            http->response_status() = 400; // Bad Request
            http->response_headers()["Connection"] = "close";
         }

         boost::system::error_code error;
         http->finish();
         if (error) {
            BOOST_LOG_TRIVIAL(error) << error.message();
            return;
         }

         // Handshake complete, hand off stream.
         speak_websocket(http->stream());
      });

   // Set the optional logging callback.
   server.set_logger([](const std::string& message) {
         BOOST_LOG_TRIVIAL(info) << message;
      });

   // Run the server on all IPv4 and IPv6 interfaces.
   using boost::asio::ip::tcp;
   server.listen(tcp::endpoint(tcp::v4(), 8800));
   server.listen(tcp::endpoint(tcp::v6(), 8800));
   server.run();
   BOOST_LOG_TRIVIAL(info) << "listening on port 8800";

   // Accept new connections for 60 seconds. After that, the server
   // destructor will block until all existing TCP connections are
   // completed. Note that browsers may leave a connection open for
   // several minutes.
   std::this_thread::sleep_for(std::chrono::seconds(60));
   BOOST_LOG_TRIVIAL(info) << "exiting (blocks until existing connections close)";
   return 0;
}
<commit_msg>Deliver WebSocket payload by rvalue reference.<commit_after>#define BOOST_LOG_DYN_LINK
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/log/trivial.hpp>

#include <openssl/evp.h>

#include "chunky.hpp"

// This is a simple implementation of the WebSocket frame protocol for
// a server. It can be used to communicate with a WebSocket client
// after a successful handshake. The class is stateless, so all
// methods are static and require a stream argument.
class WebSocket {
public:
   typedef std::vector<char> FramePayload;

   enum FrameType {
      continuation = 0x0,
      text         = 0x1,
      binary       = 0x2,
      close        = 0x8,
      ping         = 0x9,
      pong         = 0xa,
      fin          = 0x80
   };

   // Receive frames from the stream continuously.
   template<typename Stream, typename ReadHandler>
   static void receive_frames(Stream& stream, ReadHandler&& handler) {
      receive_frame(
         stream,
         [=, &stream](const boost::system::error_code& error,
             uint8_t type,
             FramePayload&& payload) {
            if (error) {
               handler(error, 0, FramePayload());
               return;
            }

            handler(boost::system::error_code(), type, std::move(payload));
            if (type != (fin | close))
               receive_frames(stream, handler);
         });
   }

   // Receive frame asynchronously.
   template<typename Stream, typename ReadHandler>
   static void receive_frame(Stream& stream, ReadHandler&& handler) {
      // Read the first two bytes of the frame header.
      auto header = std::make_shared<std::array<char, 14> >();
      boost::asio::async_read(
         stream, boost::asio::mutable_buffers_1(&(*header)[0], 2),
         [=, &stream](const boost::system::error_code& error, size_t) {
            if (error) {
               handler(error, 0, FramePayload());
               return;
            }

            // Determine the payload size format.
            size_t nLengthBytes = 0;
            size_t nPayloadBytes = (*header)[1] & 0x7f;
            switch (nPayloadBytes) {
            case 126:
               nLengthBytes = 2;
               nPayloadBytes = 0;
               break;
            case 127:
               nLengthBytes = 8;
               nPayloadBytes = 0;
               break;
            }

            // Configure the mask.
            const size_t nMaskBytes = ((*header)[1] & 0x80) ? 4 : 0;
            char* mask = &(*header)[2 + nLengthBytes];
            std::fill(mask, mask + nMaskBytes, 0);

            // Read the payload size and mask.
            boost::asio::async_read(
               stream, boost::asio::mutable_buffers_1(&(*header)[2], nLengthBytes + nMaskBytes),
               [=, &stream](const boost::system::error_code& error, size_t) mutable {
                  if (error) {
                     handler(error, 0, FramePayload());
                     return;
                  }

                  for (size_t i = 0; i < nLengthBytes; ++i) {
                     nPayloadBytes <<= 8;
                     nPayloadBytes |= static_cast<uint8_t>((*header)[2 + i]);
                  }

                  // Read the payload itself.
                  auto payload = std::make_shared<FramePayload>(nPayloadBytes);
                  boost::asio::async_read(
                     stream, boost::asio::buffer(*payload),
                     [=](const boost::system::error_code& error, size_t) {
                        if (error) {
                           handler(error, 0, FramePayload());
                           return;
                        }

                        // Unmask the payload buffer.
                        size_t cindex = 0;
                        for (char& c : *payload)
                           c ^= mask[cindex++ & 0x3];

                        // Dispatch the frame.
                        const uint8_t type = static_cast<uint8_t>((*header)[0]);
                        handler(boost::system::error_code(), type, std::move(*payload));
                     });
               });
         });
   }

   // Send frame asynchronously.
   template<typename Stream, typename ConstBufferSequence, typename WriteHandler>
   static void send_frame(
      Stream& stream,
      uint8_t type,
      const ConstBufferSequence& buffers,
      WriteHandler&& handler) {
      // Build the frame header.
      auto header = std::make_shared<FramePayload>(build_header(type, buffers));

      // Assemble the frame from the header and payload.
      std::vector<boost::asio::const_buffer> frame;
      frame.emplace_back(header->data(), header->size());
      for (const auto& buffer : buffers)
         frame.emplace_back(buffer);

      boost::asio::async_write(
         stream, frame,
         [=](const boost::system::error_code& error, size_t) {
            if (error) {
               handler(error);
               return;
            }

            header.get();
            handler(error);
         });
   }

   // Send frame synchronously returning error via error_code argument.
   template<typename Stream, typename ConstBufferSequence>
   static void send_frame(
      Stream& stream,
      uint8_t type,
      const ConstBufferSequence& buffers,
      boost::system::error_code& error) {
      auto header = build_header(type, buffers);

      // Assemble the frame from the header and payload.
      std::vector<boost::asio::const_buffer> frame;
      frame.emplace_back(header.data(), header.size());
      for (const auto& buffer : buffers)
         frame.emplace_back(buffer);

      boost::asio::write(stream, frame, error);
   }

   // Send frame synchronously returning error via exception.
   template<typename Stream, typename ConstBufferSequence>
   static void send_frame(
      Stream& stream,
      uint8_t type,
      const ConstBufferSequence& buffers) {
      boost::system::error_code error;
      send_frame(stream, type, buffers, error);
      if (error)
         throw boost::system::system_error(error);
   }

   // Transform Sec-WebSocket-Key value to Sec-WebSocket-Accept value.
   static std::string process_key(const std::string& key) {
      EVP_MD_CTX sha1;
      EVP_DigestInit(&sha1, EVP_sha1());
      EVP_DigestUpdate(&sha1, key.data(), key.size());

      static const std::string suffix("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
      EVP_DigestUpdate(&sha1, suffix.data(), suffix.size());

      unsigned int digestSize;
      unsigned char digest[EVP_MAX_MD_SIZE];
      EVP_DigestFinal(&sha1, digest, &digestSize);

      using namespace boost::archive::iterators;
      typedef base64_from_binary<transform_width<const unsigned char*, 6, 8>> Iterator;
      std::string result((Iterator(digest)), (Iterator(digest + digestSize)));
      result.resize((result.size() + 3) & ~size_t(3), '=');
      return result;
   }

private:
   template<typename ConstBufferSequence>
   static FramePayload build_header(uint8_t type, const ConstBufferSequence& buffers) {
      FramePayload header;
      header.push_back(static_cast<char>(type));

      const size_t bufferSize = boost::asio::buffer_size(buffers);
      if (bufferSize < 126) {
         header.push_back(static_cast<char>(bufferSize));
      }
      else if (bufferSize < 65536) {
         header.push_back(static_cast<char>(126));
         header.push_back(static_cast<char>((bufferSize >> 8) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 0) & 0xff));
      }
      else {
         header.push_back(static_cast<char>(127));
         header.push_back(static_cast<char>((bufferSize >> 56) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 48) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 40) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 32) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 24) & 0xff));
         header.push_back(static_cast<char>((bufferSize >> 16) & 0xff));
         header.push_back(static_cast<char>((bufferSize >>  8) & 0xff));
         header.push_back(static_cast<char>((bufferSize >>  0) & 0xff));
      }

      return header;
   }
};

// This is a sample WebSocket session function. It manages one
// connection over its stream argument.
static void speak_websocket(const std::shared_ptr<chunky::TCP>& tcp) {
   static const std::vector<std::string> messages = {
      std::string(""),
      std::string(1, 'A'),
      std::string(2, 'B'),
      std::string(4, 'C'),
      std::string(8, 'D'),
      std::string(16, 'E'),
      std::string(32, 'F'),
      std::string(64, 'G'),
      std::string(128, 'H'),
      std::string(256, 'I'),
      std::string(512, 'J'),
      std::string(1024, 'K'),
      std::string(2048, 'L'),
      std::string(4096, 'M'),
      std::string(8192, 'N'),
      std::string(16384, 'O'),
      std::string(32768, 'P'),
      std::string(65536, 'Q'),
      std::string(131072, 'R'),
      std::string(262144, 'S'),
   };

   // Start with a fragmented message.
   WebSocket::send_frame(*tcp, WebSocket::text, boost::asio::buffer(std::string("frag")));
   WebSocket::send_frame(*tcp, WebSocket::continuation, boost::asio::buffer(std::string("ment")));
   WebSocket::send_frame(*tcp, WebSocket::continuation, boost::asio::buffer(std::string("ation")));
   WebSocket::send_frame(*tcp, WebSocket::continuation, boost::asio::buffer(std::string(" test")));
   WebSocket::send_frame(*tcp, WebSocket::fin | WebSocket::continuation, boost::asio::null_buffers());

   // Iterate through the array of test messages with this index.
   auto index = std::make_shared<int>(0);

   // Receive frames until an error or close.
   WebSocket::receive_frames(
      *tcp,
      [=](const boost::system::error_code& error,
          uint8_t type,
          WebSocket::FramePayload&& payload) {
         if (error) {
            BOOST_LOG_TRIVIAL(error) << error.message();
            return;
         }

         try {
            switch(type & 0x7f) {
            case WebSocket::continuation:
            case WebSocket::text:
            case WebSocket::binary:
               BOOST_LOG_TRIVIAL(info) << boost::format("%02x %6d %s")
                  % static_cast<unsigned int>(type)
                  % payload.size()
                  % std::string(payload.begin(), payload.begin() + std::min(payload.size(), size_t(20)));

               // Send the next test message (or close) when the
               // incoming message is complete.
               if (type & WebSocket::fin) {
                  if (*index < messages.size()) {
                     WebSocket::send_frame(
                        *tcp,
                        WebSocket::fin | WebSocket::text,
                        boost::asio::buffer(messages[(*index)++]),
                        [](const boost::system::error_code& error) {
                           if (error) {
                              BOOST_LOG_TRIVIAL(error) << error.message();
                              return;
                           }
                        });
                  }
                  else
                     WebSocket::send_frame(*tcp, WebSocket::fin | WebSocket::close, boost::asio::null_buffers());
               }
               break;
            case WebSocket::ping:
               BOOST_LOG_TRIVIAL(info) << "WebSocket::ping";
               WebSocket::send_frame(*tcp, WebSocket::fin | WebSocket::pong, boost::asio::buffer(payload));
               break;
            case WebSocket::pong:
               BOOST_LOG_TRIVIAL(info) << "WebSocket::pong";
               break;
            case WebSocket::close:
               BOOST_LOG_TRIVIAL(info) << "WebSocket::close";
               break;
            }
         }
         catch (const std::exception& e) {
            BOOST_LOG_TRIVIAL(error) << e.what();
         }
      });
}

int main() {
   chunky::SimpleHTTPServer server;

   // Simple web page that opens a WebSocket on the server.
   server.add_handler("/", [](const std::shared_ptr<chunky::HTTP>& http) {
         http->response_status() = 200;
         http->response_headers()["Content-Type"] = "text/html";

         // The client will simply echo messages the server sends.
         static const std::string html =
            "<!DOCTYPE html>"
            "<title>chunky WebSocket</title>"
            "
chunky WebSocket
"
            "\n";

         boost::system::error_code error;
         boost::asio::write(*http, boost::asio::buffer(html), error);
         if (error) {
            BOOST_LOG_TRIVIAL(error) << error.message();
            return;
         }

         http->finish(error);
      });

   // Perform the WebSocket handshake on /ws.
   server.add_handler("/ws", [](const std::shared_ptr<chunky::HTTP>& http) {
         BOOST_LOG_TRIVIAL(info) << boost::format("%s %s")
            % http->request_method()
            % http->request_resource();

         auto key = http->request_headers().find("Sec-WebSocket-Key");
         if (key != http->request_headers().end()) {
            http->response_status() = 101; // Switching Protocols
            http->response_headers()["Upgrade"] = "websocket";
            http->response_headers()["Connection"] = "Upgrade";
            http->response_headers()["Sec-WebSocket-Accept"] = WebSocket::process_key(key->second);
         }
         else {
            http->response_status() = 400; // Bad Request
            http->response_headers()["Connection"] = "close";
         }

         boost::system::error_code error;
         http->finish();
         if (error) {
            BOOST_LOG_TRIVIAL(error) << error.message();
            return;
         }

         // Handshake complete, hand off stream.
         speak_websocket(http->stream());
      });

   // Set the optional logging callback.
   server.set_logger([](const std::string& message) {
         BOOST_LOG_TRIVIAL(info) << message;
      });

   // Run the server on all IPv4 and IPv6 interfaces.
   using boost::asio::ip::tcp;
   server.listen(tcp::endpoint(tcp::v4(), 8800));
   server.listen(tcp::endpoint(tcp::v6(), 8800));
   server.run();
   BOOST_LOG_TRIVIAL(info) << "listening on port 8800";

   // Accept new connections for 60 seconds. After that, the server
   // destructor will block until all existing TCP connections are
   // completed. Note that browsers may leave a connection open for
   // several minutes.
   std::this_thread::sleep_for(std::chrono::seconds(60));
   BOOST_LOG_TRIVIAL(info) << "exiting (blocks until existing connections close)";
   return 0;
}
<|endoftext|>


<commit_before>#include "petriproperties.h"
#include "ui_petriproperties.h"

#include "diagram/arcs/ipetriarc.h"

#include "diagram/items/placeitem.h"

PetriProperties::PetriProperties(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PetriProperties)
{
    ui->setupUi(this);
    this->itemDataID = "";
    this->netData = nullptr;
    this->currentPetriItem = nullptr;
}

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

void PetriProperties::setCurrentNet(spnp::Net *net)
{
    this->netData = net;
}

void PetriProperties::onItemSelected(QGraphicsItem *item)
{
    if(item == nullptr)
    {
        this->ui->stackedWidget->setCurrentIndex(7);
        this->itemDataID = "";
    }
    else if(item->type() == IPetriItem::Type)
    {
        IPetriItem *other = qgraphicsitem_cast<IPetriItem *>(item);
        this->currentPetriItem = other;
        this->setData(other->getPetriItemId());
        switch (other->petriType())
        {
        case IPetriItem::Place:
            this->ui->stackedWidget->setCurrentIndex(0);
            this->loadPlace();
            break;
        case IPetriItem::FPlace:
            this->ui->stackedWidget->setCurrentIndex(1);
            break;
        case IPetriItem::ITrans:
            this->ui->stackedWidget->setCurrentIndex(2);
            break;
        case IPetriItem::TTrans:
            this->ui->stackedWidget->setCurrentIndex(3);
            break;
        default:
            break;
        }
    }
    else if(item->type() == IPetriArc::Type)
    {
        IPetriArc *arc = qgraphicsitem_cast<IPetriArc *>(item);
        this->setData(arc->getArcId());

        switch (arc->arcType())
        {
        case IPetriArc::Activator:
            this->ui->stackedWidget->setCurrentIndex(4);
            break;
        case IPetriArc::FActivator:
            this->ui->stackedWidget->setCurrentIndex(5);
            break;
        case IPetriArc::Inhibitor:
            this->ui->stackedWidget->setCurrentIndex(6);
            break;
        default:
            break;
        }
    }
}

void PetriProperties::on_le_place_name_textEdited(const QString &arg1)
{
    spnp::Place* p = this->netData->getPlace(itemDataID);
    if(p != nullptr)
    {
        p->setName(arg1.toStdString());
    }
    this->currentPetriItem->updateLabel(p);
}

void PetriProperties::on_le_place_tokens_textEdited(const QString &arg1)
{
    QString newValue = this->clearArg(arg1);
    spnp::Place* p = this->netData->getPlace(itemDataID);
    if(p != nullptr)
    {
        p->setToken(newValue.toStdString());
    }
    PlaceItem *pi = qgraphicsitem_cast<PlaceItem*>(this->currentPetriItem);
    pi->updateToken(newValue);
}

void PetriProperties::setData(std::string itemId)
{
    this->itemDataID = itemId;
}

void PetriProperties::loadPlace()
{
    spnp::Place* place = this->netData->getPlace(this->itemDataID);
    if(place != nullptr)
    {
        this->ui->le_place_name->setText(QString::fromStdString(place->getName()));
        this->ui->le_place_tokens->setText(QString::fromStdString(place->getToken()));
    }
}

void PetriProperties::on_le_itrans_name_textEdited(const QString &arg1)
{
    spnp::ImmediateTransition *it = this->netData->getTransition(itemDataID);
    if(it != nullptr)
    {
        it->setName(arg1.toStdString());
    }
}

void PetriProperties::on_le_itrans_prior_textEdited(const QString &arg1)
{
    //TODO
    (void)arg1;
}

void PetriProperties::on_le_itrans_guard_textEdited(const QString &arg1)
{
    //TODO
    (void)arg1;
}

void PetriProperties::on_le_net_name_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_fplace_name_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_fplace_tokens_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_fplace_limit_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_fplace_break_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_itrans_prob_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_le_itrans_prob_value_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_itrans_prob_place_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_le_ttrans_name_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_ttrans_guard_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_ttrans_prior_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_distr_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_pte_ttrans_distr_textChanged()
{

}

void PetriProperties::on_le_ttrans_rate_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_rate_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_place_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_pol_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_afected_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_rb_arc_const_toggled(bool checked)
{

}

void PetriProperties::on_le_arc_mult_textEdited(const QString &arg1)
{

}

QString PetriProperties::clearArg(QString arg1)
{
    QString newValue = arg1;
    return newValue.remove(QRegExp("\001"));
}
<commit_msg>Nome da rede<commit_after>#include "petriproperties.h"
#include "ui_petriproperties.h"

#include "diagram/arcs/ipetriarc.h"

#include "diagram/items/placeitem.h"

PetriProperties::PetriProperties(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PetriProperties)
{
    ui->setupUi(this);
    this->itemDataID = "";
    this->netData = nullptr;
    this->currentPetriItem = nullptr;
}

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

void PetriProperties::setCurrentNet(spnp::Net *net)
{
    this->netData = net;
}

void PetriProperties::onItemSelected(QGraphicsItem *item)
{
    if(item == nullptr)
    {
        this->ui->stackedWidget->setCurrentIndex(7);
        this->itemDataID = "";
    }
    else if(item->type() == IPetriItem::Type)
    {
        IPetriItem *other = qgraphicsitem_cast<IPetriItem *>(item);
        this->currentPetriItem = other;
        this->setData(other->getPetriItemId());
        switch (other->petriType())
        {
        case IPetriItem::Place:
            this->ui->stackedWidget->setCurrentIndex(0);
            this->loadPlace();
            break;
        case IPetriItem::FPlace:
            this->ui->stackedWidget->setCurrentIndex(1);
            break;
        case IPetriItem::ITrans:
            this->ui->stackedWidget->setCurrentIndex(2);
            break;
        case IPetriItem::TTrans:
            this->ui->stackedWidget->setCurrentIndex(3);
            break;
        default:
            break;
        }
    }
    else if(item->type() == IPetriArc::Type)
    {
        IPetriArc *arc = qgraphicsitem_cast<IPetriArc *>(item);
        this->setData(arc->getArcId());

        switch (arc->arcType())
        {
        case IPetriArc::Activator:
            this->ui->stackedWidget->setCurrentIndex(4);
            break;
        case IPetriArc::FActivator:
            this->ui->stackedWidget->setCurrentIndex(5);
            break;
        case IPetriArc::Inhibitor:
            this->ui->stackedWidget->setCurrentIndex(6);
            break;
        default:
            break;
        }
    }
}

void PetriProperties::on_le_place_name_textEdited(const QString &arg1)
{
    spnp::Place* p = this->netData->getPlace(itemDataID);
    if(p != nullptr)
    {
        p->setName(arg1.toStdString());
    }
    this->currentPetriItem->updateLabel(p);
}

void PetriProperties::on_le_place_tokens_textEdited(const QString &arg1)
{
    QString newValue = this->clearArg(arg1);
    spnp::Place* p = this->netData->getPlace(itemDataID);
    if(p != nullptr)
    {
        p->setToken(newValue.toStdString());
    }
    PlaceItem *pi = qgraphicsitem_cast<PlaceItem*>(this->currentPetriItem);
    pi->updateToken(newValue);
}

void PetriProperties::setData(std::string itemId)
{
    this->itemDataID = itemId;
}

void PetriProperties::loadPlace()
{
    spnp::Place* place = this->netData->getPlace(this->itemDataID);
    if(place != nullptr)
    {
        this->ui->le_place_name->setText(QString::fromStdString(place->getName()));
        this->ui->le_place_tokens->setText(QString::fromStdString(place->getToken()));
    }
}

void PetriProperties::on_le_itrans_name_textEdited(const QString &arg1)
{
    spnp::ImmediateTransition *it = this->netData->getTransition(itemDataID);
    if(it != nullptr)
    {
        it->setName(arg1.toStdString());
    }
}

void PetriProperties::on_le_itrans_prior_textEdited(const QString &arg1)
{
    //TODO
    (void)arg1;
}

void PetriProperties::on_le_itrans_guard_textEdited(const QString &arg1)
{
    //TODO
    (void)arg1;
}

void PetriProperties::on_le_net_name_textEdited(const QString &arg1)
{
    this->netData->setName(arg1.toStdString());
}

void PetriProperties::on_le_fplace_name_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_fplace_tokens_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_fplace_limit_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_fplace_break_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_itrans_prob_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_le_itrans_prob_value_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_itrans_prob_place_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_le_ttrans_name_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_ttrans_guard_textEdited(const QString &arg1)
{

}

void PetriProperties::on_le_ttrans_prior_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_distr_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_pte_ttrans_distr_textChanged()
{

}

void PetriProperties::on_le_ttrans_rate_textEdited(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_rate_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_place_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_pol_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_cb_ttrans_afected_currentTextChanged(const QString &arg1)
{

}

void PetriProperties::on_rb_arc_const_toggled(bool checked)
{

}

void PetriProperties::on_le_arc_mult_textEdited(const QString &arg1)
{

}

QString PetriProperties::clearArg(QString arg1)
{
    QString newValue = arg1;
    return newValue.remove(QRegExp("\001"));
}
<|endoftext|>


<commit_before>//Create by Christine Nattrass, Rebecca Scott, Irakli Martashvili
//University of Tennessee at Knoxville

//by default this runs locally
//With the argument true this submits jobs to the grid
//As written this requires an xml script tag.xml in the ~/et directory on the grid to submit jobs
void runCaloEt(bool submit = false, // true or false
	       const char *dataType="sim", // "sim" or "real" etc.
	       const char *pluginRunMode="full", // "test" or "full" or "terminate"
	       const char *det = "EMCAL") // "PHOS" or "EMCAL"
{
  TStopwatch timer;
  timer.Start();
  gSystem->Load("libTree");
  gSystem->Load("libGeom");
  gSystem->Load("libVMC");
  gSystem->Load("libPhysics");

  gSystem->Load("libMinuit");

  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
  gSystem->AddIncludePath("-I. -I$ALICE_ROOT/EMCAL -I$ALICE_ROOT/ANALYSIS");

  gSystem->Load("libSTEERBase");
  gSystem->Load("libESD");
  gSystem->Load("libAOD");

  gSystem->Load("libANALYSIS");
  gSystem->Load("libANALYSISalice");
  gSystem->Load("libCORRFW");

  if (!submit) {
    cout << "local - no submitting" << endl;
  }
  else {
    cout << "submitting to grid" << endl;
  }

  gROOT->ProcessLine(".L AliAnalysisEtCuts.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisHadEtCorrections.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtCommon.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEt.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtMonteCarlo.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtMonteCarloPhos.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtMonteCarloEmcal.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtReconstructed.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtReconstructedPhos.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtReconstructedEmcal.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtSelectionContainer.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtSelectionHandler.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisTaskTransverseEnergy.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisTaskTotEt.cxx+g");

   gInterpreter->GenerateDictionary("std::map<int, AliPhysicsSelection*>", "AliPhysicsSelection.h;map")  ;
   gInterpreter->GenerateDictionary("std::pair<int, AliPhysicsSelection*>", "AliPhysicsSelection.h;utility");

  char *kTreeName = "esdTree" ;
  TChain * chain   = new TChain(kTreeName,"myESDTree") ;

  if(submit){
    gSystem->Load("libNetx") ;
    gSystem->Load("libgapiUI");
    gSystem->Load("libRAliEn");
    TGrid::Connect("alien://") ;
  }

  // Make the analysis manager
  AliAnalysisManager *mgr = new AliAnalysisManager("TotEtManager");

  TString detStr(det);
  TString taskName = "TaskTotEt" + detStr;
  TString dataStr(dataType);
  TString dataStrName(dataType);
  dataStrName.ReplaceAll("/",".");
  TString outputName = "Et.ESD." + dataStrName + "." + detStr + ".root";
  TString outputDir = "totEt" + dataStr;

  cout << " taskName " << taskName
       << " outputName " << outputName
       << " outputDir (alien) " << outputDir << endl;

  if (submit) {
    gROOT->LoadMacro("CreateAlienHandlerCaloEtSim.C");
    AliAnalysisGrid *alienHandler = CreateAlienHandlerCaloEtSim(outputDir, outputName, pluginRunMode);
    if (!alienHandler) return;
    mgr->SetGridHandler(alienHandler);
  }

  AliVEventHandler* esdH = new AliESDInputHandler;
  mgr->SetInputEventHandler(esdH);
  AliMCEventHandler* handler = new AliMCEventHandler;
  Bool_t isMc = kTRUE;
  Bool_t isPb = kFALSE;
  if ( dataStr.Contains("PbPb") ) { isPb = kTRUE;}
  if ( dataStr.Contains("sim") ) {
    cout << " MC " << endl;
    if ( dataStr.Contains("PbPb") ) { // a la: simPbPb/LHC10e18a
      cout << " PbPb " << endl;
      TString fileLocation = "/home/dsilverm/data/E_T/" + dataStr + "/dir/AliESDs.root";
      cout << "fileLocation " << fileLocation.Data() << endl;
      chain->Add(fileLocation.Data()); // link to local test file
    }
    else { // pp
      chain->Add("/data/LHC10d15/1821/AliESDs.root");
      //chain->Add("/data/LHC10dpass2/10000126403050.70/AliESDs.root");//data
      //chain->Add("/home/dsilverm/data/E_T/sim/LHC10d1/117222/100/AliESDs.root"); // link to local test file
    }
    handler->SetReadTR(kFALSE);
    mgr->SetMCtruthEventHandler(handler);
  }
  else { // real data
    isMc = kFALSE;
    chain->Add("/home/dsilverm/data/E_T/data/2010/LHC10b/000117222/ESDs/pass2/10000117222021.30/AliESDs.root"); // link to local test file
    cout << " not MC " << endl;
  }

  gROOT->ProcessLine(".L $ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");

  AliPhysicsSelectionTask *physicsSelectionTask = AddTaskPhysicsSelection(isMc);//isMC is true when processing monte carlo

  if(isPb){
    gROOT->ProcessLine(".L $ALICE_ROOT/ANALYSIS/macros/AddTaskCentrality.C");
    gROOT->ProcessLine(".L AliCentralitySelectionTask.cxx++g");
    AliCentralitySelectionTask *centTask = AddTaskCentrality();
  }

  AliAnalysisTaskTotEt *task1 = new AliAnalysisTaskTotEt(taskName);
  task1->SetMcData(isMc);//necessary to tell the task to basically accept all MC events.
  mgr->AddTask(task1);

  AliAnalysisDataContainer *cinput1 = mgr->GetCommonInputContainer();
  AliAnalysisDataContainer *coutput1 = mgr->CreateContainer("out1", TList::Class(), AliAnalysisManager::kOutputContainer, outputName);

  //____________________________________________//
  mgr->ConnectInput(task1,0,cinput1);
  mgr->ConnectOutput(task1,1,coutput1);

  mgr->SetDebugLevel(0);

  if (!mgr->InitAnalysis()) return;
  mgr->PrintStatus();
  if(submit){
    mgr->StartAnalysis("grid");
  }
  else{
    mgr->StartAnalysis("local",chain);
  }

  timer.Stop();
  timer.Print();
}
<commit_msg>Adding lines to compile Marcelos code to driver macro<commit_after>//Create by Christine Nattrass, Rebecca Scott, Irakli Martashvili
//University of Tennessee at Knoxville

//by default this runs locally
//With the argument true this submits jobs to the grid
//As written this requires an xml script tag.xml in the ~/et directory on the grid to submit jobs
void runCaloEt(bool submit = false, // true or false
	       const char *dataType="sim", // "sim" or "real" etc.
	       const char *pluginRunMode="full", // "test" or "full" or "terminate"
	       const char *det = "EMCAL") // "PHOS" or "EMCAL"
{
  TStopwatch timer;
  timer.Start();
  gSystem->Load("libTree");
  gSystem->Load("libGeom");
  gSystem->Load("libVMC");
  gSystem->Load("libPhysics");

  gSystem->Load("libMinuit");

  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
  gSystem->AddIncludePath("-I. -I$ALICE_ROOT/EMCAL -I$ALICE_ROOT/ANALYSIS");

  gSystem->Load("libSTEERBase");
  gSystem->Load("libESD");
  gSystem->Load("libAOD");

  gSystem->Load("libANALYSIS");
  gSystem->Load("libANALYSISalice");
  gSystem->Load("libCORRFW");

  if (!submit) {
    cout << "local - no submitting" << endl;
  }
  else {
    cout << "submitting to grid" << endl;
  }

  gROOT->ProcessLine(".L AliAnalysisEtCuts.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisHadEtCorrections.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtCommon.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEt.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtMonteCarlo.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtMonteCarloPhos.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtMonteCarloEmcal.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtReconstructed.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtReconstructedPhos.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtReconstructedEmcal.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtSelectionContainer.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisEtSelectionHandler.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisTaskTransverseEnergy.cxx+g");
gROOT->ProcessLine(".L AliAnalysisEmEtMonteCarlo.cxx+g");
gROOT->ProcessLine(".L AliAnalysisEmEtReconstructed.cxx+g");
  gROOT->ProcessLine(".L AliAnalysisTaskTotEt.cxx+g");

   gInterpreter->GenerateDictionary("std::map<int, AliPhysicsSelection*>", "AliPhysicsSelection.h;map")  ;
   gInterpreter->GenerateDictionary("std::pair<int, AliPhysicsSelection*>", "AliPhysicsSelection.h;utility");

  char *kTreeName = "esdTree" ;
  TChain * chain   = new TChain(kTreeName,"myESDTree") ;

  if(submit){
    gSystem->Load("libNetx") ;
    gSystem->Load("libgapiUI");
    gSystem->Load("libRAliEn");
    TGrid::Connect("alien://") ;
  }

  // Make the analysis manager
  AliAnalysisManager *mgr = new AliAnalysisManager("TotEtManager");

  TString detStr(det);
  TString taskName = "TaskTotEt" + detStr;
  TString dataStr(dataType);
  TString dataStrName(dataType);
  dataStrName.ReplaceAll("/",".");
  TString outputName = "Et.ESD." + dataStrName + "." + detStr + ".root";
  TString outputDir = "totEt" + dataStr;

  cout << " taskName " << taskName
       << " outputName " << outputName
       << " outputDir (alien) " << outputDir << endl;

  if (submit) {
    gROOT->LoadMacro("CreateAlienHandlerCaloEtSim.C");
    AliAnalysisGrid *alienHandler = CreateAlienHandlerCaloEtSim(outputDir, outputName, pluginRunMode);
    if (!alienHandler) return;
    mgr->SetGridHandler(alienHandler);
  }

  AliVEventHandler* esdH = new AliESDInputHandler;
  mgr->SetInputEventHandler(esdH);
  AliMCEventHandler* handler = new AliMCEventHandler;
  Bool_t isMc = kTRUE;
  Bool_t isPb = kFALSE;
  if ( dataStr.Contains("PbPb") ) { isPb = kTRUE;}
  if ( dataStr.Contains("sim") ) {
    cout << " MC " << endl;
    if ( dataStr.Contains("PbPb") ) { // a la: simPbPb/LHC10e18a
      cout << " PbPb " << endl;
      TString fileLocation = "/home/dsilverm/data/E_T/" + dataStr + "/dir/AliESDs.root";
      cout << "fileLocation " << fileLocation.Data() << endl;
      chain->Add(fileLocation.Data()); // link to local test file
    }
    else { // pp
      chain->Add("/data/LHC10d15/1821/AliESDs.root");
      //chain->Add("/data/LHC10dpass2/10000126403050.70/AliESDs.root");//data
      //chain->Add("/home/dsilverm/data/E_T/sim/LHC10d1/117222/100/AliESDs.root"); // link to local test file
    }
    handler->SetReadTR(kFALSE);
    mgr->SetMCtruthEventHandler(handler);
  }
  else { // real data
    isMc = kFALSE;
    chain->Add("/home/dsilverm/data/E_T/data/2010/LHC10b/000117222/ESDs/pass2/10000117222021.30/AliESDs.root"); // link to local test file
    cout << " not MC " << endl;
  }

  gROOT->ProcessLine(".L $ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");

  AliPhysicsSelectionTask *physicsSelectionTask = AddTaskPhysicsSelection(isMc);//isMC is true when processing monte carlo

  if(isPb){
    gROOT->ProcessLine(".L $ALICE_ROOT/ANALYSIS/macros/AddTaskCentrality.C");
    gROOT->ProcessLine(".L AliCentralitySelectionTask.cxx++g");
    AliCentralitySelectionTask *centTask = AddTaskCentrality();
  }

  AliAnalysisTaskTotEt *task1 = new AliAnalysisTaskTotEt(taskName);
  task1->SetMcData(isMc);//necessary to tell the task to basically accept all MC events.
  mgr->AddTask(task1);

  AliAnalysisDataContainer *cinput1 = mgr->GetCommonInputContainer();
  AliAnalysisDataContainer *coutput1 = mgr->CreateContainer("out1", TList::Class(), AliAnalysisManager::kOutputContainer, outputName);

  //____________________________________________//
  mgr->ConnectInput(task1,0,cinput1);
  mgr->ConnectOutput(task1,1,coutput1);

  mgr->SetDebugLevel(0);

  if (!mgr->InitAnalysis()) return;
  mgr->PrintStatus();
  if(submit){
    mgr->StartAnalysis("grid");
  }
  else{
    mgr->StartAnalysis("local",chain);
  }

  timer.Stop();
  timer.Print();
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "p2p/base/datagram_dtls_adaptor.h"

#include <algorithm>
#include <memory>
#include <utility>

#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "api/rtc_error.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "p2p/base/dtls_transport_internal.h"
#include "p2p/base/packet_transport_internal.h"
#include "rtc_base/buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/dscp.h"
#include "rtc_base/flags.h"
#include "rtc_base/logging.h"
#include "rtc_base/message_queue.h"
#include "rtc_base/rtc_certificate.h"
#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/stream.h"
#include "rtc_base/thread.h"

#ifdef BYPASS_DATAGRAM_DTLS_TEST_ONLY
// Send unencrypted packets directly to ICE, bypassing datagtram
// transport. Use in tests only.
constexpr bool kBypassDatagramDtlsTestOnly = true;
#else
constexpr bool kBypassDatagramDtlsTestOnly = false;
#endif

namespace cricket {

DatagramDtlsAdaptor::DatagramDtlsAdaptor(
    std::unique_ptr<IceTransportInternal> ice_transport,
    std::unique_ptr<webrtc::DatagramTransportInterface> datagram_transport,
    const webrtc::CryptoOptions& crypto_options,
    webrtc::RtcEventLog* event_log)
    : crypto_options_(crypto_options),
      ice_transport_(std::move(ice_transport)),
      datagram_transport_(std::move(datagram_transport)),
      event_log_(event_log) {
  RTC_DCHECK(ice_transport_);
  RTC_DCHECK(datagram_transport_);
  ConnectToIceTransport();
}

void DatagramDtlsAdaptor::ConnectToIceTransport() {
  if (kBypassDatagramDtlsTestOnly) {
    // In bypass mode we have to subscribe to ICE read and sent events.
    // Test only case to use ICE directly instead of data transport.
    ice_transport_->SignalReadPacket.connect(
        this, &DatagramDtlsAdaptor::OnReadPacket);

    ice_transport_->SignalSentPacket.connect(
        this, &DatagramDtlsAdaptor::OnSentPacket);

    ice_transport_->SignalWritableState.connect(
        this, &DatagramDtlsAdaptor::OnWritableState);
    ice_transport_->SignalReadyToSend.connect(
        this, &DatagramDtlsAdaptor::OnReadyToSend);
    ice_transport_->SignalReceivingState.connect(
        this, &DatagramDtlsAdaptor::OnReceivingState);
  } else {
    // Subscribe to Data Transport read packets.
    datagram_transport_->SetDatagramSink(this);
    datagram_transport_->SetTransportStateCallback(this);

    // Datagram transport does not propagate network route change.
    ice_transport_->SignalNetworkRouteChanged.connect(
        this, &DatagramDtlsAdaptor::OnNetworkRouteChanged);
  }
}

DatagramDtlsAdaptor::~DatagramDtlsAdaptor() {
  // Unsubscribe from Datagram Transport dinks.
  datagram_transport_->SetDatagramSink(nullptr);
  datagram_transport_->SetTransportStateCallback(nullptr);

  // Make sure datagram transport is destroyed before ICE.
  datagram_transport_.reset();
  ice_transport_.reset();
}

const webrtc::CryptoOptions& DatagramDtlsAdaptor::crypto_options() const {
  return crypto_options_;
}

int DatagramDtlsAdaptor::SendPacket(const char* data,
                                    size_t len,
                                    const rtc::PacketOptions& options,
                                    int flags) {
  // TODO(sukhanov): Handle options and flags.
  if (kBypassDatagramDtlsTestOnly) {
    // In bypass mode sent directly to ICE.
    return ice_transport_->SendPacket(data, len, options);
  }

  // Send datagram with id equal to options.packet_id, so we get it back
  // in DatagramDtlsAdaptor::OnDatagramSent() and propagate notification
  // up.
  webrtc::RTCError error = datagram_transport_->SendDatagram(
      rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(data), len),
      /*datagram_id=*/options.packet_id);

  return (error.ok() ? len : -1);
}

void DatagramDtlsAdaptor::OnReadPacket(rtc::PacketTransportInternal* transport,
                                       const char* data,
                                       size_t size,
                                       const int64_t& packet_time_us,
                                       int flags) {
  // Only used in bypass mode.
  RTC_DCHECK(kBypassDatagramDtlsTestOnly);

  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK_EQ(transport, ice_transport_.get());
  RTC_DCHECK(flags == 0);

  PropagateReadPacket(
      rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(data), size),
      packet_time_us);
}

void DatagramDtlsAdaptor::OnDatagramReceived(
    rtc::ArrayView<const uint8_t> data) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK(!kBypassDatagramDtlsTestOnly);

  // TODO(sukhanov): I am not filling out time, but on my video quality
  // test in WebRTC the time was not set either and higher layers of the stack
  // overwrite -1 with current current rtc time. Leaveing comment for now to
  // make sure it works as expected.
  int64_t packet_time_us = -1;

  PropagateReadPacket(data, packet_time_us);
}

void DatagramDtlsAdaptor::OnDatagramSent(webrtc::DatagramId datagram_id) {
  // When we called DatagramTransportInterface::SendDatagram, we passed
  // packet_id as datagram_id, so we simply need to set it in sent_packet
  // and propagate notification up the stack.

  // Also see how DatagramDtlsAdaptor::OnSentPacket handles OnSentPacket
  // notification from ICE in bypass mode.
  rtc::SentPacket sent_packet(/*packet_id=*/datagram_id, rtc::TimeMillis());

  PropagateOnSentNotification(sent_packet);
}

void DatagramDtlsAdaptor::OnSentPacket(rtc::PacketTransportInternal* transport,
                                       const rtc::SentPacket& sent_packet) {
  // Only used in bypass mode.
  RTC_DCHECK(kBypassDatagramDtlsTestOnly);
  RTC_DCHECK_RUN_ON(&thread_checker_);

  PropagateOnSentNotification(sent_packet);
}

void DatagramDtlsAdaptor::PropagateOnSentNotification(
    const rtc::SentPacket& sent_packet) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  SignalSentPacket(this, sent_packet);
}

void DatagramDtlsAdaptor::PropagateReadPacket(
    rtc::ArrayView<const uint8_t> data,
    const int64_t& packet_time_us) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  SignalReadPacket(this, reinterpret_cast<const char*>(data.data()),
                   data.size(), packet_time_us, /*flags=*/0);
}

int DatagramDtlsAdaptor::component() const {
  return kDatagramDtlsAdaptorComponent;
}
bool DatagramDtlsAdaptor::IsDtlsActive() const {
  return false;
}
bool DatagramDtlsAdaptor::GetDtlsRole(rtc::SSLRole* role) const {
  return false;
}
bool DatagramDtlsAdaptor::SetDtlsRole(rtc::SSLRole role) {
  return false;
}
bool DatagramDtlsAdaptor::GetSrtpCryptoSuite(int* cipher) {
  return false;
}
bool DatagramDtlsAdaptor::GetSslCipherSuite(int* cipher) {
  return false;
}

rtc::scoped_refptr<rtc::RTCCertificate>
DatagramDtlsAdaptor::GetLocalCertificate() const {
  return nullptr;
}

bool DatagramDtlsAdaptor::SetLocalCertificate(
    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
  return false;
}

std::unique_ptr<rtc::SSLCertChain> DatagramDtlsAdaptor::GetRemoteSSLCertChain()
    const {
  return nullptr;
}

bool DatagramDtlsAdaptor::ExportKeyingMaterial(const std::string& label,
                                               const uint8_t* context,
                                               size_t context_len,
                                               bool use_context,
                                               uint8_t* result,
                                               size_t result_len) {
  return false;
}

bool DatagramDtlsAdaptor::SetRemoteFingerprint(const std::string& digest_alg,
                                               const uint8_t* digest,
                                               size_t digest_len) {
  // TODO(sukhanov): We probably should not called with fingerptints in
  // datagram scenario, but we may need to change code up the stack before
  // we can return false or DCHECK.
  return true;
}

bool DatagramDtlsAdaptor::SetSslMaxProtocolVersion(
    rtc::SSLProtocolVersion version) {
  // TODO(sukhanov): We may be able to return false and/or DCHECK that we
  // are not called if datagram transport is used, but we need to change
  // integration before we can do it.
  return true;
}

IceTransportInternal* DatagramDtlsAdaptor::ice_transport() {
  return ice_transport_.get();
}

webrtc::DatagramTransportInterface* DatagramDtlsAdaptor::datagram_transport() {
  return datagram_transport_.get();
}

// Similar implementaton as in p2p/base/dtls_transport.cc.
void DatagramDtlsAdaptor::OnReadyToSend(
    rtc::PacketTransportInternal* transport) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  if (writable()) {
    SignalReadyToSend(this);
  }
}

void DatagramDtlsAdaptor::OnWritableState(
    rtc::PacketTransportInternal* transport) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK(transport == ice_transport_.get());
  RTC_LOG(LS_VERBOSE) << ": ice_transport writable state changed to "
                      << ice_transport_->writable();

  if (kBypassDatagramDtlsTestOnly) {
    // Note: SignalWritableState fired by set_writable.
    set_writable(ice_transport_->writable());
    return;
  }

  switch (dtls_state()) {
    case DTLS_TRANSPORT_NEW:
      break;
    case DTLS_TRANSPORT_CONNECTED:
      // Note: SignalWritableState fired by set_writable.
      // Do we also need set_receiving(ice_transport_->receiving()) here now, in
      // case we lose that signal before "DTLS" connects?
      // DtlsTransport::OnWritableState does not set_receiving in a similar
      // case, so leaving it out for the time being, but it would be good to
      // understand why.
      set_writable(ice_transport_->writable());
      break;
    case DTLS_TRANSPORT_CONNECTING:
      // Do nothing.
      break;
    case DTLS_TRANSPORT_FAILED:
    case DTLS_TRANSPORT_CLOSED:
      // Should not happen. Do nothing.
      break;
  }
}

void DatagramDtlsAdaptor::OnStateChanged(webrtc::MediaTransportState state) {
  // Convert MediaTransportState to DTLS state.
  switch (state) {
    case webrtc::MediaTransportState::kPending:
      set_dtls_state(DTLS_TRANSPORT_CONNECTING);
      break;

    case webrtc::MediaTransportState::kWritable:
      // Since we do not set writable state until datagram transport is
      // connected, we need to call set_writable first.
      set_writable(ice_transport_->writable());
      set_dtls_state(DTLS_TRANSPORT_CONNECTED);
      break;

    case webrtc::MediaTransportState::kClosed:
      set_dtls_state(DTLS_TRANSPORT_CLOSED);
      break;
  }
}

DtlsTransportState DatagramDtlsAdaptor::dtls_state() const {
  return dtls_state_;
}

const std::string& DatagramDtlsAdaptor::transport_name() const {
  return ice_transport_->transport_name();
}

bool DatagramDtlsAdaptor::writable() const {
  // NOTE that even if ice is writable, writable_ maybe false, because we
  // propagte writable only after DTLS is connect (this is consistent with
  // implementation in dtls_transport.cc).
  return writable_;
}

bool DatagramDtlsAdaptor::receiving() const {
  return receiving_;
}

int DatagramDtlsAdaptor::SetOption(rtc::Socket::Option opt, int value) {
  return ice_transport_->SetOption(opt, value);
}

int DatagramDtlsAdaptor::GetError() {
  return ice_transport_->GetError();
}

void DatagramDtlsAdaptor::OnNetworkRouteChanged(
    absl::optional<rtc::NetworkRoute> network_route) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  SignalNetworkRouteChanged(network_route);
}

void DatagramDtlsAdaptor::OnReceivingState(
    rtc::PacketTransportInternal* transport) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK(transport == ice_transport_.get());
  RTC_LOG(LS_VERBOSE) << "ice_transport receiving state changed to "
                      << ice_transport_->receiving();

  if (kBypassDatagramDtlsTestOnly || dtls_state() == DTLS_TRANSPORT_CONNECTED) {
    // Note: SignalReceivingState fired by set_receiving.
    set_receiving(ice_transport_->receiving());
  }
}

void DatagramDtlsAdaptor::set_receiving(bool receiving) {
  if (receiving_ == receiving) {
    return;
  }
  receiving_ = receiving;
  SignalReceivingState(this);
}

// Similar implementaton as in p2p/base/dtls_transport.cc.
void DatagramDtlsAdaptor::set_writable(bool writable) {
  if (writable_ == writable) {
    return;
  }
  if (event_log_) {
    event_log_->Log(
        absl::make_unique<webrtc::RtcEventDtlsWritableState>(writable));
  }
  RTC_LOG(LS_VERBOSE) << "set_writable to: " << writable;
  writable_ = writable;
  if (writable_) {
    SignalReadyToSend(this);
  }
  SignalWritableState(this);
}

// Similar implementaton as in p2p/base/dtls_transport.cc.
void DatagramDtlsAdaptor::set_dtls_state(DtlsTransportState state) {
  if (dtls_state_ == state) {
    return;
  }
  if (event_log_) {
    event_log_->Log(absl::make_unique<webrtc::RtcEventDtlsTransportState>(
        ConvertDtlsTransportState(state)));
  }
  RTC_LOG(LS_VERBOSE) << "set_dtls_state from:" << dtls_state_ << " to "
                      << state;
  dtls_state_ = state;
  SignalDtlsState(this, state);
}

}  // namespace cricket
<commit_msg>Fix ICE connection in datagram_transport.<commit_after>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "p2p/base/datagram_dtls_adaptor.h"

#include <algorithm>
#include <memory>
#include <utility>

#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "api/rtc_error.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_transport_state.h"
#include "logging/rtc_event_log/events/rtc_event_dtls_writable_state.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "p2p/base/dtls_transport_internal.h"
#include "p2p/base/packet_transport_internal.h"
#include "rtc_base/buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/dscp.h"
#include "rtc_base/flags.h"
#include "rtc_base/logging.h"
#include "rtc_base/message_queue.h"
#include "rtc_base/rtc_certificate.h"
#include "rtc_base/ssl_stream_adapter.h"
#include "rtc_base/stream.h"
#include "rtc_base/thread.h"

#ifdef BYPASS_DATAGRAM_DTLS_TEST_ONLY
// Send unencrypted packets directly to ICE, bypassing datagtram
// transport. Use in tests only.
constexpr bool kBypassDatagramDtlsTestOnly = true;
#else
constexpr bool kBypassDatagramDtlsTestOnly = false;
#endif

namespace cricket {

DatagramDtlsAdaptor::DatagramDtlsAdaptor(
    std::unique_ptr<IceTransportInternal> ice_transport,
    std::unique_ptr<webrtc::DatagramTransportInterface> datagram_transport,
    const webrtc::CryptoOptions& crypto_options,
    webrtc::RtcEventLog* event_log)
    : crypto_options_(crypto_options),
      ice_transport_(std::move(ice_transport)),
      datagram_transport_(std::move(datagram_transport)),
      event_log_(event_log) {
  RTC_DCHECK(ice_transport_);
  RTC_DCHECK(datagram_transport_);
  ConnectToIceTransport();
}

void DatagramDtlsAdaptor::ConnectToIceTransport() {
  ice_transport_->SignalWritableState.connect(
      this, &DatagramDtlsAdaptor::OnWritableState);
  ice_transport_->SignalReadyToSend.connect(
      this, &DatagramDtlsAdaptor::OnReadyToSend);
  ice_transport_->SignalReceivingState.connect(
      this, &DatagramDtlsAdaptor::OnReceivingState);

  // Datagram transport does not propagate network route change.
  ice_transport_->SignalNetworkRouteChanged.connect(
      this, &DatagramDtlsAdaptor::OnNetworkRouteChanged);

  if (kBypassDatagramDtlsTestOnly) {
    // In bypass mode we have to subscribe to ICE read and sent events.
    // Test only case to use ICE directly instead of data transport.
    ice_transport_->SignalReadPacket.connect(
        this, &DatagramDtlsAdaptor::OnReadPacket);

    ice_transport_->SignalSentPacket.connect(
        this, &DatagramDtlsAdaptor::OnSentPacket);
  } else {
    // Subscribe to Data Transport read packets.
    datagram_transport_->SetDatagramSink(this);
    datagram_transport_->SetTransportStateCallback(this);
  }
}

DatagramDtlsAdaptor::~DatagramDtlsAdaptor() {
  // Unsubscribe from Datagram Transport dinks.
  datagram_transport_->SetDatagramSink(nullptr);
  datagram_transport_->SetTransportStateCallback(nullptr);

  // Make sure datagram transport is destroyed before ICE.
  datagram_transport_.reset();
  ice_transport_.reset();
}

const webrtc::CryptoOptions& DatagramDtlsAdaptor::crypto_options() const {
  return crypto_options_;
}

int DatagramDtlsAdaptor::SendPacket(const char* data,
                                    size_t len,
                                    const rtc::PacketOptions& options,
                                    int flags) {
  // TODO(sukhanov): Handle options and flags.
  if (kBypassDatagramDtlsTestOnly) {
    // In bypass mode sent directly to ICE.
    return ice_transport_->SendPacket(data, len, options);
  }

  // Send datagram with id equal to options.packet_id, so we get it back
  // in DatagramDtlsAdaptor::OnDatagramSent() and propagate notification
  // up.
  webrtc::RTCError error = datagram_transport_->SendDatagram(
      rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(data), len),
      /*datagram_id=*/options.packet_id);

  return (error.ok() ? len : -1);
}

void DatagramDtlsAdaptor::OnReadPacket(rtc::PacketTransportInternal* transport,
                                       const char* data,
                                       size_t size,
                                       const int64_t& packet_time_us,
                                       int flags) {
  // Only used in bypass mode.
  RTC_DCHECK(kBypassDatagramDtlsTestOnly);

  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK_EQ(transport, ice_transport_.get());
  RTC_DCHECK(flags == 0);

  PropagateReadPacket(
      rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(data), size),
      packet_time_us);
}

void DatagramDtlsAdaptor::OnDatagramReceived(
    rtc::ArrayView<const uint8_t> data) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK(!kBypassDatagramDtlsTestOnly);

  // TODO(sukhanov): I am not filling out time, but on my video quality
  // test in WebRTC the time was not set either and higher layers of the stack
  // overwrite -1 with current current rtc time. Leaveing comment for now to
  // make sure it works as expected.
  int64_t packet_time_us = -1;

  PropagateReadPacket(data, packet_time_us);
}

void DatagramDtlsAdaptor::OnDatagramSent(webrtc::DatagramId datagram_id) {
  // When we called DatagramTransportInterface::SendDatagram, we passed
  // packet_id as datagram_id, so we simply need to set it in sent_packet
  // and propagate notification up the stack.

  // Also see how DatagramDtlsAdaptor::OnSentPacket handles OnSentPacket
  // notification from ICE in bypass mode.
  rtc::SentPacket sent_packet(/*packet_id=*/datagram_id, rtc::TimeMillis());

  PropagateOnSentNotification(sent_packet);
}

void DatagramDtlsAdaptor::OnSentPacket(rtc::PacketTransportInternal* transport,
                                       const rtc::SentPacket& sent_packet) {
  // Only used in bypass mode.
  RTC_DCHECK(kBypassDatagramDtlsTestOnly);
  RTC_DCHECK_RUN_ON(&thread_checker_);

  PropagateOnSentNotification(sent_packet);
}

void DatagramDtlsAdaptor::PropagateOnSentNotification(
    const rtc::SentPacket& sent_packet) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  SignalSentPacket(this, sent_packet);
}

void DatagramDtlsAdaptor::PropagateReadPacket(
    rtc::ArrayView<const uint8_t> data,
    const int64_t& packet_time_us) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  SignalReadPacket(this, reinterpret_cast<const char*>(data.data()),
                   data.size(), packet_time_us, /*flags=*/0);
}

int DatagramDtlsAdaptor::component() const {
  return kDatagramDtlsAdaptorComponent;
}
bool DatagramDtlsAdaptor::IsDtlsActive() const {
  return false;
}
bool DatagramDtlsAdaptor::GetDtlsRole(rtc::SSLRole* role) const {
  return false;
}
bool DatagramDtlsAdaptor::SetDtlsRole(rtc::SSLRole role) {
  return false;
}
bool DatagramDtlsAdaptor::GetSrtpCryptoSuite(int* cipher) {
  return false;
}
bool DatagramDtlsAdaptor::GetSslCipherSuite(int* cipher) {
  return false;
}

rtc::scoped_refptr<rtc::RTCCertificate>
DatagramDtlsAdaptor::GetLocalCertificate() const {
  return nullptr;
}

bool DatagramDtlsAdaptor::SetLocalCertificate(
    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
  return false;
}

std::unique_ptr<rtc::SSLCertChain> DatagramDtlsAdaptor::GetRemoteSSLCertChain()
    const {
  return nullptr;
}

bool DatagramDtlsAdaptor::ExportKeyingMaterial(const std::string& label,
                                               const uint8_t* context,
                                               size_t context_len,
                                               bool use_context,
                                               uint8_t* result,
                                               size_t result_len) {
  return false;
}

bool DatagramDtlsAdaptor::SetRemoteFingerprint(const std::string& digest_alg,
                                               const uint8_t* digest,
                                               size_t digest_len) {
  // TODO(sukhanov): We probably should not called with fingerptints in
  // datagram scenario, but we may need to change code up the stack before
  // we can return false or DCHECK.
  return true;
}

bool DatagramDtlsAdaptor::SetSslMaxProtocolVersion(
    rtc::SSLProtocolVersion version) {
  // TODO(sukhanov): We may be able to return false and/or DCHECK that we
  // are not called if datagram transport is used, but we need to change
  // integration before we can do it.
  return true;
}

IceTransportInternal* DatagramDtlsAdaptor::ice_transport() {
  return ice_transport_.get();
}

webrtc::DatagramTransportInterface* DatagramDtlsAdaptor::datagram_transport() {
  return datagram_transport_.get();
}

// Similar implementaton as in p2p/base/dtls_transport.cc.
void DatagramDtlsAdaptor::OnReadyToSend(
    rtc::PacketTransportInternal* transport) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  if (writable()) {
    SignalReadyToSend(this);
  }
}

void DatagramDtlsAdaptor::OnWritableState(
    rtc::PacketTransportInternal* transport) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK(transport == ice_transport_.get());
  RTC_LOG(LS_VERBOSE) << ": ice_transport writable state changed to "
                      << ice_transport_->writable();

  if (kBypassDatagramDtlsTestOnly) {
    // Note: SignalWritableState fired by set_writable.
    set_writable(ice_transport_->writable());
    return;
  }

  switch (dtls_state()) {
    case DTLS_TRANSPORT_NEW:
      break;
    case DTLS_TRANSPORT_CONNECTED:
      // Note: SignalWritableState fired by set_writable.
      // Do we also need set_receiving(ice_transport_->receiving()) here now, in
      // case we lose that signal before "DTLS" connects?
      // DtlsTransport::OnWritableState does not set_receiving in a similar
      // case, so leaving it out for the time being, but it would be good to
      // understand why.
      set_writable(ice_transport_->writable());
      break;
    case DTLS_TRANSPORT_CONNECTING:
      // Do nothing.
      break;
    case DTLS_TRANSPORT_FAILED:
    case DTLS_TRANSPORT_CLOSED:
      // Should not happen. Do nothing.
      break;
  }
}

void DatagramDtlsAdaptor::OnStateChanged(webrtc::MediaTransportState state) {
  // Convert MediaTransportState to DTLS state.
  switch (state) {
    case webrtc::MediaTransportState::kPending:
      set_dtls_state(DTLS_TRANSPORT_CONNECTING);
      break;

    case webrtc::MediaTransportState::kWritable:
      // Since we do not set writable state until datagram transport is
      // connected, we need to call set_writable first.
      set_writable(ice_transport_->writable());
      set_dtls_state(DTLS_TRANSPORT_CONNECTED);
      break;

    case webrtc::MediaTransportState::kClosed:
      set_dtls_state(DTLS_TRANSPORT_CLOSED);
      break;
  }
}

DtlsTransportState DatagramDtlsAdaptor::dtls_state() const {
  return dtls_state_;
}

const std::string& DatagramDtlsAdaptor::transport_name() const {
  return ice_transport_->transport_name();
}

bool DatagramDtlsAdaptor::writable() const {
  // NOTE that even if ice is writable, writable_ maybe false, because we
  // propagte writable only after DTLS is connect (this is consistent with
  // implementation in dtls_transport.cc).
  return writable_;
}

bool DatagramDtlsAdaptor::receiving() const {
  return receiving_;
}

int DatagramDtlsAdaptor::SetOption(rtc::Socket::Option opt, int value) {
  return ice_transport_->SetOption(opt, value);
}

int DatagramDtlsAdaptor::GetError() {
  return ice_transport_->GetError();
}

void DatagramDtlsAdaptor::OnNetworkRouteChanged(
    absl::optional<rtc::NetworkRoute> network_route) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  SignalNetworkRouteChanged(network_route);
}

void DatagramDtlsAdaptor::OnReceivingState(
    rtc::PacketTransportInternal* transport) {
  RTC_DCHECK_RUN_ON(&thread_checker_);
  RTC_DCHECK(transport == ice_transport_.get());
  RTC_LOG(LS_VERBOSE) << "ice_transport receiving state changed to "
                      << ice_transport_->receiving();

  if (kBypassDatagramDtlsTestOnly || dtls_state() == DTLS_TRANSPORT_CONNECTED) {
    // Note: SignalReceivingState fired by set_receiving.
    set_receiving(ice_transport_->receiving());
  }
}

void DatagramDtlsAdaptor::set_receiving(bool receiving) {
  if (receiving_ == receiving) {
    return;
  }
  receiving_ = receiving;
  SignalReceivingState(this);
}

// Similar implementaton as in p2p/base/dtls_transport.cc.
void DatagramDtlsAdaptor::set_writable(bool writable) {
  if (writable_ == writable) {
    return;
  }
  if (event_log_) {
    event_log_->Log(
        absl::make_unique<webrtc::RtcEventDtlsWritableState>(writable));
  }
  RTC_LOG(LS_VERBOSE) << "set_writable to: " << writable;
  writable_ = writable;
  if (writable_) {
    SignalReadyToSend(this);
  }
  SignalWritableState(this);
}

// Similar implementaton as in p2p/base/dtls_transport.cc.
void DatagramDtlsAdaptor::set_dtls_state(DtlsTransportState state) {
  if (dtls_state_ == state) {
    return;
  }
  if (event_log_) {
    event_log_->Log(absl::make_unique<webrtc::RtcEventDtlsTransportState>(
        ConvertDtlsTransportState(state)));
  }
  RTC_LOG(LS_VERBOSE) << "set_dtls_state from:" << dtls_state_ << " to "
                      << state;
  dtls_state_ = state;
  SignalDtlsState(this, state);
}

}  // namespace cricket
<|endoftext|>