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

/* $Id$ */

/// \ingroup macros
/// \file MUONClusterInfo.C
/// \brief Macro to fill AliMUONClusterInfo objects
///
/// \author Philippe Pillot, SUBATECH

#if !defined(__CINT__) || defined(__MAKECINT__)
#include <TStopwatch.h>
#include <TFile.h>
#include <TClonesArray.h>
#include <TTree.h>
#include <TString.h>
#include <Riostream.h>
#include <TGeoManager.h>
#include <TRandom.h>
#include <TROOT.h>

// STEER includes
#include "AliMagFMaps.h"
#include "AliTracker.h"
#include "AliESDEvent.h"
#include "AliESDMuonTrack.h"
#include "AliRecoParam.h"
#include "AliCDBManager.h"
#include "AliGeomManager.h"

// MUON includes
#include "AliMpCDB.h"
#include "AliMpSegmentation.h"
#include "AliMpVSegmentation.h"
#include "AliMpPad.h"
#include "AliMUONCalibrationData.h"
#include "AliMUONVCalibParam.h"
#include "AliMUONPadInfo.h"
#include "AliMUONClusterInfo.h"
#include "AliMUONRecoParam.h"
#include "AliMUONESDInterface.h"
#include "AliMUONRefitter.h"
#include "AliMUONVDigit.h"
#include "AliMUONVDigitStore.h"
#include "AliMUONVCluster.h"
#include "AliMUONVClusterStore.h"
#include "AliMUONTrack.h"
#include "AliMUONVTrackStore.h"
#include "AliMUONTrackParam.h"
#include "AliMUONTrackExtrap.h"
#endif

const Int_t printLevel = 1;

void Prepare();
TTree* GetESDTree(TFile *esdFile);

//-----------------------------------------------------------------------
void MUONClusterInfo(Int_t nevents = -1, const char* esdFileName = "AliESDs.root", const char* outFileName = "clusterInfo.root")
{
  /// refit ESD tracks from ESD clusters to get track parameters at each attached cluster;
  /// fill AliMUONESDClusterInfo object with ESD cluster + corresponding track parameters;
  /// write results in a new root file.

  AliMUONClusterInfo* clusterInfo = new AliMUONClusterInfo();
  AliMUONPadInfo padInfo;
  AliMUONCalibrationData* calibData = 0x0;

  // prepare the refitting
  gRandom->SetSeed(0);
  Prepare();
  AliMUONESDInterface esdInterface;
  AliMUONRefitter refitter;
  refitter.Connect(&esdInterface);

  // open the ESD file and tree and connect the ESD event
  TFile* esdFile = TFile::Open(esdFileName);
  TTree* esdTree = GetESDTree(esdFile);
  AliESDEvent* esd = new AliESDEvent();
  esd->ReadFromTree(esdTree);

  // prepare the output tree
  gROOT->cd();
  TFile* clusterInfoFile = TFile::Open(outFileName, "RECREATE");
  clusterInfoFile->SetCompressionLevel(1);

  TTree* clusterInfoTree = new TTree("clusterInfoTree","clusterInfoTree");
  clusterInfoTree->Branch("clusterInfo", &clusterInfo, 32000, 99);

  // timer start...
  TStopwatch timer;

  // Loop over ESD events
  if (nevents > 0) nevents = TMath::Min(nevents,(Int_t)esdTree->GetEntries());
  else nevents = (Int_t)esdTree->GetEntries();
  for (Int_t iEvent = 0; iEvent < nevents; iEvent++) {

    //----------------------------------------------//
    // -------------- process event --------------- //
    //----------------------------------------------//
    // get the ESD of current event
    esdTree->GetEvent(iEvent);
    if (!esd) {
      Error("CheckESD", "no ESD object found for event %d", iEvent);
      return;
    }
    Int_t nTracks = (Int_t)esd->GetNumberOfMuonTracks();
    if (nTracks < 1) continue;

    // prepare access to calibration data
    if (!calibData) calibData = new AliMUONCalibrationData(esd->GetESDRun()->GetRunNumber());

    // load the current event
    esdInterface.LoadEvent(*esd);

    // get digit store
    AliMUONVDigitStore* digitStore = esdInterface.GetDigits();

    // refit the tracks from clusters
    AliMUONVTrackStore* newTrackStore = refitter.ReconstructFromClusters();

    //----------------------------------------------//
    // ------------- fill cluster info ------------ //
    //----------------------------------------------//
    // loop over the refitted tracks
    TIter nextTrack(newTrackStore->CreateIterator());
    AliMUONTrack* newTrack;
    while ((newTrack = static_cast<AliMUONTrack*>(nextTrack()))) {

      // loop over clusters
      AliMUONTrackParam* trackParam = static_cast<AliMUONTrackParam*>(newTrack->GetTrackParamAtCluster()->First());
      while (trackParam) {
	clusterInfo->Clear("C");

	// fill cluster info
	AliMUONVCluster* cluster = trackParam->GetClusterPtr();
	clusterInfo->SetEventId(iEvent);
	clusterInfo->SetZ(cluster->GetZ());
	clusterInfo->SetClusterId(cluster->GetUniqueID());
	clusterInfo->SetClusterXY(cluster->GetX(), cluster->GetY());
	clusterInfo->SetClusterXYErr(cluster->GetErrX(), cluster->GetErrY());
	clusterInfo->SetClusterChi2(cluster->GetChi2());
	clusterInfo->SetClusterCharge(cluster->GetCharge());

	// fill track info
	clusterInfo->SetTrackId(newTrack->GetUniqueID());
	clusterInfo->SetTrackXY(trackParam->GetNonBendingCoor(), trackParam->GetBendingCoor());
	clusterInfo->SetTrackThetaXY(TMath::ATan(trackParam->GetBendingSlope()), TMath::ATan(trackParam->GetNonBendingSlope()));
	clusterInfo->SetTrackP(trackParam->P());
	const TMatrixD paramCov = trackParam->GetCovariances();
	clusterInfo->SetTrackXYErr(TMath::Sqrt(paramCov(0,0)), TMath::Sqrt(paramCov(2,2)));
	clusterInfo->SetTrackChi2(newTrack->GetNormalizedChi2());
	clusterInfo->SetTrackCharge((Short_t)trackParam->GetCharge());

	// fill pad info if available
	for (Int_t i=0; i<cluster->GetNDigits(); i++) {
	  AliMUONVDigit* digit = digitStore->FindObject(cluster->GetDigitId(i));
	  if (!digit) continue;

	  // pad location
	  const AliMpVSegmentation* seg = AliMpSegmentation::Instance()->
	    GetMpSegmentation(digit->DetElemId(),AliMp::GetCathodType(digit->Cathode()));
	  AliMpPad pad = seg->PadByIndices(AliMpIntPair(digit->PadX(), digit->PadY()));

	  // calibration parameters
	  AliMUONVCalibParam* ped = calibData->Pedestals(digit->DetElemId(), digit->ManuId());
	  AliMUONVCalibParam* gain = calibData->Gains(digit->DetElemId(), digit->ManuId());
	  Int_t manuChannel = digit->ManuChannel();

	  // fill pad info
	  padInfo.SetPadId(digit->GetUniqueID());
	  padInfo.SetPadXY(pad.Position().X(), pad.Position().Y());
	  padInfo.SetPadDimXY(pad.Dimensions().X(), pad.Dimensions().Y());
	  padInfo.SetPadCharge((Double_t)digit->Charge());
	  padInfo.SetPadADC(digit->ADC());
	  padInfo.SetSaturated(digit->IsSaturated());
	  padInfo.SetCalibrated(digit->IsCalibrated());
	  padInfo.SetPedestal(ped->ValueAsFloatFast(manuChannel,0), ped->ValueAsFloatFast(manuChannel,1));
	  padInfo.SetGain(gain->ValueAsFloatFast(manuChannel,0), gain->ValueAsFloatFast(manuChannel,1),
			  gain->ValueAsFloatFast(manuChannel,2), gain->ValueAsFloatFast(manuChannel,3));

	  clusterInfo->AddPad(padInfo);
	}

	// fill cluster info tree
	clusterInfoTree->Fill();

	trackParam = static_cast<AliMUONTrackParam*>(newTrack->GetTrackParamAtCluster()->After(trackParam));
      }

    }

    // free memory
    delete newTrackStore;
  }

  // ...timer stop
  timer.Stop();
  printf("Writing Tree\n");
  // write output tree
  clusterInfoFile->cd();
  clusterInfoTree->Write();
  printf("Deleting Tree\n");
  delete clusterInfoTree;
  printf("Closing File\n");
  clusterInfoFile->Close();

  // free memory
  printf("Deleting calibData\n");
  delete calibData;
  printf("Deleting clusterInfo\n");
  delete clusterInfo;
  printf("Closing esdFile\n");
  esdFile->Close();
  printf("Deleting esd\n");
  delete esd;
  //  delete padInfo;
  cout<<endl<<"time to fill cluster/track info: R:"<<timer.RealTime()<<" C:"<<timer.CpuTime()<<endl<<endl;
}

//-----------------------------------------------------------------------
void Prepare()
{
  /// Set the geometry, the magnetic field, the mapping and the reconstruction parameters

  // Import TGeo geometry (needed by AliMUONTrackExtrap::ExtrapToVertex)
  if (!gGeoManager) {
    AliGeomManager::LoadGeometry("geometry.root");
    if (!gGeoManager) {
      Error("MUONRefit", "getting geometry from file %s failed", "generated/galice.root");
      return;
    }
  }

  // set mag field
  printf("Loading field map...\n");
  AliMagFMaps* field = new AliMagFMaps("Maps","Maps", 1, 1., 10., AliMagFMaps::k5kG);
  AliTracker::SetFieldMap(field, kFALSE);
  AliMUONTrackExtrap::SetField(AliTracker::GetFieldMap());

  // Load mapping
  AliCDBManager* man = AliCDBManager::Instance();
  man->SetDefaultStorage("local://$ALICE_ROOT");
  man->SetRun(0);
  if ( ! AliMpCDB::LoadDDLStore() ) {
    Error("MUONRefit","Could not access mapping from OCDB !");
    exit(-1);
  }

  // set reconstruction parameters
  AliMUONRecoParam *muonRecoParam = AliMUONRecoParam::GetLowFluxParam();
  muonRecoParam->Print("FULL");
  AliRecoParam::Instance()->RegisterRecoParam(muonRecoParam);

}

//-----------------------------------------------------------------------
TTree* GetESDTree(TFile *esdFile)
{
  /// Check that the file is properly open
  /// Return pointer to the ESD Tree

  if (!esdFile || !esdFile->IsOpen()) {
    Error("GetESDTree", "opening ESD file failed");
    exit(-1);
  }

  TTree* tree = (TTree*) esdFile->Get("esdTree");
  if (!tree) {
    Error("GetESDTree", "no ESD tree found");
    exit(-1);
  }

  return tree;

}

<commit_msg>In MUONClusterInfo.C: Do not refit the track since it is already done during  the ESD->MUON track conversion in the ESD interface. (Philippe P.)<commit_after>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

/* $Id$ */

/// \ingroup macros
/// \file MUONClusterInfo.C
/// \brief Macro to fill AliMUONClusterInfo objects
///
/// \author Philippe Pillot, SUBATECH

#if !defined(__CINT__) || defined(__MAKECINT__)
#include <TStopwatch.h>
#include <TFile.h>
#include <TClonesArray.h>
#include <TTree.h>
#include <TString.h>
#include <Riostream.h>
#include <TGeoManager.h>
#include <TRandom.h>
#include <TROOT.h>

// STEER includes
#include "AliMagFMaps.h"
#include "AliTracker.h"
#include "AliESDEvent.h"
#include "AliESDMuonTrack.h"
#include "AliRecoParam.h"
#include "AliCDBManager.h"
#include "AliGeomManager.h"

// MUON includes
#include "AliMpCDB.h"
#include "AliMpSegmentation.h"
#include "AliMpVSegmentation.h"
#include "AliMpPad.h"
#include "AliMUONCalibrationData.h"
#include "AliMUONVCalibParam.h"
#include "AliMUONPadInfo.h"
#include "AliMUONClusterInfo.h"
#include "AliMUONRecoParam.h"
#include "AliMUONESDInterface.h"
#include "AliMUONVDigit.h"
#include "AliMUONVDigitStore.h"
#include "AliMUONVCluster.h"
#include "AliMUONTrack.h"
#include "AliMUONTrackParam.h"
#endif

const Int_t printLevel = 1;

void Prepare();
TTree* GetESDTree(TFile *esdFile);

//-----------------------------------------------------------------------
void MUONClusterInfo(Int_t nevents = -1, const char* esdFileName = "AliESDs.root", const char* outFileName = "clusterInfo.root")
{
  /// load ESD event in the ESDInterface to recover MUON objects;
  /// fill AliMUONESDClusterInfo object with ESD cluster + corresponding track parameters;
  /// write results in a new root file.

  AliMUONClusterInfo* clusterInfo = new AliMUONClusterInfo();
  AliMUONPadInfo padInfo;
  AliMUONCalibrationData* calibData = 0x0;
  AliMUONESDInterface esdInterface;

  // prepare the refitting during ESD->MUON conversion
  Prepare();

  // open the ESD file and tree and connect the ESD event
  TFile* esdFile = TFile::Open(esdFileName);
  TTree* esdTree = GetESDTree(esdFile);
  AliESDEvent* esd = new AliESDEvent();
  esd->ReadFromTree(esdTree);

  // prepare the output tree
  gROOT->cd();
  TFile* clusterInfoFile = TFile::Open(outFileName, "RECREATE");
  clusterInfoFile->SetCompressionLevel(1);

  TTree* clusterInfoTree = new TTree("clusterInfoTree","clusterInfoTree");
  clusterInfoTree->Branch("clusterInfo", &clusterInfo, 32000, 99);

  // timer start...
  TStopwatch timer;

  // Loop over ESD events
  if (nevents > 0) nevents = TMath::Min(nevents,(Int_t)esdTree->GetEntries());
  else nevents = (Int_t)esdTree->GetEntries();
  for (Int_t iEvent = 0; iEvent < nevents; iEvent++) {

    //----------------------------------------------//
    // -------------- process event --------------- //
    //----------------------------------------------//
    // get the ESD of current event
    esdTree->GetEvent(iEvent);
    if (!esd) {
      Error("CheckESD", "no ESD object found for event %d", iEvent);
      return;
    }
    if (esd->GetNumberOfMuonTracks() < 1) continue;

    // prepare access to calibration data
    if (!calibData) calibData = new AliMUONCalibrationData(esd->GetESDRun()->GetRunNumber());

    // load the current event
    esdInterface.LoadEvent(*esd);

    // get digit store
    AliMUONVDigitStore* digitStore = esdInterface.GetDigits();

    //----------------------------------------------//
    // ------------- fill cluster info ------------ //
    //----------------------------------------------//
    // loop over the refitted tracks
    TIter nextTrack(esdInterface.CreateTrackIterator());
    AliMUONTrack* track;
    while ((track = static_cast<AliMUONTrack*>(nextTrack()))) {

      // loop over clusters
      AliMUONTrackParam* trackParam = static_cast<AliMUONTrackParam*>(track->GetTrackParamAtCluster()->First());
      while (trackParam) {
	clusterInfo->Clear("C");

	// fill cluster info
	AliMUONVCluster* cluster = trackParam->GetClusterPtr();
	clusterInfo->SetEventId(iEvent);
	clusterInfo->SetZ(cluster->GetZ());
	clusterInfo->SetClusterId(cluster->GetUniqueID());
	clusterInfo->SetClusterXY(cluster->GetX(), cluster->GetY());
	clusterInfo->SetClusterXYErr(cluster->GetErrX(), cluster->GetErrY());
	clusterInfo->SetClusterChi2(cluster->GetChi2());
	clusterInfo->SetClusterCharge(cluster->GetCharge());

	// fill track info
	clusterInfo->SetTrackId(track->GetUniqueID());
	clusterInfo->SetTrackXY(trackParam->GetNonBendingCoor(), trackParam->GetBendingCoor());
	clusterInfo->SetTrackThetaXY(TMath::ATan(trackParam->GetBendingSlope()), TMath::ATan(trackParam->GetNonBendingSlope()));
	clusterInfo->SetTrackP(trackParam->P());
	const TMatrixD paramCov = trackParam->GetCovariances();
	clusterInfo->SetTrackXYErr(TMath::Sqrt(paramCov(0,0)), TMath::Sqrt(paramCov(2,2)));
	clusterInfo->SetTrackChi2(track->GetNormalizedChi2());
	clusterInfo->SetTrackCharge((Short_t)trackParam->GetCharge());

	// fill pad info if available
	for (Int_t i=0; i<cluster->GetNDigits(); i++) {
	  AliMUONVDigit* digit = digitStore->FindObject(cluster->GetDigitId(i));
	  if (!digit) continue;

	  // pad location
	  const AliMpVSegmentation* seg = AliMpSegmentation::Instance()->
	    GetMpSegmentation(digit->DetElemId(),AliMp::GetCathodType(digit->Cathode()));
	  AliMpPad pad = seg->PadByIndices(AliMpIntPair(digit->PadX(), digit->PadY()));

	  // calibration parameters
	  AliMUONVCalibParam* ped = calibData->Pedestals(digit->DetElemId(), digit->ManuId());
	  AliMUONVCalibParam* gain = calibData->Gains(digit->DetElemId(), digit->ManuId());
	  Int_t manuChannel = digit->ManuChannel();

	  // fill pad info
	  padInfo.SetPadId(digit->GetUniqueID());
	  padInfo.SetPadXY(pad.Position().X(), pad.Position().Y());
	  padInfo.SetPadDimXY(pad.Dimensions().X(), pad.Dimensions().Y());
	  padInfo.SetPadCharge((Double_t)digit->Charge());
	  padInfo.SetPadADC(digit->ADC());
	  padInfo.SetSaturated(digit->IsSaturated());
	  padInfo.SetCalibrated(digit->IsCalibrated());
	  padInfo.SetPedestal(ped->ValueAsFloatFast(manuChannel,0), ped->ValueAsFloatFast(manuChannel,1));
	  padInfo.SetGain(gain->ValueAsFloatFast(manuChannel,0), gain->ValueAsFloatFast(manuChannel,1),
			  gain->ValueAsFloatFast(manuChannel,2), gain->ValueAsFloatFast(manuChannel,3));

	  clusterInfo->AddPad(padInfo);
	}

	// fill cluster info tree
	clusterInfoTree->Fill();

	trackParam = static_cast<AliMUONTrackParam*>(track->GetTrackParamAtCluster()->After(trackParam));
      }

    }

  }

  // ...timer stop
  timer.Stop();
  printf("Writing Tree\n");
  // write output tree
  clusterInfoFile->cd();
  clusterInfoTree->Write();
  printf("Deleting Tree\n");
  delete clusterInfoTree;
  printf("Closing File\n");
  clusterInfoFile->Close();

  // free memory
  printf("Deleting calibData\n");
  delete calibData;
  printf("Deleting clusterInfo\n");
  delete clusterInfo;
  printf("Closing esdFile\n");
  esdFile->Close();
  printf("Deleting esd\n");
  delete esd;
  //  delete padInfo;
  cout<<endl<<"time to fill cluster/track info: R:"<<timer.RealTime()<<" C:"<<timer.CpuTime()<<endl<<endl;
}

//-----------------------------------------------------------------------
void Prepare()
{
  /// Set the geometry, the magnetic field, the mapping and the reconstruction parameters

  gRandom->SetSeed(0);

  // Import TGeo geometry (needed for track extrapolation)
  if (!gGeoManager) {
    AliGeomManager::LoadGeometry("geometry.root");
    if (!gGeoManager) {
      Error("MUONRefit", "getting geometry from file %s failed", "generated/galice.root");
      return;
    }
  }

  // set mag field
  printf("Loading field map...\n");
  AliMagFMaps* field = new AliMagFMaps("Maps","Maps", 1, 1., 10., AliMagFMaps::k5kG);
  AliTracker::SetFieldMap(field, kFALSE);

  // Load mapping
  AliCDBManager* man = AliCDBManager::Instance();
  man->SetDefaultStorage("local://$ALICE_ROOT");
  man->SetRun(0);
  if ( ! AliMpCDB::LoadDDLStore() ) {
    Error("MUONRefit","Could not access mapping from OCDB !");
    exit(-1);
  }

  // eventually set reconstruction parameters for refit (otherwise read from OCDB)
/*  AliMUONRecoParam *muonRecoParam = AliMUONRecoParam::GetLowFluxParam();
  muonRecoParam->Print("FULL");
  AliRecoParam::Instance()->RegisterRecoParam(muonRecoParam);
*/
}

//-----------------------------------------------------------------------
TTree* GetESDTree(TFile *esdFile)
{
  /// Check that the file is properly open
  /// Return pointer to the ESD Tree

  if (!esdFile || !esdFile->IsOpen()) {
    Error("GetESDTree", "opening ESD file failed");
    exit(-1);
  }

  TTree* tree = (TTree*) esdFile->Get("esdTree");
  if (!tree) {
    Error("GetESDTree", "no ESD tree found");
    exit(-1);
  }

  return tree;

}

<|endoftext|>


<commit_before>//
//  http_tls_shared.cc
//

#include "plat_os.h"
#include "plat_net.h"

#include <cassert>
#include <cstring>
#include <iostream>
#include <sstream>
#include <functional>
#include <algorithm>
#include <thread>
#include <mutex>
#include <memory>
#include <string>
#include <vector>
#include <deque>
#include <map>

#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#include "io.h"
#include "hex.h"
#include "url.h"
#include "log.h"
#include "socket.h"
#include "resolver.h"
#include "config_parser.h"
#include "config.h"
#include "pollset.h"
#include "protocol.h"
#include "http_tls_shared.h"

/* http_tls_shared */

bool http_tls_shared::tls_session_debug = true;
std::mutex http_tls_shared::session_mutex;
http_tls_session_map http_tls_shared::session_map;
std::once_flag http_tls_shared::lock_init_flag;
std::vector<std::shared_ptr<std::mutex>> http_tls_shared::locks;

void http_tls_shared::tls_threadid_function(CRYPTO_THREADID *thread_id)
{
    CRYPTO_THREADID_set_pointer(thread_id, (void*)pthread_self());
}

void http_tls_shared::tls_locking_function(int mode, int n, const char *file, int line)
{
    std::call_once(lock_init_flag, [](){
        size_t num_locks = CRYPTO_num_locks();
        locks.resize(CRYPTO_num_locks());
        for (size_t i = 0; i < num_locks; i++) {
            locks[i] = std::make_shared<std::mutex>();
        }
    });

    if (mode & CRYPTO_LOCK) {
        locks[n]->lock();
    } else if (mode & CRYPTO_UNLOCK) {
        locks[n]->unlock();
    }
}

int http_tls_shared::tls_log_errors(const char *str, size_t len, void *bio)
{
    fprintf(stderr, "%s", str);
    return 0;
}

int http_tls_shared::tls_new_session_cb(struct ssl_st *ssl, SSL_SESSION *sess)
{
    unsigned int sess_id_len;
    const unsigned char *sess_id = SSL_SESSION_get_id(sess, &sess_id_len);
    std::string sess_key = hex::encode(sess_id, sess_id_len);
    session_mutex.lock();
    size_t sess_der_len = i2d_SSL_SESSION(sess, NULL);
    unsigned char *sess_der = new unsigned char[sess_der_len];
    if (sess_der) {
        i2d_SSL_SESSION(sess, &sess_der);
        auto si = session_map.insert(http_tls_session_entry(sess_key, std::make_shared<http_tls_session>()));
        http_tls_session &tls_sess = *si.first->second;
        tls_sess.sess_der_len = sess_der_len;
        tls_sess.sess_der = sess_der;
        session_mutex.unlock();
        if (tls_session_debug) {
            log_debug("%s: added session: id=%s", __func__, sess_key.c_str());
        }
        return 0;
    } else {
        if (tls_session_debug) {
            log_debug("%s: failed to add session: id=%s", __func__, sess_key.c_str());
        }
        session_mutex.unlock();
        return -1;
    }
}

void http_tls_shared::tls_remove_session_cb(struct ssl_ctx_st *ctx, SSL_SESSION *sess)
{
    unsigned int sess_id_len;
    const unsigned char *sess_id = SSL_SESSION_get_id(sess, &sess_id_len);
    std::string sess_key = hex::encode(sess_id, sess_id_len);
    session_mutex.lock();
    session_map.erase(sess_key);
    session_mutex.unlock();
    if (tls_session_debug) {
        log_debug("%s: removed session: id=%s", __func__, sess_key.c_str());
    }
}

SSL_SESSION * http_tls_shared::tls_get_session_cb(struct ssl_st *ssl, unsigned char *sess_id, int sess_id_len, int *copy)
{
    *copy = 0;
    std::string sess_key = hex::encode(sess_id, sess_id_len);
    session_mutex.lock();
    auto si = session_map.find(sess_key);
    if (si != session_map.end()) {
        auto sess = si->second;
        session_mutex.unlock();
        // TODO - implement session timeout
        if (tls_session_debug) {
            log_debug("%s: lookup session: cache hit: id=%s", __func__, sess_key.c_str());
        }
        return d2i_SSL_SESSION(NULL, (const uint8_t**)&sess->sess_der, sess->sess_der_len);
    }
    session_mutex.unlock();
    if (tls_session_debug) {
        log_debug("%s: lookup session: cache miss: id=%s", __func__, sess_key.c_str());
    }
    return nullptr;
}

SSL_CTX* http_tls_shared::init_client(protocol *proto, config_ptr cfg)
{
    SSL_library_init();
    SSL_load_error_strings();

    CRYPTO_set_locking_callback(http_tls_shared::tls_locking_function);
    CRYPTO_THREADID_set_callback(http_tls_shared::tls_threadid_function);

    SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
#ifdef SSL_OP_NO_SSLv2
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
#endif
#ifdef SSL_OP_NO_SSLv3
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
#endif
#ifdef SSL_OP_NO_COMPRESSION
    SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
#endif

    if ((!SSL_CTX_load_verify_locations(ctx, cfg->tls_ca_file.c_str(), NULL)) ||
        (!SSL_CTX_set_default_verify_paths(ctx))) {
        ERR_print_errors_cb(http_tls_shared::tls_log_errors, NULL);
        log_fatal_exit("%s failed to load cacert: %s",
                       proto->name.c_str(), cfg->tls_ca_file.c_str());
    } else {
        log_debug("%s loaded cacert: %s",
                  proto->name.c_str(), cfg->tls_ca_file.c_str());
    }
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_set_verify_depth(ctx, 9);

    return ctx;
}

SSL_CTX* http_tls_shared::init_server(protocol *proto, config_ptr cfg)
{
    SSL_library_init();
    SSL_load_error_strings();

    CRYPTO_set_locking_callback(http_tls_shared::tls_locking_function);
    CRYPTO_THREADID_set_callback(http_tls_shared::tls_threadid_function);

    SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
#ifdef SSL_OP_NO_SSLv2
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
#endif
#ifdef SSL_OP_NO_SSLv3
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
#endif
#ifdef SSL_OP_NO_COMPRESSION
    SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
#endif

#if 0
    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_NO_INTERNAL |
                                        SSL_SESS_CACHE_NO_AUTO_CLEAR |
                                        SSL_SESS_CACHE_SERVER);
    SSL_CTX_sess_set_new_cb(ctx, http_tls_shared::tls_new_session_cb);
    SSL_CTX_sess_set_remove_cb(ctx, http_tls_shared::tls_remove_session_cb);
    SSL_CTX_sess_set_get_cb(ctx, http_tls_shared::tls_get_session_cb);
#endif

    if (SSL_CTX_use_certificate_file(ctx,
                                     cfg->tls_cert_file.c_str(), SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_cb(http_tls_shared::tls_log_errors, NULL);
        log_fatal_exit("%s failed to load certificate: %s",
                       proto->name.c_str(), cfg->tls_cert_file.c_str());
    } else {
        log_info("%s loaded cert: %s",
                 proto->name.c_str(), cfg->tls_cert_file.c_str());
    }

    if (SSL_CTX_use_PrivateKey_file(ctx,
                                    cfg->tls_key_file.c_str(), SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_cb(http_tls_shared::tls_log_errors, NULL);
        log_fatal_exit("%s failed to load private key: %s",
                       proto->name.c_str(), cfg->tls_key_file.c_str());
    } else {
        log_info("%s loaded key: %s",
                 proto->name.c_str(), cfg->tls_key_file.c_str());
    }

    return ctx;
}
<commit_msg>Use temporary pointer for calls to i2d_SSL_SESSION<commit_after>//
//  http_tls_shared.cc
//

#include "plat_os.h"
#include "plat_net.h"

#include <cassert>
#include <cstring>
#include <iostream>
#include <sstream>
#include <functional>
#include <algorithm>
#include <thread>
#include <mutex>
#include <memory>
#include <string>
#include <vector>
#include <deque>
#include <map>

#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#include "io.h"
#include "hex.h"
#include "url.h"
#include "log.h"
#include "socket.h"
#include "resolver.h"
#include "config_parser.h"
#include "config.h"
#include "pollset.h"
#include "protocol.h"
#include "http_tls_shared.h"

/* http_tls_shared */

bool http_tls_shared::tls_session_debug = true;
std::mutex http_tls_shared::session_mutex;
http_tls_session_map http_tls_shared::session_map;
std::once_flag http_tls_shared::lock_init_flag;
std::vector<std::shared_ptr<std::mutex>> http_tls_shared::locks;

void http_tls_shared::tls_threadid_function(CRYPTO_THREADID *thread_id)
{
    CRYPTO_THREADID_set_pointer(thread_id, (void*)pthread_self());
}

void http_tls_shared::tls_locking_function(int mode, int n, const char *file, int line)
{
    std::call_once(lock_init_flag, [](){
        size_t num_locks = CRYPTO_num_locks();
        locks.resize(CRYPTO_num_locks());
        for (size_t i = 0; i < num_locks; i++) {
            locks[i] = std::make_shared<std::mutex>();
        }
    });

    if (mode & CRYPTO_LOCK) {
        locks[n]->lock();
    } else if (mode & CRYPTO_UNLOCK) {
        locks[n]->unlock();
    }
}

int http_tls_shared::tls_log_errors(const char *str, size_t len, void *bio)
{
    fprintf(stderr, "%s", str);
    return 0;
}

int http_tls_shared::tls_new_session_cb(struct ssl_st *ssl, SSL_SESSION *sess)
{
    unsigned int sess_id_len;
    const unsigned char *sess_id = SSL_SESSION_get_id(sess, &sess_id_len);
    std::string sess_key = hex::encode(sess_id, sess_id_len);
    session_mutex.lock();
    size_t sess_der_len = i2d_SSL_SESSION(sess, NULL);
    unsigned char *sess_der = new unsigned char[sess_der_len];
    if (sess_der) {
        unsigned char *p = sess_der;
        i2d_SSL_SESSION(sess, &p);
        auto si = session_map.insert(http_tls_session_entry(sess_key, std::make_shared<http_tls_session>()));
        http_tls_session &tls_sess = *si.first->second;
        tls_sess.sess_der_len = sess_der_len;
        tls_sess.sess_der = sess_der;
        session_mutex.unlock();
        if (tls_session_debug) {
            log_debug("%s: added session: id=%s", __func__, sess_key.c_str());
        }
        return 0;
    } else {
        if (tls_session_debug) {
            log_debug("%s: failed to add session: id=%s", __func__, sess_key.c_str());
        }
        session_mutex.unlock();
        return -1;
    }
}

void http_tls_shared::tls_remove_session_cb(struct ssl_ctx_st *ctx, SSL_SESSION *sess)
{
    unsigned int sess_id_len;
    const unsigned char *sess_id = SSL_SESSION_get_id(sess, &sess_id_len);
    std::string sess_key = hex::encode(sess_id, sess_id_len);
    session_mutex.lock();
    session_map.erase(sess_key);
    session_mutex.unlock();
    if (tls_session_debug) {
        log_debug("%s: removed session: id=%s", __func__, sess_key.c_str());
    }
}

SSL_SESSION * http_tls_shared::tls_get_session_cb(struct ssl_st *ssl, unsigned char *sess_id, int sess_id_len, int *copy)
{
    *copy = 0;
    std::string sess_key = hex::encode(sess_id, sess_id_len);
    session_mutex.lock();
    auto si = session_map.find(sess_key);
    if (si != session_map.end()) {
        auto sess = si->second;
        session_mutex.unlock();
        // TODO - implement session timeout
        if (tls_session_debug) {
            log_debug("%s: lookup session: cache hit: id=%s", __func__, sess_key.c_str());
        }
        unsigned const char *p = sess->sess_der;
        return d2i_SSL_SESSION(NULL, &p, sess->sess_der_len);
    }
    session_mutex.unlock();
    if (tls_session_debug) {
        log_debug("%s: lookup session: cache miss: id=%s", __func__, sess_key.c_str());
    }
    return nullptr;
}

SSL_CTX* http_tls_shared::init_client(protocol *proto, config_ptr cfg)
{
    SSL_library_init();
    SSL_load_error_strings();

    CRYPTO_set_locking_callback(http_tls_shared::tls_locking_function);
    CRYPTO_THREADID_set_callback(http_tls_shared::tls_threadid_function);

    SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
#ifdef SSL_OP_NO_SSLv2
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
#endif
#ifdef SSL_OP_NO_SSLv3
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
#endif
#ifdef SSL_OP_NO_COMPRESSION
    SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
#endif

    if ((!SSL_CTX_load_verify_locations(ctx, cfg->tls_ca_file.c_str(), NULL)) ||
        (!SSL_CTX_set_default_verify_paths(ctx))) {
        ERR_print_errors_cb(http_tls_shared::tls_log_errors, NULL);
        log_fatal_exit("%s failed to load cacert: %s",
                       proto->name.c_str(), cfg->tls_ca_file.c_str());
    } else {
        log_debug("%s loaded cacert: %s",
                  proto->name.c_str(), cfg->tls_ca_file.c_str());
    }
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL_CTX_set_verify_depth(ctx, 9);

    return ctx;
}

SSL_CTX* http_tls_shared::init_server(protocol *proto, config_ptr cfg)
{
    SSL_library_init();
    SSL_load_error_strings();

    CRYPTO_set_locking_callback(http_tls_shared::tls_locking_function);
    CRYPTO_THREADID_set_callback(http_tls_shared::tls_threadid_function);

    SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
#ifdef SSL_OP_NO_SSLv2
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
#endif
#ifdef SSL_OP_NO_SSLv3
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
#endif
#ifdef SSL_OP_NO_COMPRESSION
    SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
#endif

#if 0
    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_NO_INTERNAL |
                                        SSL_SESS_CACHE_NO_AUTO_CLEAR |
                                        SSL_SESS_CACHE_SERVER);
    SSL_CTX_sess_set_new_cb(ctx, http_tls_shared::tls_new_session_cb);
    SSL_CTX_sess_set_remove_cb(ctx, http_tls_shared::tls_remove_session_cb);
    SSL_CTX_sess_set_get_cb(ctx, http_tls_shared::tls_get_session_cb);
#endif

    if (SSL_CTX_use_certificate_file(ctx,
                                     cfg->tls_cert_file.c_str(), SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_cb(http_tls_shared::tls_log_errors, NULL);
        log_fatal_exit("%s failed to load certificate: %s",
                       proto->name.c_str(), cfg->tls_cert_file.c_str());
    } else {
        log_info("%s loaded cert: %s",
                 proto->name.c_str(), cfg->tls_cert_file.c_str());
    }

    if (SSL_CTX_use_PrivateKey_file(ctx,
                                    cfg->tls_key_file.c_str(), SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_cb(http_tls_shared::tls_log_errors, NULL);
        log_fatal_exit("%s failed to load private key: %s",
                       proto->name.c_str(), cfg->tls_key_file.c_str());
    } else {
        log_info("%s loaded key: %s",
                 proto->name.c_str(), cfg->tls_key_file.c_str());
    }

    return ctx;
}
<|endoftext|>


<commit_before>/* <x0/connection.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#include <x0/connection.hpp>
#include <x0/listener.hpp>
#include <x0/request.hpp>
#include <x0/response.hpp>
#include <x0/server.hpp>
#include <x0/types.hpp>
#include <x0/sysconfig.h>

#if defined(WITH_SSL)
#	include <gnutls/gnutls.h>
#	include <gnutls/extra.h>
#endif

#include <functional>

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#if 0
#	undef DEBUG
#	define DEBUG(x...) /*!*/
#endif

namespace x0 {

connection::connection(x0::listener& lst) :
	secure(false),
	listener_(lst),
	server_(lst.server()),
//	socket_(), // initialized in constructor body
	remote_ip_(),
	remote_port_(0),
	buffer_(8192),
	request_(new request(*this)),
	request_parser_(),
	response_(0),
	state_(invalid),
	watcher_(server_.loop())
#if defined(WITH_CONNECTION_TIMEOUTS)
	, timer_(server_.loop())
#endif
#if !defined(NDEBUG)
	, ctime_(ev_now(server_.loop()))
#endif
{
	watcher_.set<connection, &connection::io_callback>(this);

#if defined(WITH_CONNECTION_TIMEOUTS)
	timer_.set<connection, &connection::timeout_callback>(this);
#endif

}

connection::~connection()
{
	delete request_;
	delete response_;
	request_ = 0;
	response_ = 0;

	DEBUG("~connection(%p)", this);

	try
	{
		server_.connection_close(this); // we cannot pass a shared pointer here as use_count is already zero and it would just lead into an exception though
	}
	catch (...)
	{
		DEBUG("~connection(%p): unexpected exception", this);
	}

#if defined(WITH_SSL)
	if (ssl_enabled())
		gnutls_deinit(ssl_session_);
#endif

	if (socket_ != -1)
	{
		::close(socket_);
#if !defined(NDEBUG)
		socket_ = -1;
#endif
	}
}

void connection::io_callback(ev::io& w, int revents)
{
	DEBUG("connection(%p).io_callback(revents=0x%04X)", this, revents);

#if defined(WITH_CONNECTION_TIMEOUTS)
	timer_.stop();
#endif

	if (revents & ev::READ)
		handle_read();

	if (revents & ev::WRITE)
		handle_write();
}

#if defined(WITH_CONNECTION_TIMEOUTS)
void connection::timeout_callback(ev::timer& watcher, int revents)
{
	handle_timeout();
}

void connection::handle_timeout()
{
	DEBUG("connection(%p): timed out", this);

	watcher_.stop();
//	ev_unloop(loop(), EVUNLOOP_ONE);

	delete this;
}
#endif

#if defined(WITH_SSL)
void connection::ssl_initialize()
{
	gnutls_init(&ssl_session_, GNUTLS_SERVER);
	gnutls_priority_set(ssl_session_, listener_.priority_cache_);
	gnutls_credentials_set(ssl_session_, GNUTLS_CRD_CERTIFICATE, listener_.x509_cred_);

	gnutls_certificate_server_set_request(ssl_session_, GNUTLS_CERT_REQUEST);
	gnutls_dh_set_prime_bits(ssl_session_, 1024);

	gnutls_session_enable_compatibility_mode(ssl_session_);

	gnutls_transport_set_ptr(ssl_session_, (gnutls_transport_ptr_t)handle());

	listener_.ssl_db().bind(ssl_session_);
}

bool connection::ssl_enabled() const
{
	return listener_.secure();
}
#endif

/** start first async operation for this connection.
 *
 * This is done by simply registering the underlying socket to the the I/O service
 * to watch for available input.
 * \see stop()
 * :
 */
void connection::start()
{
	socklen_t slen = sizeof(saddr_);
	memset(&saddr_, 0, slen);

	socket_ = ::accept(listener_.handle(), reinterpret_cast<sockaddr *>(&saddr_), &slen);

	if (socket_ < 0)
	{
		server_.log(severity::error, "Could not accept client socket: %s", strerror(errno));
		delete this;
		return;
	}

	DEBUG("connection(%p).start() fd=%d", this, socket_);

	if (fcntl(socket_, F_SETFL, O_NONBLOCK) < 0)
		printf("could not set server socket into non-blocking mode: %s\n", strerror(errno));

#if defined(TCP_CORK)
	{
		int flag = 1;
		setsockopt(socket_, IPPROTO_TCP, TCP_CORK, &flag, sizeof(flag));
	}
#endif

#if 0 // defined(TCP_NODELAY)
	{
		int flag = 1;
		setsockopt(socket_, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
	}
#endif

	server_.connection_open(this);

	if (socket_ < 0) // hook triggered delayed delete via connection::close()
	{
		delete this;
		return;
	}

#if defined(WITH_SSL)
	if (ssl_enabled())
	{
		handshaking_ = true;
		ssl_initialize();
		ssl_handshake();
		return;
	}
	else
		handshaking_ = false;
#endif

#if defined(TCP_DEFER_ACCEPT)
	// it is ensured, that we have data pending, so directly start reading
	handle_read();
#else
	// client connected, but we do not yet know if we have data pending
	start_read();
#endif
}

#if defined(WITH_SSL)
bool connection::ssl_handshake()
{
	int rv = gnutls_handshake(ssl_session_);
	if (rv == GNUTLS_E_SUCCESS)
	{
		// handshake either completed or failed
		handshaking_ = false;
		DEBUG("SSL handshake time: %.4f", ev_now(server_.loop()) - ctime_);
		start_read();
		return true;
	}

	if (rv != GNUTLS_E_AGAIN && rv != GNUTLS_E_INTERRUPTED)
	{
		DEBUG("SSL handshake failed (%d): %s", rv, gnutls_strerror(rv));

		delete this;
		return false;
	}

	DEBUG("SSL handshake incomplete: (%d)", gnutls_record_get_direction(ssl_session_));
	switch (gnutls_record_get_direction(ssl_session_))
	{
		case 0: // read
			start_read();
			break;
		case 1: // write
			start_write();
			break;
		default:
			break;
	}
	return false;
}
#endif

/** Resumes async operations.
 *
 * This method is being invoked on a keep-alive connection to parse further requests.
 * \see start()
 */
void connection::resume()
{
	DEBUG("connection(%p).resume()", this);

	delete request_;
	request_ = 0;

	delete response_;
	response_ = 0;

	std::size_t offset = request_parser_.next_offset();
	request_parser_.reset();
	request_ = new request(*this);

	if (offset < buffer_.size()) // HTTP pipelining
	{
		DEBUG("resume(): pipelined %ld bytes", buffer_.size() - offset);
		parse_request(offset, buffer_.size() - offset);
	}
	else
	{
		DEBUG("resume(): start read");
		buffer_.clear();
		start_read();
	}
}

void connection::start_read()
{
	switch (state_)
	{
		case invalid:
			DEBUG("start_read(): start watching");
			state_ = reading;
			watcher_.set(socket_, ev::READ);
			watcher_.start();
			break;
		case reading:
			DEBUG("start_read(): continue reading (fd=%d)", socket_);
			break;
		case writing:
			state_ = reading;
			DEBUG("start_read(): continue reading (fd=%d) (was ev::WRITE)", socket_);
			watcher_.set(socket_, ev::READ);
			break;
	}

#if defined(WITH_CONNECTION_TIMEOUTS)
	if (server_.max_read_idle() > 0)
		timer_.start(server_.max_read_idle(), 0.0);
#endif
}

void connection::start_write()
{
	if (state_ != writing)
	{
		DEBUG("start_write(): start watching");
		state_ = writing;
		watcher_.set(socket_, ev::WRITE);
	}
	else
		DEBUG("start_write(): continue watching");

#if defined(WITH_CONNECTION_TIMEOUTS)
	if (server_.max_write_idle() > 0)
		timer_.start(server_.max_write_idle(), 0.0);
#endif
}

void connection::stop_write()
{
	DEBUG("stop_write()");
	start_read();
}

void connection::handle_write()
{
	DEBUG("connection(%p).handle_write()", this);

#if defined(WITH_SSL)
	if (handshaking_)
		return (void) ssl_handshake();

//	if (ssl_enabled())
//		rv = gnutls_write(ssl_session_, buffer_.capacity() - buffer_.size());
//	else if (write_some)
//		write_some(this);
#else
#endif

#if 0
	buffer write_buffer_;
	int write_offset_ = 0;

	int rv = ::write(socket_, write_buffer_.begin() + write_offset_, write_buffer_.size() - write_offset_);

	if (rv < 0)
		; // error
	else
	{
		write_offset_ += rv;
		start_write();
	}
#else
	if (write_some)
		write_some(this);
#endif
}

/**
 * This method gets invoked when there is data in our connection ready to read.
 *
 * We assume, that we are in request-parsing state.
 */
void connection::handle_read()
{
	DEBUG("connection(%p).handle_read()", this);

#if defined(WITH_SSL)
	if (handshaking_)
		return (void) ssl_handshake();
#endif

	std::size_t lower_bound = buffer_.size();
	int rv;

#if defined(WITH_SSL)
	if (ssl_enabled())
		rv = gnutls_read(ssl_session_, buffer_.end(), buffer_.capacity() - buffer_.size());
	else
		rv = ::read(socket_, buffer_.end(), buffer_.capacity() - buffer_.size());
#else
	rv = ::read(socket_, buffer_.end(), buffer_.capacity() - buffer_.size());
#endif

	if (rv < 0) // error
	{
		if (errno == EAGAIN || errno == EINTR)
		{
			start_read();
			ev_unloop(server_.loop(), EVUNLOOP_ONE);
		}
		else
		{
			DEBUG("connection::handle_read(): %s", strerror(errno));
			delete this;
		}
	}
	else if (rv == 0) // EOF
	{
		DEBUG("connection::handle_read(): (EOF)");
		delete this;
	}
	else
	{
		DEBUG("connection::handle_read(): read %d bytes", rv);

		buffer_.resize(lower_bound + rv);
		parse_request(lower_bound, rv);
	}
}

/** closes this connection, possibly deleting this object (or propagating delayed delete).
 */
void connection::close()
{
	switch (state_)
	{
		case invalid:
			// we've got invoked from within connection_open()-hook (within the connection::start()-call)
			::close(socket_);
			socket_ = -1;
			break;
		case reading:
		case writing:
			delete this;
			break;
	}
}

/** parses (partial) request from buffer's given \p offset of \p count bytes.
 */
void connection::parse_request(std::size_t offset, std::size_t count)
{
	// parse request (partial)
	boost::tribool result = request_parser_.parse(*request_, buffer_.ref(offset, count));

	if (result) // request fully parsed
	{
		if (response *response_ = new response(this, request_))
		{
			try
			{
//				state_ = writing;
				server_.handle_request(response_->request(), response_);
			}
			catch (response::code_type reply)
			{
//				fprintf(stderr, "response::code exception caught (%d %s)\n", reply, response::status_cstr(reply));
//				fflush(stderr);
				response_->status = reply;
				response_->finish();
			}
		}
	}
	else if (!result) // received an invalid request
	{
		// -> send stock response: BAD_REQUEST
		(new response(this, request_, response::bad_request))->finish();
	}
	else // result indeterminate: request still incomplete
	{
		// -> continue reading for request
		start_read();
	}
}

std::string connection::remote_ip() const
{
	if (remote_ip_.empty())
	{
		char buf[128];

		if (inet_ntop(AF_INET6, &saddr_.sin6_addr, buf, sizeof(buf)))
			remote_ip_ = buf;
	}

	return remote_ip_;
}

int connection::remote_port() const
{
	if (!remote_port_)
	{
		remote_port_ = ntohs(saddr_.sin6_port);
	}

	return remote_port_;
}

std::string connection::local_ip() const
{
	return listener_.address();
}

int connection::local_port() const
{
	return listener_.port();
}

} // namespace x0
<commit_msg>core: disable TCP_CORK for a while<commit_after>/* <x0/connection.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#include <x0/connection.hpp>
#include <x0/listener.hpp>
#include <x0/request.hpp>
#include <x0/response.hpp>
#include <x0/server.hpp>
#include <x0/types.hpp>
#include <x0/sysconfig.h>

#if defined(WITH_SSL)
#	include <gnutls/gnutls.h>
#	include <gnutls/extra.h>
#endif

#include <functional>

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#if 0
#	undef DEBUG
#	define DEBUG(x...) /*!*/
#endif

namespace x0 {

connection::connection(x0::listener& lst) :
	secure(false),
	listener_(lst),
	server_(lst.server()),
//	socket_(), // initialized in constructor body
	remote_ip_(),
	remote_port_(0),
	buffer_(8192),
	request_(new request(*this)),
	request_parser_(),
	response_(0),
	state_(invalid),
	watcher_(server_.loop())
#if defined(WITH_CONNECTION_TIMEOUTS)
	, timer_(server_.loop())
#endif
#if !defined(NDEBUG)
	, ctime_(ev_now(server_.loop()))
#endif
{
	watcher_.set<connection, &connection::io_callback>(this);

#if defined(WITH_CONNECTION_TIMEOUTS)
	timer_.set<connection, &connection::timeout_callback>(this);
#endif

}

connection::~connection()
{
	delete request_;
	delete response_;
	request_ = 0;
	response_ = 0;

	DEBUG("~connection(%p)", this);

	try
	{
		server_.connection_close(this); // we cannot pass a shared pointer here as use_count is already zero and it would just lead into an exception though
	}
	catch (...)
	{
		DEBUG("~connection(%p): unexpected exception", this);
	}

#if defined(WITH_SSL)
	if (ssl_enabled())
		gnutls_deinit(ssl_session_);
#endif

	if (socket_ != -1)
	{
		::close(socket_);
#if !defined(NDEBUG)
		socket_ = -1;
#endif
	}
}

void connection::io_callback(ev::io& w, int revents)
{
	DEBUG("connection(%p).io_callback(revents=0x%04X)", this, revents);

#if defined(WITH_CONNECTION_TIMEOUTS)
	timer_.stop();
#endif

	if (revents & ev::READ)
		handle_read();

	if (revents & ev::WRITE)
		handle_write();
}

#if defined(WITH_CONNECTION_TIMEOUTS)
void connection::timeout_callback(ev::timer& watcher, int revents)
{
	handle_timeout();
}

void connection::handle_timeout()
{
	DEBUG("connection(%p): timed out", this);

	watcher_.stop();
//	ev_unloop(loop(), EVUNLOOP_ONE);

	delete this;
}
#endif

#if defined(WITH_SSL)
void connection::ssl_initialize()
{
	gnutls_init(&ssl_session_, GNUTLS_SERVER);
	gnutls_priority_set(ssl_session_, listener_.priority_cache_);
	gnutls_credentials_set(ssl_session_, GNUTLS_CRD_CERTIFICATE, listener_.x509_cred_);

	gnutls_certificate_server_set_request(ssl_session_, GNUTLS_CERT_REQUEST);
	gnutls_dh_set_prime_bits(ssl_session_, 1024);

	gnutls_session_enable_compatibility_mode(ssl_session_);

	gnutls_transport_set_ptr(ssl_session_, (gnutls_transport_ptr_t)handle());

	listener_.ssl_db().bind(ssl_session_);
}

bool connection::ssl_enabled() const
{
	return listener_.secure();
}
#endif

/** start first async operation for this connection.
 *
 * This is done by simply registering the underlying socket to the the I/O service
 * to watch for available input.
 * \see stop()
 * :
 */
void connection::start()
{
	socklen_t slen = sizeof(saddr_);
	memset(&saddr_, 0, slen);

	socket_ = ::accept(listener_.handle(), reinterpret_cast<sockaddr *>(&saddr_), &slen);

	if (socket_ < 0)
	{
		server_.log(severity::error, "Could not accept client socket: %s", strerror(errno));
		delete this;
		return;
	}

	DEBUG("connection(%p).start() fd=%d", this, socket_);

	if (fcntl(socket_, F_SETFL, O_NONBLOCK) < 0)
		printf("could not set server socket into non-blocking mode: %s\n", strerror(errno));

#if 0 // defined(TCP_CORK)
	{
		int flag = 1;
		setsockopt(socket_, IPPROTO_TCP, TCP_CORK, &flag, sizeof(flag));
	}
#endif

#if 0 // defined(TCP_NODELAY)
	{
		int flag = 1;
		setsockopt(socket_, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
	}
#endif

	server_.connection_open(this);

	if (socket_ < 0) // hook triggered delayed delete via connection::close()
	{
		delete this;
		return;
	}

#if defined(WITH_SSL)
	if (ssl_enabled())
	{
		handshaking_ = true;
		ssl_initialize();
		ssl_handshake();
		return;
	}
	else
		handshaking_ = false;
#endif

#if defined(TCP_DEFER_ACCEPT)
	// it is ensured, that we have data pending, so directly start reading
	handle_read();
#else
	// client connected, but we do not yet know if we have data pending
	start_read();
#endif
}

#if defined(WITH_SSL)
bool connection::ssl_handshake()
{
	int rv = gnutls_handshake(ssl_session_);
	if (rv == GNUTLS_E_SUCCESS)
	{
		// handshake either completed or failed
		handshaking_ = false;
		DEBUG("SSL handshake time: %.4f", ev_now(server_.loop()) - ctime_);
		start_read();
		return true;
	}

	if (rv != GNUTLS_E_AGAIN && rv != GNUTLS_E_INTERRUPTED)
	{
		DEBUG("SSL handshake failed (%d): %s", rv, gnutls_strerror(rv));

		delete this;
		return false;
	}

	DEBUG("SSL handshake incomplete: (%d)", gnutls_record_get_direction(ssl_session_));
	switch (gnutls_record_get_direction(ssl_session_))
	{
		case 0: // read
			start_read();
			break;
		case 1: // write
			start_write();
			break;
		default:
			break;
	}
	return false;
}
#endif

/** Resumes async operations.
 *
 * This method is being invoked on a keep-alive connection to parse further requests.
 * \see start()
 */
void connection::resume()
{
	DEBUG("connection(%p).resume()", this);

	delete request_;
	request_ = 0;

	delete response_;
	response_ = 0;

	std::size_t offset = request_parser_.next_offset();
	request_parser_.reset();
	request_ = new request(*this);

	if (offset < buffer_.size()) // HTTP pipelining
	{
		DEBUG("resume(): pipelined %ld bytes", buffer_.size() - offset);
		parse_request(offset, buffer_.size() - offset);
	}
	else
	{
		DEBUG("resume(): start read");
		buffer_.clear();
		start_read();
	}
}

void connection::start_read()
{
	switch (state_)
	{
		case invalid:
			DEBUG("start_read(): start watching");
			state_ = reading;
			watcher_.set(socket_, ev::READ);
			watcher_.start();
			break;
		case reading:
			DEBUG("start_read(): continue reading (fd=%d)", socket_);
			break;
		case writing:
			state_ = reading;
			DEBUG("start_read(): continue reading (fd=%d) (was ev::WRITE)", socket_);
			watcher_.set(socket_, ev::READ);
			break;
	}

#if defined(WITH_CONNECTION_TIMEOUTS)
	if (server_.max_read_idle() > 0)
		timer_.start(server_.max_read_idle(), 0.0);
#endif
}

void connection::start_write()
{
	if (state_ != writing)
	{
		DEBUG("start_write(): start watching");
		state_ = writing;
		watcher_.set(socket_, ev::WRITE);
	}
	else
		DEBUG("start_write(): continue watching");

#if defined(WITH_CONNECTION_TIMEOUTS)
	if (server_.max_write_idle() > 0)
		timer_.start(server_.max_write_idle(), 0.0);
#endif
}

void connection::stop_write()
{
	DEBUG("stop_write()");
	start_read();
}

void connection::handle_write()
{
	DEBUG("connection(%p).handle_write()", this);

#if defined(WITH_SSL)
	if (handshaking_)
		return (void) ssl_handshake();

//	if (ssl_enabled())
//		rv = gnutls_write(ssl_session_, buffer_.capacity() - buffer_.size());
//	else if (write_some)
//		write_some(this);
#else
#endif

#if 0
	buffer write_buffer_;
	int write_offset_ = 0;

	int rv = ::write(socket_, write_buffer_.begin() + write_offset_, write_buffer_.size() - write_offset_);

	if (rv < 0)
		; // error
	else
	{
		write_offset_ += rv;
		start_write();
	}
#else
	if (write_some)
		write_some(this);
#endif
}

/**
 * This method gets invoked when there is data in our connection ready to read.
 *
 * We assume, that we are in request-parsing state.
 */
void connection::handle_read()
{
	DEBUG("connection(%p).handle_read()", this);

#if defined(WITH_SSL)
	if (handshaking_)
		return (void) ssl_handshake();
#endif

	std::size_t lower_bound = buffer_.size();
	int rv;

#if defined(WITH_SSL)
	if (ssl_enabled())
		rv = gnutls_read(ssl_session_, buffer_.end(), buffer_.capacity() - buffer_.size());
	else
		rv = ::read(socket_, buffer_.end(), buffer_.capacity() - buffer_.size());
#else
	rv = ::read(socket_, buffer_.end(), buffer_.capacity() - buffer_.size());
#endif

	if (rv < 0) // error
	{
		if (errno == EAGAIN || errno == EINTR)
		{
			start_read();
			ev_unloop(server_.loop(), EVUNLOOP_ONE);
		}
		else
		{
			DEBUG("connection::handle_read(): %s", strerror(errno));
			delete this;
		}
	}
	else if (rv == 0) // EOF
	{
		DEBUG("connection::handle_read(): (EOF)");
		delete this;
	}
	else
	{
		DEBUG("connection::handle_read(): read %d bytes", rv);

		buffer_.resize(lower_bound + rv);
		parse_request(lower_bound, rv);
	}
}

/** closes this connection, possibly deleting this object (or propagating delayed delete).
 */
void connection::close()
{
	switch (state_)
	{
		case invalid:
			// we've got invoked from within connection_open()-hook (within the connection::start()-call)
			::close(socket_);
			socket_ = -1;
			break;
		case reading:
		case writing:
			delete this;
			break;
	}
}

/** parses (partial) request from buffer's given \p offset of \p count bytes.
 */
void connection::parse_request(std::size_t offset, std::size_t count)
{
	// parse request (partial)
	boost::tribool result = request_parser_.parse(*request_, buffer_.ref(offset, count));

	if (result) // request fully parsed
	{
		if (response *response_ = new response(this, request_))
		{
			try
			{
//				state_ = writing;
				server_.handle_request(response_->request(), response_);
			}
			catch (response::code_type reply)
			{
//				fprintf(stderr, "response::code exception caught (%d %s)\n", reply, response::status_cstr(reply));
//				fflush(stderr);
				response_->status = reply;
				response_->finish();
			}
		}
	}
	else if (!result) // received an invalid request
	{
		// -> send stock response: BAD_REQUEST
		(new response(this, request_, response::bad_request))->finish();
	}
	else // result indeterminate: request still incomplete
	{
		// -> continue reading for request
		start_read();
	}
}

std::string connection::remote_ip() const
{
	if (remote_ip_.empty())
	{
		char buf[128];

		if (inet_ntop(AF_INET6, &saddr_.sin6_addr, buf, sizeof(buf)))
			remote_ip_ = buf;
	}

	return remote_ip_;
}

int connection::remote_port() const
{
	if (!remote_port_)
	{
		remote_port_ = ntohs(saddr_.sin6_port);
	}

	return remote_port_;
}

std::string connection::local_ip() const
{
	return listener_.address();
}

int connection::local_port() const
{
	return listener_.port();
}

} // namespace x0
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>

#include "SignalRoutine.h"

#ifdef NO_TIME_CMD
static struct timeval tpstart, tpend;
#endif

bool start = false;

extern "C" {

    void OnInit(unsigned svsNum) {
        printf("OnInit-Record\n");

#ifdef NO_TIME_CMD
        gettimeofday(&tpstart, NULL);
#endif
    }

    void OnExit() {
        start = false;

#ifdef NO_TIME_CMD
        gettimeofday(&tpend, NULL);
        double timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
        timeuse /= 1000;
        printf("processor time is %lf ms\n", timeuse);
#endif
        printf("OnExit-Record\n");
    }

    void OnAddressInit(void* value, size_t size, size_t n) {
        if (!start) {
            return;
        }

    }

    void OnLoad(int svId, long address, long value, int debug) {
        if (!start) {
            return;
        }
    }

    unsigned OnPreStore(int svId, int debug) {
        if (!start) {
            return 0;
        }

        return 0;
    }

    void OnStore(int svId, unsigned version, long address, long value, int debug) {
        if (!start) {
            return;
        }
    }

    void OnLock(pthread_mutex_t* mutex_ptr) {
        if (!start) {
            return;
        }
    }

    void OnWait(pthread_cond_t* cond_ptr, pthread_mutex_t* mutex_ptr) {
        if (!start) {
            return;
        }
    }

    void OnPreMutexInit(bool race) {
        if (start && race) {
        }
    }

    void OnMutexInit(pthread_mutex_t* mutex_ptr, bool race) {
    }

    void OnPreFork(bool race) {
        if (!start) {
            start = true;
        }
    }

    void OnFork(pthread_t* forked_tid_ptr, bool race) {
        if (!start) {
            return;
        }
    }

}

/* ************************************************************************
 * Signal Process
 * ************************************************************************/

void sigroutine(int dunno) {
    printSigInformation(dunno);

    OnExit();
    exit(dunno);
}
<commit_msg>init canary replayer support<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>

extern "C" {

    void OnInit(unsigned svsNum) {
        printf("OnInit-Record (canary replayer)\n");
    }

    void OnExit() {
        printf("OnExit-Record (canary replayer)\n");
    }

    void OnAddressInit(void* value, size_t size, size_t n) {
    }

    void OnLoad(int svId, long address, long value, int debug) {
    }

    unsigned OnPreStore(int svId, int debug) {
        return 0;
    }

    void OnStore(int svId, unsigned version, long address, long value, int debug) {
    }

    void OnLock(pthread_mutex_t* mutex_ptr) {
    }

    void OnWait(pthread_cond_t* cond_ptr, pthread_mutex_t* mutex_ptr) {
    }

    void OnPreMutexInit(bool race) {
    }

    void OnMutexInit(pthread_mutex_t* mutex_ptr, bool race) {
    }

    void OnPreFork(bool race) {
    }

    void OnFork(pthread_t* forked_tid_ptr, bool race) {
    }

    void OnJoin(pthread_t tid, bool race) {
    }

    void OnLocal(long value, int id) {
    }

}
<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQBaseDataModel.cpp,v $
//   $Revision: 1.9 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2011/09/30 16:39:43 $
// End CVS Header

// Copyright (C) 2011 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "copasi.h"
#include "CQBaseDataModel.h"

CQBaseDataModel::CQBaseDataModel(QObject *parent)
    : QAbstractTableModel(parent)

{}

Qt::ItemFlags CQBaseDataModel::flags(const QModelIndex &index) const
{
  if (!index.isValid())
    return Qt::ItemIsEnabled;

  if (index.column() == COL_ROW_NUMBER)
    return QAbstractItemModel::flags(index);
  else
    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

bool CQBaseDataModel::insertRow()
{
  return insertRows(rowCount() - 1, 1);
}

bool CQBaseDataModel::removeRow(int position)
{
  if (0 <= position && position < rowCount() && !isDefaultRow(index(position, 0)))
    return removeRows(position, 1);
  else
    return false;
}

bool CQBaseDataModel::clear()
{
  return removeRows(0, rowCount());
}

bool CQBaseDataModel::isDefaultRow(const QModelIndex& i) const
{
  //Index has to be from this model and should be valid.
  if ((i.model() != this) ||
      !i.isValid())
    {
      return false;
    }

  return (i.row() == rowCount() - 1);
}

QString CQBaseDataModel::createNewName(const QString name, const int nameCol)
{
  QString nname = name;
  unsigned C_INT32 j, jmax = rowCount();

  for (unsigned C_INT32 i = 1;; ++i)
    {
      nname = name + "_" + QString::number(i);

      for (j = 0; j < jmax; ++j)
        if (index(j, nameCol).data() == nname) break;

      if (j == jmax) break;
    }

  return nname;
}
<commit_msg>Fixed Bug 1756. clear(), which is called when pressing Delete All must not remove the last row which is the default row.<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQBaseDataModel.cpp,v $
//   $Revision: 1.10 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2012/03/19 12:20:16 $
// End CVS Header

// Copyright (C) 2012 - 2011 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "copasi.h"
#include "CQBaseDataModel.h"

CQBaseDataModel::CQBaseDataModel(QObject *parent)
    : QAbstractTableModel(parent)

{}

Qt::ItemFlags CQBaseDataModel::flags(const QModelIndex &index) const
{
  if (!index.isValid())
    return Qt::ItemIsEnabled;

  if (index.column() == COL_ROW_NUMBER)
    return QAbstractItemModel::flags(index);
  else
    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

bool CQBaseDataModel::insertRow()
{
  return insertRows(rowCount() - 1, 1);
}

bool CQBaseDataModel::removeRow(int position)
{
  if (0 <= position && position < rowCount() && !isDefaultRow(index(position, 0)))
    return removeRows(position, 1);
  else
    return false;
}

bool CQBaseDataModel::clear()
{
  return removeRows(0, rowCount() - 1);
}

bool CQBaseDataModel::isDefaultRow(const QModelIndex& i) const
{
  //Index has to be from this model and should be valid.
  if ((i.model() != this) ||
      !i.isValid())
    {
      return false;
    }

  return (i.row() == rowCount() - 1);
}

QString CQBaseDataModel::createNewName(const QString name, const int nameCol)
{
  QString nname = name;
  unsigned C_INT32 j, jmax = rowCount();

  for (unsigned C_INT32 i = 1;; ++i)
    {
      nname = name + "_" + QString::number(i);

      for (j = 0; j < jmax; ++j)
        if (index(j, nameCol).data() == nname) break;

      if (j == jmax) break;
    }

  return nname;
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include "robot_utils/ros_thread_image.h"

class ROSImageObject: public ROSThreadImage
{
public:
    explicit ROSImageObject(std::string namenew): ROSThreadImage(namenew) {}

    void InternalThreadEntry()
    {
        std::cout << "test" << std::endl;
    }
};

TEST(rosimagetest, testsetname)
{
   ROSImageObject rt("test");
   rt.joinInternalThread();

   rt.setName("newtestname");
   EXPECT_EQ("newtestname", rt.getName());
   EXPECT_FALSE("test" == rt.getName());
}

// Run all the tests that were declared with TEST()
int main(int argc, char **argv)
{
    ros::init(argc, argv, "ros_thread_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>Added rostest for ros_thread_image<commit_after>#include <gtest/gtest.h>
#include "robot_utils/ros_thread_image.h"
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

static const std::string OPENCV_WINDOW = "Image window";

using namespace cv;
using namespace std;

class ROSThreadImageTester
{
  ros::NodeHandle nh_;
  image_transport::ImageTransport it_;
  image_transport::Publisher image_pub_;
  std::string name;

public:
  explicit ROSThreadImageTester(std::string _name)
    : it_(nh_), name(_name)
  {
   image_pub_ = it_.advertise("/"+name+"/image", 1);
  }

  ~ROSThreadImageTester() {}

  void sendTestImage()
  {
    cv::Mat img(200, 200, CV_8UC3, cv::Scalar(0,0,0));
    cv::waitKey(30);
    cv::circle(img, cv::Point(100, 100), 20, CV_RGB(255,0,0), -1);
    sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", img).toImageMsg();
    image_pub_.publish(msg);
  }
};

class ROSImageInstance: public ROSThreadImage
{
private:
  int xcoord;
  int ycoord;

public:
    explicit ROSImageInstance(std::string namenew): ROSThreadImage(namenew), xcoord(-1), ycoord(-1) {}

    void InternalThreadEntry()
    {
        while(ros::ok())
        {
            cv::Mat img_in;

            if (!_img_empty)
            {
                ROS_INFO("Processing image");
                pthread_mutex_lock(&_mutex_img);
                img_in=_curr_img;
                pthread_mutex_unlock(&_mutex_img);

                cv::Mat gray;
                cv::cvtColor(img_in, gray, CV_BGR2GRAY);
                std::vector<vector<Point>> contours;
                findContours(gray, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, Point(0,0));

                //Finds the moments
                vector<Moments> mu(contours.size() );
                for(unsigned int i = 0; i < contours.size(); i++ )
                {
                    mu[i] = moments(contours[i], false );
                }

                //Finds the Centroid
                vector<Point2f> mc( contours.size());
                for( unsigned int i = 0; i < contours.size(); i++ )
                {
                    mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 );
                    xcoord = mu[i].m10/mu[i].m00;
                    ycoord = mu[i].m01/mu[i].m00;
                }

                break;
            }
            r.sleep();
        }
      }
    int getx() {return xcoord;}
    int gety() {return ycoord;}

    void printx() {std::cout<<"The calculated x-coord of the centroid of the cirlce is " << xcoord<< " [Expected value: 100]"<<std::endl;}
    void printy() {std::cout<<"The calculated y-coord of the centroid of the circle is " << ycoord<< " [Expected value: 100]"<<std::endl;}
};

TEST(rosimagetest, testsetname)
{
    ROSThreadImageTester rtit("test");
    ROSImageInstance rtii("test");

    rtit.sendTestImage();
    ros::Rate rate(100);

    while(ros::ok() && (rtii.getx() == -1 || rtii.gety() == -1))
    {
        ROS_INFO("Waiting for ROSThreadImage loop. [x y]: [%i %i]", rtii.getx(), rtii.gety());
        rate.sleep();
    }

    rtii.printx();
    rtii.printy();

    rtii.setName("newtestname");

    //Checks that x and y coordinates are correct
    EXPECT_TRUE(rtii.getx() == 100);
    EXPECT_TRUE(rtii.gety() == 100);

    //Checks that name is correct
    EXPECT_EQ("newtestname", rtii.getName());
    EXPECT_FALSE("test" == rtii.getName());
}

// Run all the tests that were declared with TEST()
int main(int argc, char **argv)
{
    ros::init(argc, argv, "ros_thread_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>
#pragma once

#include "physics/body_centred_body_direction_dynamic_frame.hpp"

#include "geometry/named_quantities.hpp"
#include "geometry/r3x3_matrix.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"

namespace principia {
namespace physics {
namespace internal_body_centred_body_direction_dynamic_frame {

using geometry::Bivector;
using geometry::Displacement;
using geometry::R3x3Matrix;
using geometry::Velocity;
using geometry::Wedge;
using quantities::GravitationalParameter;
using quantities::Length;
using quantities::Pow;
using quantities::Product;
using quantities::Speed;
using quantities::Variation;
using quantities::si::Radian;

template<typename InertialFrame, typename ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
    BodyCentredBodyDirectionDynamicFrame(
        not_null<Ephemeris<InertialFrame> const*> const ephemeris,
        not_null<MassiveBody const*> const primary,
        not_null<MassiveBody const*> const secondary)
    : ephemeris_(ephemeris),
      primary_(primary),
      secondary_(secondary),
      compute_gravitational_acceleration_on_primary_(
          [this](Position<InertialFrame> const& position, Instant const& t) {
            return ephemeris_->ComputeGravitationalAccelerationOnMassiveBody(
                primary_, t);
          }),
      primary_trajectory_(
          [&t = ephemeris_->trajectory(primary_)]() -> auto& { return t; }),
      secondary_trajectory_(ephemeris_->trajectory(secondary_)) {}

template<typename InertialFrame, typename ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
BodyCentredBodyDirectionDynamicFrame(
    not_null<Ephemeris<InertialFrame> const*> const ephemeris,
    std::function<Trajectory<InertialFrame> const&()> const
        primary_trajectory,
    not_null<MassiveBody const*> const secondary)
    : ephemeris_(ephemeris),
      primary_(nullptr),
      secondary_(secondary),
      compute_gravitational_acceleration_on_primary_(
          [this](Position<InertialFrame> const& position, Instant const& t) {
            return ephemeris_->ComputeGravitationalAccelerationOnMasslessBody(
                position, t);
          }),
      primary_trajectory_(primary_trajectory),
      secondary_trajectory_(ephemeris_->trajectory(secondary_)) {}

template<typename InertialFrame, typename ThisFrame>
RigidMotion<InertialFrame, ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
    ToThisFrameAtTime(Instant const& t) const {
  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_().EvaluateDegreesOfFreedom(t);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t);

  Rotation<InertialFrame, ThisFrame> rotation =
      Rotation<InertialFrame, ThisFrame>::Identity();
  AngularVelocity<InertialFrame> angular_velocity;
  ComputeAngularDegreesOfFreedom(primary_degrees_of_freedom,
                                 secondary_degrees_of_freedom,
                                 rotation,
                                 angular_velocity);

  RigidTransformation<InertialFrame, ThisFrame> const
      rigid_transformation(primary_degrees_of_freedom.position(),
                           ThisFrame::origin,
                           rotation.Forget());
  return RigidMotion<InertialFrame, ThisFrame>(
             rigid_transformation,
             angular_velocity,
             primary_degrees_of_freedom.velocity());
}

template<typename InertialFrame, typename ThisFrame>
void BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
WriteToMessage(not_null<serialization::DynamicFrame*> const message) const {
  auto* const extension =
      message->MutableExtension(
          serialization::BodyCentredBodyDirectionDynamicFrame::extension);
  extension->set_primary(ephemeris_->serialization_index_for_body(primary_));
  extension->set_secondary(
      ephemeris_->serialization_index_for_body(secondary_));
}

template<typename InertialFrame, typename ThisFrame>
not_null<std::unique_ptr<
    BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>>>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::ReadFromMessage(
    not_null<Ephemeris<InertialFrame> const*> const ephemeris,
    serialization::BodyCentredBodyDirectionDynamicFrame const & message) {
  return std::make_unique<BodyCentredBodyDirectionDynamicFrame>(
      ephemeris,
      ephemeris->body_for_serialization_index(message.primary()),
      ephemeris->body_for_serialization_index(message.secondary()));
}

template<typename InertialFrame, typename ThisFrame>
Vector<Acceleration, InertialFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
GravitationalAcceleration(Instant const& t,
                          Position<InertialFrame> const& q) const {
  return ephemeris_->ComputeGravitationalAccelerationOnMasslessBody(q, t);
}

template<typename InertialFrame, typename ThisFrame>
AcceleratedRigidMotion<InertialFrame, ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
MotionOfThisFrame(Instant const& t) const {
  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_().EvaluateDegreesOfFreedom(t);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t);

  // TODO(egg): eventually we want to add the intrinsic acceleration here.
  Vector<Acceleration, InertialFrame> const primary_acceleration =
      compute_gravitational_acceleration_on_primary_(
          primary_degrees_of_freedom.position(), t);

  Vector<Acceleration, InertialFrame> const secondary_acceleration =
      ephemeris_->ComputeGravitationalAccelerationOnMassiveBody(secondary_, t);

  auto const to_this_frame = ToThisFrameAtTime(t);

  // TODO(egg): TeX and reference.
  RelativeDegreesOfFreedom<InertialFrame> const secondary_primary =
      secondary_degrees_of_freedom - primary_degrees_of_freedom;
  Displacement<InertialFrame> const& r = secondary_primary.displacement();
  Velocity<InertialFrame> const& ṙ = secondary_primary.velocity();
  Vector<Acceleration, InertialFrame> const r̈ =
      secondary_acceleration - primary_acceleration;
  AngularVelocity<InertialFrame> const& ω =
      to_this_frame.angular_velocity_of_to_frame();
  Variation<AngularVelocity<InertialFrame>> const
      angular_acceleration_of_to_frame =
          (Wedge(r, r̈) * Radian - 2 * ω * InnerProduct(r, ṙ)) /
          InnerProduct(r, r);

  Vector<Acceleration, InertialFrame> const& acceleration_of_to_frame_origin =
      primary_acceleration;
  return AcceleratedRigidMotion<InertialFrame, ThisFrame>(
             to_this_frame,
             angular_acceleration_of_to_frame,
             acceleration_of_to_frame_origin);
}

template<typename InertialFrame, typename ThisFrame>
void BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
ComputeAngularDegreesOfFreedom(
    DegreesOfFreedom<InertialFrame> const& primary_degrees_of_freedom,
    DegreesOfFreedom<InertialFrame> const& secondary_degrees_of_freedom,
    Rotation<InertialFrame, ThisFrame>& rotation,
    AngularVelocity<InertialFrame>& angular_velocity) {
  RelativeDegreesOfFreedom<InertialFrame> const reference =
       secondary_degrees_of_freedom - primary_degrees_of_freedom;
  Displacement<InertialFrame> const& reference_direction =
      reference.displacement();
  Velocity<InertialFrame> const reference_normal =
      reference.velocity().OrthogonalizationAgainst(reference_direction);
  Bivector<Product<Length, Speed>, InertialFrame> const reference_binormal =
      Wedge(reference_direction, reference_normal);
  rotation = Rotation<InertialFrame, ThisFrame>(Normalize(reference_direction),
                                                Normalize(reference_normal),
                                                Normalize(reference_binormal));
  angular_velocity = reference_binormal * Radian /
                     InnerProduct(reference_direction, reference_direction);
}

}  // namespace internal_body_centred_body_direction_dynamic_frame
}  // namespace physics
}  // namespace principia
<commit_msg>indent is hard<commit_after>
#pragma once

#include "physics/body_centred_body_direction_dynamic_frame.hpp"

#include "geometry/named_quantities.hpp"
#include "geometry/r3x3_matrix.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"

namespace principia {
namespace physics {
namespace internal_body_centred_body_direction_dynamic_frame {

using geometry::Bivector;
using geometry::Displacement;
using geometry::R3x3Matrix;
using geometry::Velocity;
using geometry::Wedge;
using quantities::GravitationalParameter;
using quantities::Length;
using quantities::Pow;
using quantities::Product;
using quantities::Speed;
using quantities::Variation;
using quantities::si::Radian;

template<typename InertialFrame, typename ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
BodyCentredBodyDirectionDynamicFrame(
    not_null<Ephemeris<InertialFrame> const*> const ephemeris,
    not_null<MassiveBody const*> const primary,
    not_null<MassiveBody const*> const secondary)
    : ephemeris_(ephemeris),
      primary_(primary),
      secondary_(secondary),
      compute_gravitational_acceleration_on_primary_(
          [this](Position<InertialFrame> const& position, Instant const& t) {
            return ephemeris_->ComputeGravitationalAccelerationOnMassiveBody(
                primary_, t);
          }),
      primary_trajectory_(
          [&t = ephemeris_->trajectory(primary_)]() -> auto& { return t; }),
      secondary_trajectory_(ephemeris_->trajectory(secondary_)) {}

template<typename InertialFrame, typename ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
BodyCentredBodyDirectionDynamicFrame(
    not_null<Ephemeris<InertialFrame> const*> const ephemeris,
    std::function<Trajectory<InertialFrame> const&()> const
        primary_trajectory,
    not_null<MassiveBody const*> const secondary)
    : ephemeris_(ephemeris),
      primary_(nullptr),
      secondary_(secondary),
      compute_gravitational_acceleration_on_primary_(
          [this](Position<InertialFrame> const& position, Instant const& t) {
            return ephemeris_->ComputeGravitationalAccelerationOnMasslessBody(
                position, t);
          }),
      primary_trajectory_(primary_trajectory),
      secondary_trajectory_(ephemeris_->trajectory(secondary_)) {}

template<typename InertialFrame, typename ThisFrame>
RigidMotion<InertialFrame, ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
    ToThisFrameAtTime(Instant const& t) const {
  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_().EvaluateDegreesOfFreedom(t);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t);

  Rotation<InertialFrame, ThisFrame> rotation =
      Rotation<InertialFrame, ThisFrame>::Identity();
  AngularVelocity<InertialFrame> angular_velocity;
  ComputeAngularDegreesOfFreedom(primary_degrees_of_freedom,
                                 secondary_degrees_of_freedom,
                                 rotation,
                                 angular_velocity);

  RigidTransformation<InertialFrame, ThisFrame> const
      rigid_transformation(primary_degrees_of_freedom.position(),
                           ThisFrame::origin,
                           rotation.Forget());
  return RigidMotion<InertialFrame, ThisFrame>(
             rigid_transformation,
             angular_velocity,
             primary_degrees_of_freedom.velocity());
}

template<typename InertialFrame, typename ThisFrame>
void BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
WriteToMessage(not_null<serialization::DynamicFrame*> const message) const {
  auto* const extension =
      message->MutableExtension(
          serialization::BodyCentredBodyDirectionDynamicFrame::extension);
  extension->set_primary(ephemeris_->serialization_index_for_body(primary_));
  extension->set_secondary(
      ephemeris_->serialization_index_for_body(secondary_));
}

template<typename InertialFrame, typename ThisFrame>
not_null<std::unique_ptr<
    BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>>>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::ReadFromMessage(
    not_null<Ephemeris<InertialFrame> const*> const ephemeris,
    serialization::BodyCentredBodyDirectionDynamicFrame const & message) {
  return std::make_unique<BodyCentredBodyDirectionDynamicFrame>(
      ephemeris,
      ephemeris->body_for_serialization_index(message.primary()),
      ephemeris->body_for_serialization_index(message.secondary()));
}

template<typename InertialFrame, typename ThisFrame>
Vector<Acceleration, InertialFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
GravitationalAcceleration(Instant const& t,
                          Position<InertialFrame> const& q) const {
  return ephemeris_->ComputeGravitationalAccelerationOnMasslessBody(q, t);
}

template<typename InertialFrame, typename ThisFrame>
AcceleratedRigidMotion<InertialFrame, ThisFrame>
BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
MotionOfThisFrame(Instant const& t) const {
  DegreesOfFreedom<InertialFrame> const primary_degrees_of_freedom =
      primary_trajectory_().EvaluateDegreesOfFreedom(t);
  DegreesOfFreedom<InertialFrame> const secondary_degrees_of_freedom =
      secondary_trajectory_->EvaluateDegreesOfFreedom(t);

  // TODO(egg): eventually we want to add the intrinsic acceleration here.
  Vector<Acceleration, InertialFrame> const primary_acceleration =
      compute_gravitational_acceleration_on_primary_(
          primary_degrees_of_freedom.position(), t);

  Vector<Acceleration, InertialFrame> const secondary_acceleration =
      ephemeris_->ComputeGravitationalAccelerationOnMassiveBody(secondary_, t);

  auto const to_this_frame = ToThisFrameAtTime(t);

  // TODO(egg): TeX and reference.
  RelativeDegreesOfFreedom<InertialFrame> const secondary_primary =
      secondary_degrees_of_freedom - primary_degrees_of_freedom;
  Displacement<InertialFrame> const& r = secondary_primary.displacement();
  Velocity<InertialFrame> const& ṙ = secondary_primary.velocity();
  Vector<Acceleration, InertialFrame> const r̈ =
      secondary_acceleration - primary_acceleration;
  AngularVelocity<InertialFrame> const& ω =
      to_this_frame.angular_velocity_of_to_frame();
  Variation<AngularVelocity<InertialFrame>> const
      angular_acceleration_of_to_frame =
          (Wedge(r, r̈) * Radian - 2 * ω * InnerProduct(r, ṙ)) /
          InnerProduct(r, r);

  Vector<Acceleration, InertialFrame> const& acceleration_of_to_frame_origin =
      primary_acceleration;
  return AcceleratedRigidMotion<InertialFrame, ThisFrame>(
             to_this_frame,
             angular_acceleration_of_to_frame,
             acceleration_of_to_frame_origin);
}

template<typename InertialFrame, typename ThisFrame>
void BodyCentredBodyDirectionDynamicFrame<InertialFrame, ThisFrame>::
ComputeAngularDegreesOfFreedom(
    DegreesOfFreedom<InertialFrame> const& primary_degrees_of_freedom,
    DegreesOfFreedom<InertialFrame> const& secondary_degrees_of_freedom,
    Rotation<InertialFrame, ThisFrame>& rotation,
    AngularVelocity<InertialFrame>& angular_velocity) {
  RelativeDegreesOfFreedom<InertialFrame> const reference =
       secondary_degrees_of_freedom - primary_degrees_of_freedom;
  Displacement<InertialFrame> const& reference_direction =
      reference.displacement();
  Velocity<InertialFrame> const reference_normal =
      reference.velocity().OrthogonalizationAgainst(reference_direction);
  Bivector<Product<Length, Speed>, InertialFrame> const reference_binormal =
      Wedge(reference_direction, reference_normal);
  rotation = Rotation<InertialFrame, ThisFrame>(Normalize(reference_direction),
                                                Normalize(reference_normal),
                                                Normalize(reference_binormal));
  angular_velocity = reference_binormal * Radian /
                     InnerProduct(reference_direction, reference_direction);
}

}  // namespace internal_body_centred_body_direction_dynamic_frame
}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          process.cpp
* Purpose:       Implementation of class 'wxExProcessWithListView'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/tokenzr.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/extension/app.h>
#include <wx/extension/configdialog.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listview.h>

BEGIN_EVENT_TABLE(wxExProcessWithListView, wxProcess)
  EVT_TIMER(-1, wxExProcessWithListView::OnTimer)
END_EVENT_TABLE()

wxString wxExProcessWithListView::m_Command = "";

wxExProcessWithListView::wxExProcessWithListView(
  wxExListViewFile* listview,
  const wxString& command)
  : wxProcess(NULL, -1)
  , m_Owner(listview)
  , m_Timer(this)
{
  if (!command.empty())
  {
    m_Command = command;
  }

  Redirect();
}

bool wxExProcessWithListView::CheckInput()
{
  bool hasInput = false;

  // This assumes that the output is always line buffered.
  wxString line;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());
    line << tis.ReadLine();
    hasInput = true;
  }
  else if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());
    line << tis.ReadLine();
    hasInput = true;
  }

  if (hasInput && !line.empty())
  {
    wxString lineno;
    wxString path;

    // Check on error in php script output.
    wxRegEx regex(".*in \\(.*\\) on line \\(.*\\)");

    if (regex.Matches(line))
    {
      size_t start, len;

      if (regex.GetMatch(&start, &len, 1))
      {
        path = line.substr(start, len);
      }

      if (regex.GetMatch(&start, &len, 2))
      {
        lineno = line.substr(start, len);
      }
    }
    else
    {
      // Check on error in gcc output (and some others).
      wxStringTokenizer tkz(line, ':');
      path = tkz.GetNextToken();

      if (tkz.HasMoreTokens())
      {
        const wxString number = tkz.GetNextToken();
        long val;
        if (number.ToLong(&val)) lineno = number;
      }
    }

    wxFileName fn(path);
    fn.Normalize();

    if (fn.FileExists())
    {
      wxExListItemWithFileName item(m_Owner, fn.GetFullPath());
      item.Insert();
      item.SetColumnText(_("Line"), line);
      item.SetColumnText(_("Line No"), lineno);
    }
    else
    {
      wxExListItemWithFileName item(m_Owner, wxEmptyString); // wxExListItem gives incorrect image
      item.Insert();
      item.SetColumnText(_("Line"), line);
    }

    // If nothing selected, then ensure last line is visible.
    // Otherwise you are busy inspecting some line, and
    // it would be irritating to get it out of view.
    if (m_Owner->GetSelectedItemCount() == 0)
    {
      m_Owner->EnsureVisible(m_Owner->GetItemCount() - 1);
    }

    m_Owner->UpdateStatusBar();
  }

  return hasInput;
}

int wxExProcessWithListView::ConfigDialog()
{
  std::vector<wxExConfigItem> v;
  v.push_back(wxExConfigItem(_("Process"), CONFIG_COMBOBOX, wxEmptyString, true));
  v.push_back(wxExConfigItem(_("In folder"), CONFIG_COMBOBOXDIR, wxEmptyString, true));

  const int result = wxExConfigDialog(NULL,
    wxExApp::GetConfig(),
    v,
    _("Select Process")).ShowModal();

  if (result == wxID_OK)
  {
    wxSetWorkingDirectory(wxExApp::GetConfig(_("In folder")));
    m_Command = wxExApp::GetConfig(_("Process"));
  }

  return result;
}

long wxExProcessWithListView::Execute()
{
  long pid;

  if ((pid = wxExecute(m_Command, wxEXEC_ASYNC, this)) > 0)
  {
    SetPid(pid);

    wxExFrame::StatusText(m_Command);
    wxExApp::Log(_("Running process") + ": " + m_Command);

    m_Timer.Start(100); // each 100 milliseconds
  }
  else
  {
    wxLogError(_("Cannot run process") + ": " + m_Command);
  }

  return pid;
}

wxKillError wxExProcessWithListView::Kill(wxSignal sig)
{
  m_Timer.Stop();

  wxExFrame::StatusText(_("Stopped"));

  return wxProcess::Kill(GetPid(), sig);
}

void wxExProcessWithListView::OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
{
  m_Timer.Stop();

  // Collect remaining input.
  while (CheckInput())
  {
    // Do nothing.
  }

  wxExFrame::StatusText(_("Ready"));

  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(m_Owner, event);
}

void wxExProcessWithListView::OnTimer(wxTimerEvent& event)
{
  while (CheckInput())
  {
    // Do nothing.
  }
}
<commit_msg>delete this when killing the process<commit_after>/******************************************************************************\
* File:          process.cpp
* Purpose:       Implementation of class 'wxExProcessWithListView'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/tokenzr.h>
#include <wx/txtstrm.h> // for wxTextInputStream
#include <wx/extension/app.h>
#include <wx/extension/configdialog.h>
#include <wx/extension/report/process.h>
#include <wx/extension/report/defs.h>
#include <wx/extension/report/listitem.h>
#include <wx/extension/report/listview.h>

BEGIN_EVENT_TABLE(wxExProcessWithListView, wxProcess)
  EVT_TIMER(-1, wxExProcessWithListView::OnTimer)
END_EVENT_TABLE()

wxString wxExProcessWithListView::m_Command = "";

wxExProcessWithListView::wxExProcessWithListView(
  wxExListViewFile* listview,
  const wxString& command)
  : wxProcess(NULL, -1)
  , m_Owner(listview)
  , m_Timer(this)
{
  if (!command.empty())
  {
    m_Command = command;
  }

  Redirect();
}

bool wxExProcessWithListView::CheckInput()
{
  bool hasInput = false;

  // This assumes that the output is always line buffered.
  wxString line;

  if (IsInputAvailable())
  {
    wxTextInputStream tis(*GetInputStream());
    line << tis.ReadLine();
    hasInput = true;
  }
  else if (IsErrorAvailable())
  {
    wxTextInputStream tis(*GetErrorStream());
    line << tis.ReadLine();
    hasInput = true;
  }

  if (hasInput && !line.empty())
  {
    wxString lineno;
    wxString path;

    // Check on error in php script output.
    wxRegEx regex(".*in \\(.*\\) on line \\(.*\\)");

    if (regex.Matches(line))
    {
      size_t start, len;

      if (regex.GetMatch(&start, &len, 1))
      {
        path = line.substr(start, len);
      }

      if (regex.GetMatch(&start, &len, 2))
      {
        lineno = line.substr(start, len);
      }
    }
    else
    {
      // Check on error in gcc output (and some others).
      wxStringTokenizer tkz(line, ':');
      path = tkz.GetNextToken();

      if (tkz.HasMoreTokens())
      {
        const wxString number = tkz.GetNextToken();
        long val;
        if (number.ToLong(&val)) lineno = number;
      }
    }

    wxFileName fn(path);
    fn.Normalize();

    if (fn.FileExists())
    {
      wxExListItemWithFileName item(m_Owner, fn.GetFullPath());
      item.Insert();
      item.SetColumnText(_("Line"), line);
      item.SetColumnText(_("Line No"), lineno);
    }
    else
    {
      wxExListItemWithFileName item(m_Owner, wxEmptyString); // wxExListItem gives incorrect image
      item.Insert();
      item.SetColumnText(_("Line"), line);
    }

    // If nothing selected, then ensure last line is visible.
    // Otherwise you are busy inspecting some line, and
    // it would be irritating to get it out of view.
    if (m_Owner->GetSelectedItemCount() == 0)
    {
      m_Owner->EnsureVisible(m_Owner->GetItemCount() - 1);
    }

    m_Owner->UpdateStatusBar();
  }

  return hasInput;
}

int wxExProcessWithListView::ConfigDialog()
{
  std::vector<wxExConfigItem> v;
  v.push_back(wxExConfigItem(_("Process"), CONFIG_COMBOBOX, wxEmptyString, true));
  v.push_back(wxExConfigItem(_("In folder"), CONFIG_COMBOBOXDIR, wxEmptyString, true));

  const int result = wxExConfigDialog(NULL,
    wxExApp::GetConfig(),
    v,
    _("Select Process")).ShowModal();

  if (result == wxID_OK)
  {
    wxSetWorkingDirectory(wxExApp::GetConfig(_("In folder")));
    m_Command = wxExApp::GetConfig(_("Process"));
  }

  return result;
}

long wxExProcessWithListView::Execute()
{
  long pid;

  if ((pid = wxExecute(m_Command, wxEXEC_ASYNC, this)) > 0)
  {
    SetPid(pid);

    wxExFrame::StatusText(m_Command);
    wxExApp::Log(_("Running process") + ": " + m_Command);

    m_Timer.Start(100); // each 100 milliseconds
  }
  else
  {
    wxLogError(_("Cannot run process") + ": " + m_Command);
  }

  return pid;
}

wxKillError wxExProcessWithListView::Kill(wxSignal sig)
{
  m_Timer.Stop();

  wxExFrame::StatusText(_("Stopped"));

  DeletePendingEvents();

  delete this;

  return wxProcess::Kill(GetPid(), sig);
}

void wxExProcessWithListView::OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
{
  m_Timer.Stop();

  // Collect remaining input.
  while (CheckInput())
  {
    // Do nothing.
  }

  wxExFrame::StatusText(_("Ready"));

  wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID_TERMINATED_PROCESS);
  wxPostEvent(m_Owner, event);
}

void wxExProcessWithListView::OnTimer(wxTimerEvent& event)
{
  while (CheckInput())
  {
    // Do nothing.
  }
}
<|endoftext|>