<commit_before>//
// client.cpp
//
//  Created by Peter Gusev on 07 March 2016.
//  Copyright 2013-2016 Regents of the University of California
//

#include <algorithm>
#include <boost/make_shared.hpp>
#include <ndn-cpp/security/key-chain.hpp>
#include <ndn-cpp/security/identity/memory-private-key-storage.hpp>
#include <ndn-cpp/security/identity/memory-identity-storage.hpp>
#include <ndn-cpp/security/policy/no-verify-policy-manager.hpp>

#include "client.hpp"
#include "config.hpp"
#include "renderer.hpp"

using namespace std;
using namespace ndn;

//******************************************************************************
void Client::run(unsigned int runTimeSec, unsigned int statSamplePeriodMs,
                 const ClientParams& params, const std::string& instanceName)
{
	runTimeSec_ = runTimeSec;
	statSampleIntervalMs_ = statSamplePeriodMs;
	params_ = params;
    instanceName_ = instanceName;

	bool run = setupConsumer();
	run |= setupProducer();

	if (!run) return;

	setupStatGathering();
	runProcessLoop();
	tearDownStatGathering();
	tearDownProducer();
	tearDownConsumer();
}

//******************************************************************************
bool Client::setupConsumer()
{
	if (!params_.isConsuming())
		return false;

	ConsumerClientParams ccp = params_.getConsumerParams();

	for (auto p:ccp.fetchedStreams_)
	{
		ndnrtc::GeneralConsumerParams gp = (p.type_ == ClientMediaStreamParams::MediaStreamType::MediaStreamTypeAudio ? ccp.generalAudioParams_ : ccp.generalVideoParams_);
		RemoteStream rs = initRemoteStream(p, gp);
#warning check move semantics
		remoteStreams_.push_back(boost::move(rs));

		LogInfo("") << "Set up fetching from " << p.sessionPrefix_ << ":"
			<< p.streamName_ << endl;
	}

	LogInfo("") << "Fetching " << remoteStreams_.size() << " remote stream(s) total" << endl;

	return true;
}

bool Client::setupProducer()
{
	if (!params_.isProducing())
		return false;

	ProducerClientParams pcp = params_.getProducerParams();

	for (auto p:pcp.publishedStreams_)
	{
		try
		{
			LocalStream ls = initLocalStream(p);
			localStreams_.push_back(boost::move(ls));

			LogInfo("") << "Set up publishing stream " << pcp.prefix_ << ":"
				<< p.streamName_ << endl;
		}
		catch (const runtime_error& e)
		{
			LogError("") << "error while trying to publish stream " << p.streamName_ << ": "
				<< e.what() << endl;
            throw;
		}
	}

	LogInfo("") << "Publishing " << localStreams_.size() << " stream(s) total" << endl;
	return true;
}

void Client::setupStatGathering()
{
	if (!params_.isGatheringStats())
		return;

	LogInfo("") << "new stat colllector" << endl;
	statCollector_.reset(new StatCollector(io_));

	for (auto& rs:remoteStreams_)
		statCollector_->addStream(rs.getStream());

	statCollector_->startCollecting(statSampleIntervalMs_,
		params_.getGeneralParameters().logPath_,
		params_.getConsumerParams().statGatheringParams_);

	LogInfo("") << "Gathering statistics into "
		<< statCollector_->getWritersNumber() << " files" << std::endl;
}

void Client::runProcessLoop()
{
    boost::asio::deadline_timer runTimer(io_);
    runTimer.expires_from_now(boost::posix_time::seconds(runTimeSec_));
    runTimer.wait();
}

void Client::tearDownStatGathering(){
	if (!params_.isGatheringStats())
		return;

	statCollector_->stop();
	statCollector_.reset();
	LogInfo("") << "Stopped gathering statistics" << std::endl;
}

void Client::tearDownProducer(){
	if (!params_.isProducing())
		return;

	LogInfo("Tearing down producing...");

	for (auto& ls:localStreams_)
	{
		if (!ls.getVideoSource().get())
			boost::dynamic_pointer_cast<ndnrtc::LocalAudioStream>(ls.getStream())->stop();
		else
			ls.stopSource();

		LogInfo("") << "...stopped publishing " << ls.getStream()->getPrefix() << std::endl;
	}
	localStreams_.clear();
}

void Client::tearDownConsumer(){
	if (!params_.isConsuming())
		return ;

	LogInfo("") << "Tearing down consuming..." << std::endl;

	for (auto& rs:remoteStreams_)
	{
		boost::dynamic_pointer_cast<ndnrtc::RemoteStream>(rs.getStream())->stop();
		LogInfo("") << "...stopped fetching from " << rs.getStream()->getPrefix() << std::endl;
	}
	remoteStreams_.clear();
}

RemoteStream Client::initRemoteStream(const ConsumerStreamParams& p,
	const ndnrtc::GeneralConsumerParams& gcp)
{
	RendererInternal *renderer = (p.type_ == ConsumerStreamParams::MediaStreamTypeVideo ? new RendererInternal(p.streamSink_, true) : nullptr);

	if (p.type_ == ConsumerStreamParams::MediaStreamTypeVideo)
	{
		boost::shared_ptr<ndnrtc::RemoteVideoStream>
			remoteStream(boost::make_shared<ndnrtc::RemoteVideoStream>(io_, face_, keyChain_,
				p.sessionPrefix_, p.streamName_));
		remoteStream->setLogger(consumerLogger(p.sessionPrefix_, p.streamName_));
		remoteStream->start(p.threadToFetch_, renderer);
		return RemoteStream(remoteStream, boost::shared_ptr<RendererInternal>(renderer));
	}
	else
	{
		boost::shared_ptr<ndnrtc::RemoteAudioStream>
			remoteStream(boost::make_shared<ndnrtc::RemoteAudioStream>(io_, face_, keyChain_,
				p.sessionPrefix_, p.streamName_));
		remoteStream->setLogger(consumerLogger(p.sessionPrefix_, p.streamName_));
		remoteStream->start(p.threadToFetch_);
		return RemoteStream(remoteStream, boost::shared_ptr<RendererInternal>(renderer));
	}
}

LocalStream Client::initLocalStream(const ProducerStreamParams& p)
{
	boost::shared_ptr<ndnrtc::IStream> localStream;
	boost::shared_ptr<VideoSource> videoSource;
	ndnrtc::MediaStreamSettings settings(io_, p);

	settings.keyChain_ = keyChain_.get();
	settings.face_ = face_.get();

	if (p.type_ == ndnrtc::MediaStreamParams::MediaStreamTypeVideo)
	{
		LogDebug("") << "initializing video source at " << p.source_ << endl;

		boost::shared_ptr<RawFrame> sampleFrame = sampleFrameForStream(p);

		LogDebug("") << "source should support frames of size "
			<< sampleFrame->getWidth() << "x" << sampleFrame->getHeight() << endl;
		videoSource.reset(new VideoSource(io_, p.source_, sampleFrame));
		LogDebug("") << "video source initialized" << endl;

		boost::shared_ptr<ndnrtc::LocalVideoStream> s =
			boost::make_shared<ndnrtc::LocalVideoStream>(p.sessionPrefix_, settings);

        s->setLogger(producerLogger(p.streamName_));
		videoSource->addCapturer(s.get());
		localStream = s;

#warning double-check whether FPS should be 30
		LogDebug("") << "starting video source..." << endl;
		videoSource->start(30);
		LogDebug("") << "...video source started" << endl;
	}
	else
	{
		boost::shared_ptr<ndnrtc::LocalAudioStream> s =
			boost::make_shared<ndnrtc::LocalAudioStream>(p.sessionPrefix_, settings);
        s->setLogger(producerLogger(p.streamName_));
		s->start();
		localStream = s;
	}

	return LocalStream(localStream, videoSource);
}

boost::shared_ptr<RawFrame> Client::sampleFrameForStream(const ProducerStreamParams& p)
{
	unsigned int width = 0, height = 0;
	p.getMaxResolution(width, height);

	if (width == 0 || height == 0)
	{
		stringstream ss;
		ss << "incorrect max resolution for stream " << p.streamName_;
		throw runtime_error(ss.str());
	}

	return boost::shared_ptr<RawFrame>(new ArgbFrame(width, height));
}

boost::shared_ptr<ndnlog::new_api::Logger>
Client::producerLogger(std::string streamName)
{
	std::stringstream logFileName;
	logFileName << params_.getGeneralParameters().logPath_ << "/"
		<< "producer-" << instanceName_ << "-" << streamName << ".log";
	boost::shared_ptr<ndnlog::new_api::Logger> logger(new ndnlog::new_api::Logger(params_.getGeneralParameters().loggingLevel_,
		logFileName.str()));

	return logger;
}

boost::shared_ptr<ndnlog::new_api::Logger>
Client::consumerLogger(std::string prefix, std::string streamName)
{
	std::replace(prefix.begin(), prefix.end(), '/', '-');
	std::stringstream logFileName;
	logFileName << params_.getGeneralParameters().logPath_ << "/"
		<< "consumer" << prefix << "-" << streamName << ".log" << std::endl;
	boost::shared_ptr<ndnlog::new_api::Logger> logger(new ndnlog::new_api::Logger(params_.getGeneralParameters().loggingLevel_,
		logFileName.str()));

	return logger;
}<commit_msg>[client] fixed consumer log filename<commit_after>//
// client.cpp
//
//  Created by Peter Gusev on 07 March 2016.
//  Copyright 2013-2016 Regents of the University of California
//

#include <algorithm>
#include <boost/make_shared.hpp>
#include <ndn-cpp/security/key-chain.hpp>
#include <ndn-cpp/security/identity/memory-private-key-storage.hpp>
#include <ndn-cpp/security/identity/memory-identity-storage.hpp>
#include <ndn-cpp/security/policy/no-verify-policy-manager.hpp>

#include "client.hpp"
#include "config.hpp"
#include "renderer.hpp"

using namespace std;
using namespace ndn;

//******************************************************************************
void Client::run(unsigned int runTimeSec, unsigned int statSamplePeriodMs,
                 const ClientParams& params, const std::string& instanceName)
{
	runTimeSec_ = runTimeSec;
	statSampleIntervalMs_ = statSamplePeriodMs;
	params_ = params;
    instanceName_ = instanceName;

	bool run = setupConsumer();
	run |= setupProducer();

	if (!run) return;

	setupStatGathering();
	runProcessLoop();
	tearDownStatGathering();
	tearDownProducer();
	tearDownConsumer();
}

//******************************************************************************
bool Client::setupConsumer()
{
	if (!params_.isConsuming())
		return false;

	ConsumerClientParams ccp = params_.getConsumerParams();

	for (auto p:ccp.fetchedStreams_)
	{
		ndnrtc::GeneralConsumerParams gp = (p.type_ == ClientMediaStreamParams::MediaStreamType::MediaStreamTypeAudio ? ccp.generalAudioParams_ : ccp.generalVideoParams_);
		RemoteStream rs = initRemoteStream(p, gp);
#warning check move semantics
		remoteStreams_.push_back(boost::move(rs));

		LogInfo("") << "Set up fetching from " << p.sessionPrefix_ << ":"
			<< p.streamName_ << endl;
	}

	LogInfo("") << "Fetching " << remoteStreams_.size() << " remote stream(s) total" << endl;

	return true;
}

bool Client::setupProducer()
{
	if (!params_.isProducing())
		return false;

	ProducerClientParams pcp = params_.getProducerParams();

	for (auto p:pcp.publishedStreams_)
	{
		try
		{
			LocalStream ls = initLocalStream(p);
			localStreams_.push_back(boost::move(ls));

			LogInfo("") << "Set up publishing stream " << pcp.prefix_ << ":"
				<< p.streamName_ << endl;
		}
		catch (const runtime_error& e)
		{
			LogError("") << "error while trying to publish stream " << p.streamName_ << ": "
				<< e.what() << endl;
            throw;
		}
	}

	LogInfo("") << "Publishing " << localStreams_.size() << " stream(s) total" << endl;
	return true;
}

void Client::setupStatGathering()
{
	if (!params_.isGatheringStats())
		return;

	LogInfo("") << "new stat colllector" << endl;
	statCollector_.reset(new StatCollector(io_));

	for (auto& rs:remoteStreams_)
		statCollector_->addStream(rs.getStream());

	statCollector_->startCollecting(statSampleIntervalMs_,
		params_.getGeneralParameters().logPath_,
		params_.getConsumerParams().statGatheringParams_);

	LogInfo("") << "Gathering statistics into "
		<< statCollector_->getWritersNumber() << " files" << std::endl;
}

void Client::runProcessLoop()
{
    boost::asio::deadline_timer runTimer(io_);
    runTimer.expires_from_now(boost::posix_time::seconds(runTimeSec_));
    runTimer.wait();
}

void Client::tearDownStatGathering(){
	if (!params_.isGatheringStats())
		return;

	statCollector_->stop();
	statCollector_.reset();
	LogInfo("") << "Stopped gathering statistics" << std::endl;
}

void Client::tearDownProducer(){
	if (!params_.isProducing())
		return;

	LogInfo("Tearing down producing...");

	for (auto& ls:localStreams_)
	{
		if (!ls.getVideoSource().get())
			boost::dynamic_pointer_cast<ndnrtc::LocalAudioStream>(ls.getStream())->stop();
		else
			ls.stopSource();

		LogInfo("") << "...stopped publishing " << ls.getStream()->getPrefix() << std::endl;
	}
	localStreams_.clear();
}

void Client::tearDownConsumer(){
	if (!params_.isConsuming())
		return ;

	LogInfo("") << "Tearing down consuming..." << std::endl;

	for (auto& rs:remoteStreams_)
	{
		boost::dynamic_pointer_cast<ndnrtc::RemoteStream>(rs.getStream())->stop();
		LogInfo("") << "...stopped fetching from " << rs.getStream()->getPrefix() << std::endl;
	}
	remoteStreams_.clear();
}

RemoteStream Client::initRemoteStream(const ConsumerStreamParams& p,
	const ndnrtc::GeneralConsumerParams& gcp)
{
	RendererInternal *renderer = (p.type_ == ConsumerStreamParams::MediaStreamTypeVideo ? new RendererInternal(p.streamSink_, true) : nullptr);

	if (p.type_ == ConsumerStreamParams::MediaStreamTypeVideo)
	{
		boost::shared_ptr<ndnrtc::RemoteVideoStream>
			remoteStream(boost::make_shared<ndnrtc::RemoteVideoStream>(io_, face_, keyChain_,
				p.sessionPrefix_, p.streamName_));
		remoteStream->setLogger(consumerLogger(p.sessionPrefix_, p.streamName_));
		remoteStream->start(p.threadToFetch_, renderer);
		return RemoteStream(remoteStream, boost::shared_ptr<RendererInternal>(renderer));
	}
	else
	{
		boost::shared_ptr<ndnrtc::RemoteAudioStream>
			remoteStream(boost::make_shared<ndnrtc::RemoteAudioStream>(io_, face_, keyChain_,
				p.sessionPrefix_, p.streamName_));
		remoteStream->setLogger(consumerLogger(p.sessionPrefix_, p.streamName_));
		remoteStream->start(p.threadToFetch_);
		return RemoteStream(remoteStream, boost::shared_ptr<RendererInternal>(renderer));
	}
}

LocalStream Client::initLocalStream(const ProducerStreamParams& p)
{
	boost::shared_ptr<ndnrtc::IStream> localStream;
	boost::shared_ptr<VideoSource> videoSource;
	ndnrtc::MediaStreamSettings settings(io_, p);

	settings.keyChain_ = keyChain_.get();
	settings.face_ = face_.get();

	if (p.type_ == ndnrtc::MediaStreamParams::MediaStreamTypeVideo)
	{
		LogDebug("") << "initializing video source at " << p.source_ << endl;

		boost::shared_ptr<RawFrame> sampleFrame = sampleFrameForStream(p);

		LogDebug("") << "source should support frames of size "
			<< sampleFrame->getWidth() << "x" << sampleFrame->getHeight() << endl;
		videoSource.reset(new VideoSource(io_, p.source_, sampleFrame));
		LogDebug("") << "video source initialized" << endl;

		boost::shared_ptr<ndnrtc::LocalVideoStream> s =
			boost::make_shared<ndnrtc::LocalVideoStream>(p.sessionPrefix_, settings);

        s->setLogger(producerLogger(p.streamName_));
		videoSource->addCapturer(s.get());
		localStream = s;

#warning double-check whether FPS should be 30
		LogDebug("") << "starting video source..." << endl;
		videoSource->start(30);
		LogDebug("") << "...video source started" << endl;
	}
	else
	{
		boost::shared_ptr<ndnrtc::LocalAudioStream> s =
			boost::make_shared<ndnrtc::LocalAudioStream>(p.sessionPrefix_, settings);
        s->setLogger(producerLogger(p.streamName_));
		s->start();
		localStream = s;
	}

	return LocalStream(localStream, videoSource);
}

boost::shared_ptr<RawFrame> Client::sampleFrameForStream(const ProducerStreamParams& p)
{
	unsigned int width = 0, height = 0;
	p.getMaxResolution(width, height);

	if (width == 0 || height == 0)
	{
		stringstream ss;
		ss << "incorrect max resolution for stream " << p.streamName_;
		throw runtime_error(ss.str());
	}

	return boost::shared_ptr<RawFrame>(new ArgbFrame(width, height));
}

boost::shared_ptr<ndnlog::new_api::Logger>
Client::producerLogger(std::string streamName)
{
	std::stringstream logFileName;
	logFileName << params_.getGeneralParameters().logPath_ << "/"
		<< "producer-" << instanceName_ << "-" << streamName << ".log";
	boost::shared_ptr<ndnlog::new_api::Logger> logger(new ndnlog::new_api::Logger(params_.getGeneralParameters().loggingLevel_,
		logFileName.str()));

	return logger;
}

boost::shared_ptr<ndnlog::new_api::Logger>
Client::consumerLogger(std::string prefix, std::string streamName)
{
	std::replace(prefix.begin(), prefix.end(), '/', '-');
	std::stringstream logFileName;
	logFileName << params_.getGeneralParameters().logPath_ << "/"
		<< "consumer" << prefix << "-" << streamName << ".log";
	boost::shared_ptr<ndnlog::new_api::Logger> logger(new ndnlog::new_api::Logger(params_.getGeneralParameters().loggingLevel_,
		logFileName.str()));

	return logger;
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright (C) 2000 Frans Kaashoek (kaashoek@lcs.mit.edu)
 * Copyright (C) 2001 Frans Kaashoek (kaashoek@lcs.mit.edu) and
 *                    Frank Dabek (fdabek@lcs.mit.edu).
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include "chord.h"
#include "chord_util.h"
#include "location.h"
#include "route.h"
#include "transport_prot.h"

int logbase;  // base = 2 ^ logbase

chord::chord (str _wellknownhost, int _wellknownport,
	      str _myname, int port, int max_cache,
	      int server_selection_mode,
	      int l_mode, int _logbase) :
  myname (_myname),
  ss_mode (server_selection_mode % 10),
  lookup_mode (l_mode),
  active (NULL)
{
  logbase = _logbase;
  myport = startchord (port);

  wellknown_node.r.hostname = _wellknownhost;
  wellknown_node.r.port = _wellknownport ? _wellknownport : myport;
  wellknown_node.x = make_chordID (wellknown_node.r.hostname,
				   wellknown_node.r.port);
  wellknown_node.coords.setsize (NCOORDS);

  warnx << "chord: running on " << myname << ":" << myport << "\n";

  nrcv = New refcounted<u_int32_t>;
  *nrcv = 0;
  locations = New refcounted<locationtable> (nrcv, max_cache);

  //BAD LOC (ok)
  bool ok = locations->insert (wellknown_node);
  if (!ok) {
    warn << "Well known host failed to verify! Bailing.\n";
    exit (0);
  }

  nvnode = 0;
  srandom ((unsigned int) (getusec() & 0xFFFFFFFF));
}

void
chord::tcpclient_cb (int srvfd)
{
  int fd = accept (srvfd, NULL, NULL);
  if (fd < 0)
    warn << "chord: accept failed " << strerror (errno) << "\n";
  else {
    ptr<axprt> x = axprt_stream::alloc (fd, 230000);

    ptr<asrv> s = asrv::alloc (x, transport_program_1);
    s->setcb (wrap (mkref(this), &chord::dispatch, s));
  }
}

int
chord::startchord (int myp, int type)
{

  int srvfd = inetsocket (type, myp);
  if (srvfd < 0)
    fatal ("binding %s port %d: %m\n",
	   (type == SOCK_DGRAM ? "UDP" : "TCP"), myp);

  if (myp == 0) {
    struct sockaddr_in addr;
    socklen_t len = sizeof (addr);
    bzero (&addr, sizeof (addr));
    if (getsockname (srvfd, (sockaddr *) &addr, &len) < 0)
      fatal ("getsockname failed %m\n");
    myp = ntohs (addr.sin_port);
  }

  if (type == SOCK_DGRAM) {
    x_dgram = axprt_dgram::alloc (srvfd, sizeof(sockaddr), 230000);
    ptr<asrv> s = asrv::alloc (x_dgram, transport_program_1);
    s->setcb (wrap (mkref(this), &chord::dispatch, s));
  }
  else {
    int ret = listen (srvfd, 1000);
    assert (ret == 0);
    fdcb (srvfd, selread, wrap (this, &chord::tcpclient_cb, srvfd));
  }

  return myp;
}

int
chord::startchord (int myp)
{
  // see also locationtable constructor.
  if (chord_rpc_style == CHORD_RPC_SFST) {
    // Ensure the DGRAM and STREAM sockets are on same port #,
    // since it is included in the Chord ID's hash.
    myp = startchord (myp, SOCK_STREAM);
  }

  return startchord (myp, SOCK_DGRAM);
}

ptr<vnode>
chord::newvnode (cbjoin_t cb, ptr<fingerlike> fingers, ptr<route_factory> f)
{
  if (nvnode > max_vnodes)
    fatal << "Maximum number of vnodes (" << max_vnodes << ") reached.\n";

  chordID newID = init_chordID (nvnode, myname, myport);
  warn << "creating new vnode: " << newID << "\n";

  vec<float> coords;
  warn << gettime () << " coords are: ";
  for (int i = 0; i < NCOORDS; i++) {
    coords.push_back (uniform_random_f (1000.0));
    warnx << (int) coords[i] << " " ;
  }
  warnx << "\n";
  locations->insert (newID, myname, myport, coords);
  // force an update of the coords in the locationtable
  locations->set_coords (newID, coords);

#if 0
  if (newID != wellknown_node.x) {
    // It's not yet strictly speaking useful to other nodes yet.
    ///BAD LOC (ok)
    bool ok = locations->insert (newID, myname, myport);
    assert (ok);
  }
#endif /* 0 */

  ptr<vnode> vnodep = vnode::produce_vnode (locations, fingers, f,
					    mkref (this), newID,
					    nvnode, ss_mode,
					    lookup_mode);
  f->setvnode (vnodep);

  if (!active) active = vnodep;
  nvnode++;
  vnodes.insert (newID, vnodep);

  if (newID != wellknown_node.x) {
    vnodep->join (wellknown_node, cb);
  } else {
    vnodep->stabilize ();
    (*cb) (vnodep, CHORD_OK);
  }
  return vnodep;
}

void
chord::stats_cb (const chordID &k, ptr<vnode> v) {
  v->stats();
}

void
chord::stats ()
{
  warnx << "CHORD NODE STATS\n";
  warnx << "# vnodes: " << nvnode << "\n";
  vnodes.traverse (wrap (this, &chord::stats_cb));
  locations->stats ();
}

void
chord::print_cb (const chordID &k, ptr<vnode> v) {
  v->print ();
}

void
chord::print () {
  vnodes.traverse (wrap (this, &chord::print_cb));
}

void
chord::stop_cb (const chordID &k, ptr<vnode> v) {
  v->stop ();
}

void
chord::stop () {
  vnodes.traverse (wrap (this, &chord::stop_cb));
}

const rpc_program *
chord::get_program (int progno)
{
  for (unsigned int i = 0; i < handledProgs.size (); i++)
    if (progno == (int)handledProgs[i]->progno)
      return handledProgs[i];
  return NULL;
}

bool
chord::isHandled (int progno) {
  for (u_int i = 0; i < handledProgs.size (); i++)
    if (progno == (int)handledProgs[i]->progno) return true;
  return false;
}
void
chord::handleProgram (const rpc_program &prog) {
  warn << "chord::handleProgram: " << prog.progno << "\n";
  if (isHandled (prog.progno)) return;
  else {
    handledProgs.push_back (&prog);
  }
}

void
chord::dispatch (ptr<asrv> s, svccb *sbp)
{
  if (!sbp) {
    s->setcb (NULL);
    return;
  }
  (*nrcv)++;

  //autocache nodes
  dorpc_arg *arg = sbp->template getarg<dorpc_arg> ();
  if (arg && !locations->cached (arg->src_id)) {
    const sockaddr *sa = sbp->getsa ();
    net_address netaddr;
    netaddr.port = ((sockaddr_in *)sa)->sin_port;
    str addrstr (inet_ntoa (((sockaddr_in *)sa)->sin_addr));
    netaddr.hostname = addrstr;
    warn << "autocaching " << addrstr << ":" << netaddr.port << " in ::dispatch\n";
    vec<float> coords = convert_coords (arg);
    locations->insert (arg->src_id, netaddr.hostname, netaddr.port, coords);
  }

  switch (sbp->proc ()) {
  case TRANSPORTPROC_NULL:
    {
      sbp->reply (NULL);
      break;
    }
  case TRANSPORTPROC_DORPC:
    {
      //v (the destination chordID) is at the top of the header
      chordID *v = sbp->template getarg<chordID> ();
      vnode *vnodep = vnodes[*v];
      if (!vnodep) {
	warnx << "CHORD: unknown node processing procedure " << sbp->proc ()
	      << " request " << *v << "\n";
	sbp->replyref (chordstat (CHORD_UNKNOWNNODE));
	return;
      }

      //find the program
      const rpc_program *prog = get_program (arg->progno);
      if (!prog)
	fatal << "bad prog: " << arg->progno << "\n";

      //unmarshall the args
      char *arg_base = (char *)(arg->args.base ());
      int arg_len = arg->args.size ();

      xdrmem x (arg_base, arg_len, XDR_DECODE);
      xdrproc_t proc = prog->tbl[arg->procno].xdr_arg;
      assert (proc);

      void *unmarshalled_args = prog->tbl[arg->procno].alloc_arg ();
      if (!proc (x.xdrp (), unmarshalled_args)) {
	warn << "dispatch: error unmarshalling arguments\n";
	sbp->replyref (chordstat (CHORD_RPCFAILURE));
	return;
      }

      user_args *ua = New user_args (sbp, unmarshalled_args,
				     prog, arg->procno);
      vnodep->fill_user_args (ua);

      //call the handler
      if (!vnodep->progHandled (arg->progno)) {
	warn << "program not handled!\n";
	chordstat res = CHORD_NOHANDLER;
	sbp->replyref (res);
      } else {
	cbdispatch_t dispatch = vnodep->getHandler(arg->progno);
	(dispatch)(ua);
      }

    }
    break;
  default:
    fatal << "PROC not handled\n";
  }

}

<commit_msg>Make up initial coordinates for well-known node in the same manner as everything else instead of letting them come from uninitialized memory values.  If this chord object is the well-known node, then wait for first newvnode call to insert into locationtable.<commit_after>/*
 *
 * Copyright (C) 2000 Frans Kaashoek (kaashoek@lcs.mit.edu)
 * Copyright (C) 2001 Frans Kaashoek (kaashoek@lcs.mit.edu) and
 *                    Frank Dabek (fdabek@lcs.mit.edu).
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include "chord.h"
#include "chord_util.h"
#include "location.h"
#include "route.h"
#include "transport_prot.h"

int logbase;  // base = 2 ^ logbase

chord::chord (str _wellknownhost, int _wellknownport,
	      str _myname, int port, int max_cache,
	      int server_selection_mode,
	      int l_mode, int _logbase) :
  myname (_myname),
  ss_mode (server_selection_mode % 10),
  lookup_mode (l_mode),
  active (NULL)
{
  logbase = _logbase;
  myport = startchord (port);

  warnx << "chord: running on " << myname << ":" << myport << "\n";

  nrcv = New refcounted<u_int32_t>;
  *nrcv = 0;
  locations = New refcounted<locationtable> (nrcv, max_cache);

  wellknown_node.r.hostname = _wellknownhost;
  wellknown_node.r.port = _wellknownport ? _wellknownport : myport;
  wellknown_node.x = make_chordID (wellknown_node.r.hostname,
				   wellknown_node.r.port);
  wellknown_node.coords.setsize (NCOORDS);
  // Make up some random initial information for this other node.
  for (int i = 0; i < NCOORDS; i++)
    wellknown_node.coords[i] = (int) uniform_random_f (1000.0);

  if (myname != _wellknownhost || myport != _wellknownport) {
    bool ok = locations->insert (wellknown_node);
    if (!ok) {
      warn << "Well known host failed to verify! Bailing.\n";
      exit (0);
    }
  }

  nvnode = 0;
  srandom ((unsigned int) (getusec() & 0xFFFFFFFF));
}

void
chord::tcpclient_cb (int srvfd)
{
  int fd = accept (srvfd, NULL, NULL);
  if (fd < 0)
    warn << "chord: accept failed " << strerror (errno) << "\n";
  else {
    ptr<axprt> x = axprt_stream::alloc (fd, 230000);

    ptr<asrv> s = asrv::alloc (x, transport_program_1);
    s->setcb (wrap (mkref(this), &chord::dispatch, s));
  }
}

int
chord::startchord (int myp, int type)
{

  int srvfd = inetsocket (type, myp);
  if (srvfd < 0)
    fatal ("binding %s port %d: %m\n",
	   (type == SOCK_DGRAM ? "UDP" : "TCP"), myp);

  if (myp == 0) {
    struct sockaddr_in addr;
    socklen_t len = sizeof (addr);
    bzero (&addr, sizeof (addr));
    if (getsockname (srvfd, (sockaddr *) &addr, &len) < 0)
      fatal ("getsockname failed %m\n");
    myp = ntohs (addr.sin_port);
  }

  if (type == SOCK_DGRAM) {
    x_dgram = axprt_dgram::alloc (srvfd, sizeof(sockaddr), 230000);
    ptr<asrv> s = asrv::alloc (x_dgram, transport_program_1);
    s->setcb (wrap (mkref(this), &chord::dispatch, s));
  }
  else {
    int ret = listen (srvfd, 1000);
    assert (ret == 0);
    fdcb (srvfd, selread, wrap (this, &chord::tcpclient_cb, srvfd));
  }

  return myp;
}

int
chord::startchord (int myp)
{
  // see also locationtable constructor.
  if (chord_rpc_style == CHORD_RPC_SFST) {
    // Ensure the DGRAM and STREAM sockets are on same port #,
    // since it is included in the Chord ID's hash.
    myp = startchord (myp, SOCK_STREAM);
  }

  return startchord (myp, SOCK_DGRAM);
}

ptr<vnode>
chord::newvnode (cbjoin_t cb, ptr<fingerlike> fingers, ptr<route_factory> f)
{
  if (nvnode > max_vnodes)
    fatal << "Maximum number of vnodes (" << max_vnodes << ") reached.\n";

  chordID newID = init_chordID (nvnode, myname, myport);
  warn << "creating new vnode: " << newID << "\n";

  vec<float> coords;
  warn << gettime () << " coords are: ";
  for (int i = 0; i < NCOORDS; i++) {
    coords.push_back (uniform_random_f (1000.0));
    warnx << (int) coords[i] << " " ;
  }
  warnx << "\n";
  locations->insert (newID, myname, myport, coords);

#if 0
  if (newID != wellknown_node.x) {
    // It's not yet strictly speaking useful to other nodes yet.
    ///BAD LOC (ok)
    bool ok = locations->insert (newID, myname, myport);
    assert (ok);
  }
#endif /* 0 */

  ptr<vnode> vnodep = vnode::produce_vnode (locations, fingers, f,
					    mkref (this), newID,
					    nvnode, ss_mode,
					    lookup_mode);
  f->setvnode (vnodep);

  if (!active) active = vnodep;
  nvnode++;
  vnodes.insert (newID, vnodep);

  if (newID != wellknown_node.x) {
    vnodep->join (wellknown_node, cb);
  } else {
    vnodep->stabilize ();
    (*cb) (vnodep, CHORD_OK);
  }
  return vnodep;
}

void
chord::stats_cb (const chordID &k, ptr<vnode> v) {
  v->stats();
}

void
chord::stats ()
{
  warnx << "CHORD NODE STATS\n";
  warnx << "# vnodes: " << nvnode << "\n";
  vnodes.traverse (wrap (this, &chord::stats_cb));
  locations->stats ();
}

void
chord::print_cb (const chordID &k, ptr<vnode> v) {
  v->print ();
}

void
chord::print () {
  vnodes.traverse (wrap (this, &chord::print_cb));
}

void
chord::stop_cb (const chordID &k, ptr<vnode> v) {
  v->stop ();
}

void
chord::stop () {
  vnodes.traverse (wrap (this, &chord::stop_cb));
}

const rpc_program *
chord::get_program (int progno)
{
  for (unsigned int i = 0; i < handledProgs.size (); i++)
    if (progno == (int)handledProgs[i]->progno)
      return handledProgs[i];
  return NULL;
}

bool
chord::isHandled (int progno) {
  for (u_int i = 0; i < handledProgs.size (); i++)
    if (progno == (int)handledProgs[i]->progno) return true;
  return false;
}
void
chord::handleProgram (const rpc_program &prog) {
  warn << "chord::handleProgram: " << prog.progno << "\n";
  if (isHandled (prog.progno)) return;
  else {
    handledProgs.push_back (&prog);
  }
}

void
chord::dispatch (ptr<asrv> s, svccb *sbp)
{
  if (!sbp) {
    s->setcb (NULL);
    return;
  }
  (*nrcv)++;

  //autocache nodes
  dorpc_arg *arg = sbp->template getarg<dorpc_arg> ();
  if (arg && !locations->cached (arg->src_id)) {
    const sockaddr *sa = sbp->getsa ();
    net_address netaddr;
    netaddr.port = ((sockaddr_in *)sa)->sin_port;
    str addrstr (inet_ntoa (((sockaddr_in *)sa)->sin_addr));
    netaddr.hostname = addrstr;
    warn << "autocaching " << addrstr << ":" << netaddr.port << " in ::dispatch\n";
    vec<float> coords = convert_coords (arg);
    locations->insert (arg->src_id, netaddr.hostname, netaddr.port, coords);
  }

  switch (sbp->proc ()) {
  case TRANSPORTPROC_NULL:
    {
      sbp->reply (NULL);
      break;
    }
  case TRANSPORTPROC_DORPC:
    {
      //v (the destination chordID) is at the top of the header
      chordID *v = sbp->template getarg<chordID> ();
      vnode *vnodep = vnodes[*v];
      if (!vnodep) {
	warnx << "CHORD: unknown node processing procedure " << sbp->proc ()
	      << " request " << *v << "\n";
	sbp->replyref (chordstat (CHORD_UNKNOWNNODE));
	return;
      }

      //find the program
      const rpc_program *prog = get_program (arg->progno);
      if (!prog)
	fatal << "bad prog: " << arg->progno << "\n";

      //unmarshall the args
      char *arg_base = (char *)(arg->args.base ());
      int arg_len = arg->args.size ();

      xdrmem x (arg_base, arg_len, XDR_DECODE);
      xdrproc_t proc = prog->tbl[arg->procno].xdr_arg;
      assert (proc);

      void *unmarshalled_args = prog->tbl[arg->procno].alloc_arg ();
      if (!proc (x.xdrp (), unmarshalled_args)) {
	warn << "dispatch: error unmarshalling arguments\n";
	sbp->replyref (chordstat (CHORD_RPCFAILURE));
	return;
      }

      user_args *ua = New user_args (sbp, unmarshalled_args,
				     prog, arg->procno);
      vnodep->fill_user_args (ua);

      //call the handler
      if (!vnodep->progHandled (arg->progno)) {
	warn << "program not handled!\n";
	chordstat res = CHORD_NOHANDLER;
	sbp->replyref (res);
      } else {
	cbdispatch_t dispatch = vnodep->getHandler(arg->progno);
	(dispatch)(ua);
      }

    }
    break;
  default:
    fatal << "PROC not handled\n";
  }

}

<|endoftext|>


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

#ifndef PCL_PCA_IMPL_HPP
#define PCL_PCA_IMPL_HPP

#include <Eigen/Eigenvalues>
#include "pcl/point_types.h"
#include "pcl/common/centroid.h"
#include "pcl/common/transforms.h"
#include "pcl/exceptions.h"

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT>
pcl::PCA<PointT>::PCA (const pcl::PointCloud<PointT>& X, bool basis_only)
{
  Base ();
  basis_only_ = basis_only;
  setInputCloud (X.makeShared ());
  compute_done_ = initCompute ();
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> bool
pcl::PCA<PointT>::initCompute ()
{
  if(!Base::initCompute ())
  {
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::initCompute] failed");
    return (false);
  }
  if(indices_->size () < 3)
  {
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::initCompute] number of points < 3");
    return (false);
  }

  // Compute mean
  mean_ = Eigen::Vector4f::Zero ();
  compute3DCentroid (*input_, *indices_, mean_);
  // Compute demeanished cloud
  Eigen::MatrixXf cloud_demean;
  demeanPointCloud (*input_, *indices_, mean_, cloud_demean);
  assert (cloud_demean.cols () == int (indices_->size ()));
  // Compute the product cloud_demean * cloud_demean^T
  Eigen::Matrix3f alpha = cloud_demean.topRows<3> () * cloud_demean.topRows<3> ().transpose ();

  // Compute eigen vectors and values
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> evd (alpha);
  // Organize eigenvectors and eigenvalues in ascendent order
  for (int i = 0; i < 3; ++i)
  {
    eigenvalues_[i] = evd.eigenvalues () [2-i];
    eigenvectors_.col (i) = evd.eigenvectors ().col (2-i);
  }
  // If not basis only then compute the coefficients

  if (!basis_only_)
    // 3x3 = 3x3 * 3x3
    coefficients_ = eigenvectors_.transpose() * (cloud_demean.topRows<3>()).leftCols<3> ();
  compute_done_ = true;
  return (true);
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::update (const PointT& input_point, FLAG flag)
{
  if (!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::update] PCA initCompute failed");

  Eigen::Vector3f input (input_point.x, input_point.y, input_point.z);
  const size_t n = eigenvectors_.cols ();// number of eigen vectors
  Eigen::VectorXf meanp = (float(n) * (mean_.head<3>() + input)) / float(n + 1);
  Eigen::VectorXf a = eigenvectors_.transpose() * (input - mean_.head<3>());
  Eigen::VectorXf y = (eigenvectors_ * a) + mean_.head<3>();
  Eigen::VectorXf h = y - input;
  if (h.norm() > 0)
    h.normalize ();
  else
    h.setZero ();
  float gamma = h.dot(input - mean_.head<3>());
  Eigen::MatrixXf D = Eigen::MatrixXf::Zero (a.size() + 1, a.size() + 1);
  D.block(0,0,n,n) = a * a.transpose();
  D /=  float(n)/float((n+1) * (n+1));
  for(std::size_t i=0; i < a.size(); i++) {
    D(i,i)+= float(n)/float(n+1)*eigenvalues_(i);
    D(D.rows()-1,i) = float(n) / float((n+1) * (n+1)) * gamma * a(i);
    D(i,D.cols()-1) = D(D.rows()-1,i);
    D(D.rows()-1,D.cols()-1) = float(n)/float((n+1) * (n+1)) * gamma * gamma;
  }

  Eigen::MatrixXf R(D.rows(), D.cols());
  Eigen::EigenSolver<Eigen::MatrixXf> D_evd (D, false);
  Eigen::VectorXf alphap = D_evd.eigenvalues().real();
  eigenvalues_.resize(eigenvalues_.size() +1);
  for(std::size_t i=0;i<eigenvalues_.size();i++) {
    eigenvalues_(i) = alphap(eigenvalues_.size()-i-1);
    R.col(i) = D.col(D.cols()-i-1);
  }
  Eigen::MatrixXf Up = Eigen::MatrixXf::Zero(eigenvectors_.rows(), eigenvectors_.cols()+1);
  Up.topLeftCorner(eigenvectors_.rows(),eigenvectors_.cols()) = eigenvectors_;
  Up.rightCols<1>() = h;
  eigenvectors_ = Up*R;
  if (!basis_only_) {
    Eigen::Vector3f etha = Up.transpose() * (mean_.head<3>() - meanp);
    coefficients_.resize(coefficients_.rows()+1,coefficients_.cols()+1);
    for(std::size_t i=0; i < (coefficients_.cols() - 1); i++) {
      coefficients_(coefficients_.rows()-1,i) = 0;
      coefficients_.col(i) = (R.transpose() * coefficients_.col(i)) + etha;
    }
    a.resize(a.size()+1);
    a(a.size()-1) = 0;
    coefficients_.col(coefficients_.cols()-1) = (R.transpose() * a) + etha;
  }
  mean_.head<3>() = meanp;
  switch (flag)
  {
    case increase:
      if (eigenvectors_.rows() >= eigenvectors_.cols())
        break;
    case preserve:
      if (!basis_only_)
        coefficients_ = coefficients_.topRows(coefficients_.rows() - 1);
      eigenvectors_ = eigenvectors_.leftCols(eigenvectors_.cols() - 1);
      eigenvalues_.resize(eigenvalues_.size()-1);
      break;
    default:
      PCL_ERROR("[pcl::PCA] unknown flag\n");
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::project (const PointT& input, PointT& projection)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::project] PCA initCompute failed");

  Eigen::Vector3f demean_input = input.getVector3fMap () - mean_.head<3> ();
  projection.getVector3fMap () = eigenvectors_.transpose() * demean_input;
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::project (const PointCloud& input, PointCloud& projection)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::project] PCA initCompute failed");
  if (input.is_dense)
  {
    projection.resize (input.size ());
    for (size_t i = 0; i < input.size (); ++i)
      project (input[i], projection[i]);
  }
  else
  {
    PointT p;
    for (size_t i = 0; i < input.size (); ++i)
    {
      if (!pcl_isfinite (input[i].x) ||
          !pcl_isfinite (input[i].y) ||
          !pcl_isfinite (input[i].z))
        continue;
      project (input[i], p);
      projection.push_back (p);
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::reconstruct (const PointT& projection, PointT& input)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::reconstruct] PCA initCompute failed");

  input.getVector3fMap ()= eigenvectors_ * projection.getVector3fMap ();
  input.getVector3fMap ()+= mean_.head<3> ();
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::reconstruct (const PointCloud& projection, PointCloud& input)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::reconstruct] PCA initCompute failed");
  if (input.is_dense)
  {
    input.resize (projection.size ());
    for (size_t i = 0; i < projection.size (); ++i)
      reconstruct (projection[i], input[i]);
  }
  else
  {
    PointT p;
    for (size_t i = 0; i < input.size (); ++i)
    {
      if (!pcl_isfinite (input[i].x) ||
          !pcl_isfinite (input[i].y) ||
          !pcl_isfinite (input[i].z))
        continue;
      reconstruct (projection[i], p);
      input.push_back (p);
    }
  }
}

#endif
<commit_msg>Correct coeffcients formula<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */

#ifndef PCL_PCA_IMPL_HPP
#define PCL_PCA_IMPL_HPP

#include <Eigen/Eigenvalues>
#include "pcl/point_types.h"
#include "pcl/common/centroid.h"
#include "pcl/common/transforms.h"
#include "pcl/exceptions.h"

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT>
pcl::PCA<PointT>::PCA (const pcl::PointCloud<PointT>& X, bool basis_only)
{
  Base ();
  basis_only_ = basis_only;
  setInputCloud (X.makeShared ());
  compute_done_ = initCompute ();
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> bool
pcl::PCA<PointT>::initCompute ()
{
  if(!Base::initCompute ())
  {
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::initCompute] failed");
    return (false);
  }
  if(indices_->size () < 3)
  {
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::initCompute] number of points < 3");
    return (false);
  }

  // Compute mean
  mean_ = Eigen::Vector4f::Zero ();
  compute3DCentroid (*input_, *indices_, mean_);
  // Compute demeanished cloud
  Eigen::MatrixXf cloud_demean;
  demeanPointCloud (*input_, *indices_, mean_, cloud_demean);
  assert (cloud_demean.cols () == int (indices_->size ()));
  // Compute the product cloud_demean * cloud_demean^T
  Eigen::Matrix3f alpha = cloud_demean.topRows<3> () * cloud_demean.topRows<3> ().transpose ();

  // Compute eigen vectors and values
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> evd (alpha);
  // Organize eigenvectors and eigenvalues in ascendent order
  for (int i = 0; i < 3; ++i)
  {
    eigenvalues_[i] = evd.eigenvalues () [2-i];
    eigenvectors_.col (i) = evd.eigenvectors ().col (2-i);
  }
  // If not basis only then compute the coefficients

  if (!basis_only_)
    coefficients_ = eigenvectors_.transpose() * cloud_demean.topRows<3> ();
  compute_done_ = true;
  return (true);
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::update (const PointT& input_point, FLAG flag)
{
  if (!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::update] PCA initCompute failed");

  Eigen::Vector3f input (input_point.x, input_point.y, input_point.z);
  const size_t n = eigenvectors_.cols ();// number of eigen vectors
  Eigen::VectorXf meanp = (float(n) * (mean_.head<3>() + input)) / float(n + 1);
  Eigen::VectorXf a = eigenvectors_.transpose() * (input - mean_.head<3>());
  Eigen::VectorXf y = (eigenvectors_ * a) + mean_.head<3>();
  Eigen::VectorXf h = y - input;
  if (h.norm() > 0)
    h.normalize ();
  else
    h.setZero ();
  float gamma = h.dot(input - mean_.head<3>());
  Eigen::MatrixXf D = Eigen::MatrixXf::Zero (a.size() + 1, a.size() + 1);
  D.block(0,0,n,n) = a * a.transpose();
  D /=  float(n)/float((n+1) * (n+1));
  for(std::size_t i=0; i < a.size(); i++) {
    D(i,i)+= float(n)/float(n+1)*eigenvalues_(i);
    D(D.rows()-1,i) = float(n) / float((n+1) * (n+1)) * gamma * a(i);
    D(i,D.cols()-1) = D(D.rows()-1,i);
    D(D.rows()-1,D.cols()-1) = float(n)/float((n+1) * (n+1)) * gamma * gamma;
  }

  Eigen::MatrixXf R(D.rows(), D.cols());
  Eigen::EigenSolver<Eigen::MatrixXf> D_evd (D, false);
  Eigen::VectorXf alphap = D_evd.eigenvalues().real();
  eigenvalues_.resize(eigenvalues_.size() +1);
  for(std::size_t i=0;i<eigenvalues_.size();i++) {
    eigenvalues_(i) = alphap(eigenvalues_.size()-i-1);
    R.col(i) = D.col(D.cols()-i-1);
  }
  Eigen::MatrixXf Up = Eigen::MatrixXf::Zero(eigenvectors_.rows(), eigenvectors_.cols()+1);
  Up.topLeftCorner(eigenvectors_.rows(),eigenvectors_.cols()) = eigenvectors_;
  Up.rightCols<1>() = h;
  eigenvectors_ = Up*R;
  if (!basis_only_) {
    Eigen::Vector3f etha = Up.transpose() * (mean_.head<3>() - meanp);
    coefficients_.resize(coefficients_.rows()+1,coefficients_.cols()+1);
    for(std::size_t i=0; i < (coefficients_.cols() - 1); i++) {
      coefficients_(coefficients_.rows()-1,i) = 0;
      coefficients_.col(i) = (R.transpose() * coefficients_.col(i)) + etha;
    }
    a.resize(a.size()+1);
    a(a.size()-1) = 0;
    coefficients_.col(coefficients_.cols()-1) = (R.transpose() * a) + etha;
  }
  mean_.head<3>() = meanp;
  switch (flag)
  {
    case increase:
      if (eigenvectors_.rows() >= eigenvectors_.cols())
        break;
    case preserve:
      if (!basis_only_)
        coefficients_ = coefficients_.topRows(coefficients_.rows() - 1);
      eigenvectors_ = eigenvectors_.leftCols(eigenvectors_.cols() - 1);
      eigenvalues_.resize(eigenvalues_.size()-1);
      break;
    default:
      PCL_ERROR("[pcl::PCA] unknown flag\n");
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::project (const PointT& input, PointT& projection)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::project] PCA initCompute failed");

  Eigen::Vector3f demean_input = input.getVector3fMap () - mean_.head<3> ();
  projection.getVector3fMap () = eigenvectors_.transpose() * demean_input;
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::project (const PointCloud& input, PointCloud& projection)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::project] PCA initCompute failed");
  if (input.is_dense)
  {
    projection.resize (input.size ());
    for (size_t i = 0; i < input.size (); ++i)
      project (input[i], projection[i]);
  }
  else
  {
    PointT p;
    for (size_t i = 0; i < input.size (); ++i)
    {
      if (!pcl_isfinite (input[i].x) ||
          !pcl_isfinite (input[i].y) ||
          !pcl_isfinite (input[i].z))
        continue;
      project (input[i], p);
      projection.push_back (p);
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::reconstruct (const PointT& projection, PointT& input)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::reconstruct] PCA initCompute failed");

  input.getVector3fMap ()= eigenvectors_ * projection.getVector3fMap ();
  input.getVector3fMap ()+= mean_.head<3> ();
}

/////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> inline void
pcl::PCA<PointT>::reconstruct (const PointCloud& projection, PointCloud& input)
{
  if(!compute_done_)
    initCompute ();
  if (!compute_done_)
    PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::reconstruct] PCA initCompute failed");
  if (input.is_dense)
  {
    input.resize (projection.size ());
    for (size_t i = 0; i < projection.size (); ++i)
      reconstruct (projection[i], input[i]);
  }
  else
  {
    PointT p;
    for (size_t i = 0; i < input.size (); ++i)
    {
      if (!pcl_isfinite (input[i].x) ||
          !pcl_isfinite (input[i].y) ||
          !pcl_isfinite (input[i].z))
        continue;
      reconstruct (projection[i], p);
      input.push_back (p);
    }
  }
}

#endif
<|endoftext|>


<commit_before>#include "fetcher/peer_group.h"

#include <glog/logging.h>

using std::lock_guard;
using std::max;
using std::mutex;
using std::placeholders::_1;
using std::shared_ptr;
using std::vector;
using util::Status;
using util::Task;

namespace cert_trans {

namespace {

void GetEntriesDone(AsyncLogClient::Status client_status,
                    const vector<AsyncLogClient::Entry>* entries, Task* task) {
  Status status;

  switch (client_status) {
    case AsyncLogClient::OK:
      break;

    default:
      // TODO(pphaneuf): Improve this a bit? Or wouldn't it be nice if
      // AsyncLogClient gave us a util::Status in the first place? ;-)
      status = util::Status::UNKNOWN;
  }

  if (status.ok() && entries->empty()) {
    // This should never happen.
    status =
        Status(util::error::INTERNAL, "log server did not return any entries");
  }

  task->Return(status);
}

}  // namespace

void PeerGroup::Add(const shared_ptr<Peer>& peer) {
  lock_guard<mutex> lock(lock_);

  CHECK(peers_.emplace(peer, PeerState()).second);
}

int64_t PeerGroup::TreeSize() const {
  lock_guard<mutex> lock(lock_);

  int64_t tree_size(-1);
  for (const auto& peer : peers_) {
    tree_size = max(tree_size, peer.first->TreeSize());
  }

  return tree_size;
}

void PeerGroup::FetchEntries(int64_t start_index, int64_t end_index,
                             vector<AsyncLogClient::Entry>* entries,
                             Task* task) {
  CHECK_GE(start_index, 0);
  CHECK_GE(end_index, start_index);

  const shared_ptr<Peer> peer(PickPeer(end_index + 1));
  CHECK(peer);

  // TODO(pphaneuf): Handle the case where we have no peer more cleanly.
  peer->client().GetEntries(start_index, end_index, CHECK_NOTNULL(entries),
                            bind(GetEntriesDone, _1, entries, task));
}

shared_ptr<Peer> PeerGroup::PickPeer(const int64_t needed_size) const {
  lock_guard<mutex> lock(lock_);

  // TODO(pphaneuf): We should pick peers a bit more cleverly, to
  // spread the load somewhat.
  for (const auto& peer : peers_) {
    if (peer.first->TreeSize() >= needed_size) {
      return peer.first;
    }
  }

  return nullptr;
}

}  // namespace cert_trans
<commit_msg>Do not crash when a peer group doesn't have enough entries.<commit_after>#include "fetcher/peer_group.h"

#include <glog/logging.h>

using std::lock_guard;
using std::max;
using std::mutex;
using std::placeholders::_1;
using std::shared_ptr;
using std::vector;
using util::Status;
using util::Task;

namespace cert_trans {

namespace {

void GetEntriesDone(AsyncLogClient::Status client_status,
                    const vector<AsyncLogClient::Entry>* entries, Task* task) {
  Status status;

  switch (client_status) {
    case AsyncLogClient::OK:
      break;

    default:
      // TODO(pphaneuf): Improve this a bit? Or wouldn't it be nice if
      // AsyncLogClient gave us a util::Status in the first place? ;-)
      status = util::Status::UNKNOWN;
  }

  if (status.ok() && entries->empty()) {
    // This should never happen.
    status =
        Status(util::error::INTERNAL, "log server did not return any entries");
  }

  task->Return(status);
}

}  // namespace

void PeerGroup::Add(const shared_ptr<Peer>& peer) {
  lock_guard<mutex> lock(lock_);

  CHECK(peers_.emplace(peer, PeerState()).second);
}

int64_t PeerGroup::TreeSize() const {
  lock_guard<mutex> lock(lock_);

  int64_t tree_size(-1);
  for (const auto& peer : peers_) {
    tree_size = max(tree_size, peer.first->TreeSize());
  }

  return tree_size;
}

void PeerGroup::FetchEntries(int64_t start_index, int64_t end_index,
                             vector<AsyncLogClient::Entry>* entries,
                             Task* task) {
  CHECK_GE(start_index, 0);
  CHECK_GE(end_index, start_index);

  const shared_ptr<Peer> peer(PickPeer(end_index + 1));
  if (!peer) {
    task->Return(Status(util::error::UNAVAILABLE,
                        "requested entries not available in the peer group"));
    return;
  }

  // TODO(pphaneuf): Handle the case where we have no peer more cleanly.
  peer->client().GetEntries(start_index, end_index, CHECK_NOTNULL(entries),
                            bind(GetEntriesDone, _1, entries, task));
}

shared_ptr<Peer> PeerGroup::PickPeer(const int64_t needed_size) const {
  lock_guard<mutex> lock(lock_);

  // TODO(pphaneuf): We should pick peers a bit more cleverly, to
  // spread the load somewhat.
  int64_t group_tree_size(-1);
  for (const auto& peer : peers_) {
    const int64_t tree_size(peer.first->TreeSize());
    group_tree_size = max(group_tree_size, tree_size);
    if (tree_size >= needed_size) {
      return peer.first;
    }
  }

  LOG(INFO) << "requested a peer with " << needed_size
            << " entries but the peer group only has " << group_tree_size
            << " entries";

  return nullptr;
}

}  // namespace cert_trans
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2017, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include <wangle/ssl/SSLUtil.h>

#include <folly/Memory.h>

#if OPENSSL_VERSION_NUMBER >= 0x1000105fL
#define OPENSSL_GE_101 1
#include <openssl/asn1.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h>
#else
#undef OPENSSL_GE_101
#endif

namespace wangle {

std::mutex SSLUtil::sIndexLock_;

std::unique_ptr<std::string> SSLUtil::getCommonName(const X509* cert) {
  X509_NAME* subject = X509_get_subject_name((X509*)cert);
  if (!subject) {
    return nullptr;
  }
  char cn[ub_common_name + 1];
  int res = X509_NAME_get_text_by_NID(subject, NID_commonName,
                                      cn, ub_common_name);
  if (res <= 0) {
    return nullptr;
  } else {
    cn[ub_common_name] = '\0';
    return folly::make_unique<std::string>(cn);
  }
}

std::unique_ptr<std::list<std::string>> SSLUtil::getSubjectAltName(
    const X509* cert) {
#ifdef OPENSSL_GE_101
  auto nameList = folly::make_unique<std::list<std::string>>();
  GENERAL_NAMES* names = (GENERAL_NAMES*)X509_get_ext_d2i(
      (X509*)cert, NID_subject_alt_name, nullptr, nullptr);
  if (names) {
    auto guard = folly::makeGuard([names] { GENERAL_NAMES_free(names); });
    size_t count = sk_GENERAL_NAME_num(names);
    CHECK(count < std::numeric_limits<int>::max());
    for (int i = 0; i < (int)count; ++i) {
      GENERAL_NAME* generalName = sk_GENERAL_NAME_value(names, i);
      if (generalName->type == GEN_DNS) {
        ASN1_STRING* s = generalName->d.dNSName;
        const char* name = (const char*)ASN1_STRING_data(s);
        // I can't find any docs on what a negative return value here
        // would mean, so I'm going to ignore it.
        auto len = ASN1_STRING_length(s);
        DCHECK(len >= 0);
        if (size_t(len) != strlen(name)) {
          // Null byte(s) in the name; return an error rather than depending on
          // the caller to safely handle this case.
          return nullptr;
        }
        nameList->emplace_back(name);
      }
    }
  }
  return nameList;
#else
  return nullptr;
#endif
}

folly::ssl::X509UniquePtr SSLUtil::getX509FromCertificate(
    const std::string& certificateData) {
  // BIO_new_mem_buf creates a bio pointing to a read-only buffer
  folly::ssl::BioUniquePtr bio(
    BIO_new_mem_buf((const void*)certificateData.data(),
                    certificateData.length()));
  if (!bio) {
    throw std::runtime_error("Cannot create mem BIO");
  }

  auto x509 = folly::ssl::X509UniquePtr(
      PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
  if (!x509) {
    throw std::runtime_error("Cannot read X509 from PEM bio");
  }
  return x509;
}

} // namespace wangle
<commit_msg>Fix build for OpenSSL versions older than 1.0.2g<commit_after>/*
 *  Copyright (c) 2017, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include <wangle/ssl/SSLUtil.h>

#include <folly/Memory.h>

#if OPENSSL_VERSION_NUMBER >= 0x1000105fL
#define OPENSSL_GE_101 1
#include <openssl/asn1.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h>
#else
#undef OPENSSL_GE_101
#endif

namespace wangle {

std::mutex SSLUtil::sIndexLock_;

std::unique_ptr<std::string> SSLUtil::getCommonName(const X509* cert) {
  X509_NAME* subject = X509_get_subject_name((X509*)cert);
  if (!subject) {
    return nullptr;
  }
  char cn[ub_common_name + 1];
  int res = X509_NAME_get_text_by_NID(subject, NID_commonName,
                                      cn, ub_common_name);
  if (res <= 0) {
    return nullptr;
  } else {
    cn[ub_common_name] = '\0';
    return folly::make_unique<std::string>(cn);
  }
}

std::unique_ptr<std::list<std::string>> SSLUtil::getSubjectAltName(
    const X509* cert) {
#ifdef OPENSSL_GE_101
  auto nameList = folly::make_unique<std::list<std::string>>();
  GENERAL_NAMES* names = (GENERAL_NAMES*)X509_get_ext_d2i(
      (X509*)cert, NID_subject_alt_name, nullptr, nullptr);
  if (names) {
    auto guard = folly::makeGuard([names] { GENERAL_NAMES_free(names); });
    size_t count = sk_GENERAL_NAME_num(names);
    CHECK(count < std::numeric_limits<int>::max());
    for (int i = 0; i < (int)count; ++i) {
      GENERAL_NAME* generalName = sk_GENERAL_NAME_value(names, i);
      if (generalName->type == GEN_DNS) {
        ASN1_STRING* s = generalName->d.dNSName;
        const char* name = (const char*)ASN1_STRING_data(s);
        // I can't find any docs on what a negative return value here
        // would mean, so I'm going to ignore it.
        auto len = ASN1_STRING_length(s);
        DCHECK(len >= 0);
        if (size_t(len) != strlen(name)) {
          // Null byte(s) in the name; return an error rather than depending on
          // the caller to safely handle this case.
          return nullptr;
        }
        nameList->emplace_back(name);
      }
    }
  }
  return nameList;
#else
  return nullptr;
#endif
}

folly::ssl::X509UniquePtr SSLUtil::getX509FromCertificate(
    const std::string& certificateData) {
  // BIO_new_mem_buf creates a bio pointing to a read-only buffer. However,
  // older versions of OpenSSL fail to mark the first argument `const`.
  folly::ssl::BioUniquePtr bio(
    BIO_new_mem_buf((void*)certificateData.data(), certificateData.length()));
  if (!bio) {
    throw std::runtime_error("Cannot create mem BIO");
  }

  auto x509 = folly::ssl::X509UniquePtr(
      PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
  if (!x509) {
    throw std::runtime_error("Cannot read X509 from PEM bio");
  }
  return x509;
}

} // namespace wangle
<|endoftext|>


<commit_before>#include "fixie_lib/desktop_gl_impl/framebuffer.hpp"
#include "fixie_lib/desktop_gl_impl/texture.hpp"
#include "fixie_lib/desktop_gl_impl/renderbuffer.hpp"
#include "fixie_lib/debug.hpp"

namespace fixie
{
    #define GL_FRAMEBUFFER 0x8D40
    #define GL_RENDERBUFFER 0x8D41
    #define GL_READ_FRAMEBUFFER 0x8CA8
    #define GL_DRAW_FRAMEBUFFER 0x8CA9
    #define GL_COLOR_ATTACHMENT0 0x8CE0
    #define GL_DEPTH_ATTACHMENT 0x8D00
    #define GL_STENCIL_ATTACHMENT 0x8D20

    #define GL_FRAMEBUFFER_COMPLETE 0x8CD5

    #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
    #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B

    namespace desktop_gl_impl
    {
        framebuffer::framebuffer(std::shared_ptr<const gl_functions> functions)
            : _functions(functions)
            , _id(0)
        {
            gl_call(_functions, gen_framebuffers, 1, &_id);
        }

        framebuffer::framebuffer(GLuint id, std::shared_ptr<const gl_functions> functions)
            : _functions(functions)
            , _id(id)
        {
        }

        framebuffer::~framebuffer()
        {
            if (_id)
            {
                gl_call_nothrow(_functions, delete_framebuffers, 1, &_id);
            }
        }

        GLuint framebuffer::id() const
        {
            return _id;
        }

        static void set_framebuffer_attachment(std::shared_ptr<const gl_functions> functions, GLuint framebuffer,
                                               GLenum attachment_point, const framebuffer_attachment& attachment)
        {
            if (framebuffer != 0)
            {
                gl_call(functions, bind_framebuffer, GL_FRAMEBUFFER, framebuffer);
                if (attachment.is_texture())
                {
                    std::shared_ptr<const fixie::texture> texture = attachment.texture().lock();
                    std::shared_ptr<const desktop_gl_impl::texture> texture_impl = texture ? std::dynamic_pointer_cast<const desktop_gl_impl::texture>(texture->impl().lock()) : nullptr;
                    GLuint id = texture_impl ? texture_impl->id() : 0;
                    if (attachment.texture_samples() > 1)
                    {
                        gl_call(functions, framebuffer_texture_2d, GL_FRAMEBUFFER, attachment_point, GL_TEXTURE_2D, id, attachment.texture_level());
                    }
                    else
                    {
                        gl_call(functions, framebuffer_texture_2d_multisample, GL_FRAMEBUFFER, attachment_point, GL_TEXTURE_2D, id, attachment.texture_level(), attachment.texture_samples());
                    }
                }
                else if (attachment.is_renderbuffer())
                {
                    std::shared_ptr<const fixie::renderbuffer> renderbuffer = attachment.renderbuffer().lock();
                    std::shared_ptr<const desktop_gl_impl::renderbuffer> renderbuffer_impl = renderbuffer ? std::dynamic_pointer_cast<const desktop_gl_impl::renderbuffer>(renderbuffer->impl().lock()) : nullptr;
                    GLuint id = renderbuffer_impl ? renderbuffer_impl->id() : 0;
                    gl_call(functions, framebuffer_renderbuffer, GL_FRAMEBUFFER, attachment_point, GL_RENDERBUFFER, id);
                }
                else
                {
                    assert(!attachment.is_bound());
                    gl_call(functions, framebuffer_texture_2d, GL_FRAMEBUFFER, attachment_point, GL_TEXTURE_2D, 0, 0);
                }
            }
        }

        void framebuffer::set_color_attachment(const framebuffer_attachment& attachment)
        {
            set_framebuffer_attachment(_functions, _id, GL_COLOR_ATTACHMENT0, attachment);
        }

        void framebuffer::set_depth_attachment(const framebuffer_attachment& attachment)
        {
            set_framebuffer_attachment(_functions, _id, GL_DEPTH_ATTACHMENT, attachment);
        }

        void framebuffer::set_stencil_attachment(const framebuffer_attachment& attachment)
        {
            set_framebuffer_attachment(_functions, _id, GL_STENCIL_ATTACHMENT, attachment);
        }

        GLenum framebuffer::preferred_read_format() const
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);

            GLint read_format;
            gl_call(_functions, get_integer_v, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &read_format);
            return static_cast<GLenum>(read_format);
        }

        GLenum framebuffer::preferred_read_type() const
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);

            GLint read_type;
            gl_call(_functions, get_integer_v, GL_IMPLEMENTATION_COLOR_READ_TYPE, &read_type);
            return static_cast<GLenum>(read_type);
        }

        void framebuffer::read_pixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* data)
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);
            gl_call(_functions, read_pixels, x, y, width, height, format, type, data);
        }

        GLenum framebuffer::status() const
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);
            GLenum status = gl_call(_functions, check_framebuffer_status, GL_FRAMEBUFFER);
            return status;
        }

        default_framebuffer::default_framebuffer(std::shared_ptr<const gl_functions> functions)
            : framebuffer(0, functions)
        {
        }

        GLenum default_framebuffer::status() const
        {
            return GL_FRAMEBUFFER_COMPLETE;
        }
    }
}
<commit_msg>Fixed a bug where multisampled renderbuffers are created when samples is 1.<commit_after>#include "fixie_lib/desktop_gl_impl/framebuffer.hpp"
#include "fixie_lib/desktop_gl_impl/texture.hpp"
#include "fixie_lib/desktop_gl_impl/renderbuffer.hpp"
#include "fixie_lib/debug.hpp"

namespace fixie
{
    #define GL_FRAMEBUFFER 0x8D40
    #define GL_RENDERBUFFER 0x8D41
    #define GL_READ_FRAMEBUFFER 0x8CA8
    #define GL_DRAW_FRAMEBUFFER 0x8CA9
    #define GL_COLOR_ATTACHMENT0 0x8CE0
    #define GL_DEPTH_ATTACHMENT 0x8D00
    #define GL_STENCIL_ATTACHMENT 0x8D20

    #define GL_FRAMEBUFFER_COMPLETE 0x8CD5

    #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
    #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B

    namespace desktop_gl_impl
    {
        framebuffer::framebuffer(std::shared_ptr<const gl_functions> functions)
            : _functions(functions)
            , _id(0)
        {
            gl_call(_functions, gen_framebuffers, 1, &_id);
        }

        framebuffer::framebuffer(GLuint id, std::shared_ptr<const gl_functions> functions)
            : _functions(functions)
            , _id(id)
        {
        }

        framebuffer::~framebuffer()
        {
            if (_id)
            {
                gl_call_nothrow(_functions, delete_framebuffers, 1, &_id);
            }
        }

        GLuint framebuffer::id() const
        {
            return _id;
        }

        static void set_framebuffer_attachment(std::shared_ptr<const gl_functions> functions, GLuint framebuffer,
                                               GLenum attachment_point, const framebuffer_attachment& attachment)
        {
            if (framebuffer != 0)
            {
                gl_call(functions, bind_framebuffer, GL_FRAMEBUFFER, framebuffer);
                if (attachment.is_texture())
                {
                    std::shared_ptr<const fixie::texture> texture = attachment.texture().lock();
                    std::shared_ptr<const desktop_gl_impl::texture> texture_impl = texture ? std::dynamic_pointer_cast<const desktop_gl_impl::texture>(texture->impl().lock()) : nullptr;
                    GLuint id = texture_impl ? texture_impl->id() : 0;
                    if (attachment.texture_samples() > 1)
                    {
                        gl_call(functions, framebuffer_texture_2d_multisample, GL_FRAMEBUFFER, attachment_point, GL_TEXTURE_2D, id, attachment.texture_level(), attachment.texture_samples());
                    }
                    else
                    {
                        gl_call(functions, framebuffer_texture_2d, GL_FRAMEBUFFER, attachment_point, GL_TEXTURE_2D, id, attachment.texture_level());
                    }
                }
                else if (attachment.is_renderbuffer())
                {
                    std::shared_ptr<const fixie::renderbuffer> renderbuffer = attachment.renderbuffer().lock();
                    std::shared_ptr<const desktop_gl_impl::renderbuffer> renderbuffer_impl = renderbuffer ? std::dynamic_pointer_cast<const desktop_gl_impl::renderbuffer>(renderbuffer->impl().lock()) : nullptr;
                    GLuint id = renderbuffer_impl ? renderbuffer_impl->id() : 0;
                    gl_call(functions, framebuffer_renderbuffer, GL_FRAMEBUFFER, attachment_point, GL_RENDERBUFFER, id);
                }
                else
                {
                    assert(!attachment.is_bound());
                    gl_call(functions, framebuffer_texture_2d, GL_FRAMEBUFFER, attachment_point, GL_TEXTURE_2D, 0, 0);
                }
            }
        }

        void framebuffer::set_color_attachment(const framebuffer_attachment& attachment)
        {
            set_framebuffer_attachment(_functions, _id, GL_COLOR_ATTACHMENT0, attachment);
        }

        void framebuffer::set_depth_attachment(const framebuffer_attachment& attachment)
        {
            set_framebuffer_attachment(_functions, _id, GL_DEPTH_ATTACHMENT, attachment);
        }

        void framebuffer::set_stencil_attachment(const framebuffer_attachment& attachment)
        {
            set_framebuffer_attachment(_functions, _id, GL_STENCIL_ATTACHMENT, attachment);
        }

        GLenum framebuffer::preferred_read_format() const
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);

            GLint read_format;
            gl_call(_functions, get_integer_v, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &read_format);
            return static_cast<GLenum>(read_format);
        }

        GLenum framebuffer::preferred_read_type() const
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);

            GLint read_type;
            gl_call(_functions, get_integer_v, GL_IMPLEMENTATION_COLOR_READ_TYPE, &read_type);
            return static_cast<GLenum>(read_type);
        }

        void framebuffer::read_pixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* data)
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);
            gl_call(_functions, read_pixels, x, y, width, height, format, type, data);
        }

        GLenum framebuffer::status() const
        {
            gl_call(_functions, bind_framebuffer, GL_FRAMEBUFFER, _id);
            GLenum status = gl_call(_functions, check_framebuffer_status, GL_FRAMEBUFFER);
            return status;
        }

        default_framebuffer::default_framebuffer(std::shared_ptr<const gl_functions> functions)
            : framebuffer(0, functions)
        {
        }

        GLenum default_framebuffer::status() const
        {
            return GL_FRAMEBUFFER_COMPLETE;
        }
    }
}
<|endoftext|>


<commit_before>#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/io.hpp"
#include <cstring>
#include <asio/read.hpp>
#include <asio/write.hpp>
#include <boost/bind.hpp>

using namespace libtorrent;

int read_message(stream_socket& s, char* buffer)
{
	using namespace libtorrent::detail;
	asio::error_code ec;
	asio::read(s, asio::buffer(buffer, 4), asio::transfer_all(), ec);
	TEST_CHECK(!ec);
	char* ptr = buffer;
	int length = read_int32(ptr);

	asio::read(s, asio::buffer(buffer, length), asio::transfer_all(), ec);
	TEST_CHECK(!ec);
	return length;
}

char const* message_name[] = {"choke", "unchoke", "interested", "not_interested"
	, "have", "bitfield", "request", "piece", "cancel", "dht_port", "", "", ""
	, "suggest_piece", "have_all", "have_none", "reject_request", "allowed_fast"};

void send_allow_fast(stream_socket& s, int piece)
{
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x11\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	asio::error_code ec;
	asio::write(s, asio::buffer(msg, 9), asio::transfer_all(), ec);
	TEST_CHECK(!ec);
}

void send_suggest_piece(stream_socket& s, int piece)
{
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x0d\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	asio::error_code ec;
	asio::write(s, asio::buffer(msg, 9), asio::transfer_all(), ec);
	TEST_CHECK(!ec);
}

void send_unchoke(stream_socket& s)
{
	char msg[] = "\0\0\0\x01\x01";
	asio::error_code ec;
	asio::write(s, asio::buffer(msg, 5), asio::transfer_all(), ec);
	TEST_CHECK(!ec);
}

void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer)
{
	char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
		"                    " // space for info-hash
		"aaaaaaaaaaaaaaaaaaaa" // peer-id
		"\0\0\0\x01\x0e"; // have_all
	asio::error_code ec;
	std::memcpy(handshake + 28, ih.begin(), 20);
	asio::write(s, asio::buffer(handshake, sizeof(handshake) - 1), asio::transfer_all(), ec);
	TEST_CHECK(!ec);

	// read handshake
	asio::read(s, asio::buffer(buffer, 68), asio::transfer_all(), ec);
	TEST_CHECK(!ec);

	TEST_CHECK(buffer[0] == 19);
	TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0);

	char* extensions = buffer + 20;
	// check for fast extension support
	TEST_CHECK(extensions[7] & 0x4);

#ifndef TORRENT_DISABLE_EXTENSIONS
	// check for extension protocol support
	TEST_CHECK(extensions[5] & 0x10);
#endif

#ifndef TORRENT_DISABLE_DHT
	// check for DHT support
	TEST_CHECK(extensions[7] & 0x1);
#endif

	TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0);
}

// makes sure that pieces that are allowed and then
// rejected aren't requested again
void test_reject_fast()
{
	boost::intrusive_ptr<torrent_info> t = create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
	ses1.add_torrent(t, "./tmp1");

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1"), ses1.listen_port()));

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> allowed_fast;
	allowed_fast.push_back(0);
	allowed_fast.push_back(1);
	allowed_fast.push_back(2);
	allowed_fast.push_back(3);

	std::for_each(allowed_fast.begin(), allowed_fast.end()
		, bind(&send_allow_fast, boost::ref(s), _1));

	while (!allowed_fast.empty())
	{
		read_message(s, recv_buffer);
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << message_name[msg] << std::endl;
		else
			std::cerr << msg << std::endl;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(allowed_fast.begin()
			, allowed_fast.end(), piece);
		TEST_CHECK(i != allowed_fast.end());
		if (i != allowed_fast.end())
			allowed_fast.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		asio::error_code ec;
		asio::write(s, asio::buffer("\0\0\0\x0d", 4), asio::transfer_all(), ec);
		TEST_CHECK(!ec);
		asio::write(s, asio::buffer(recv_buffer, 13), asio::transfer_all(), ec);
		TEST_CHECK(!ec);
	}
}

void test_respect_suggest()
{
	boost::intrusive_ptr<torrent_info> t = create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
	ses1.add_torrent(t, "./tmp1");

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1"), ses1.listen_port()));

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> suggested;
	suggested.push_back(0);
	suggested.push_back(1);
	suggested.push_back(2);
	suggested.push_back(3);

	std::for_each(suggested.begin(), suggested.end()
		, bind(&send_suggest_piece, boost::ref(s), _1));

	send_unchoke(s);

	int fail_counter = 100;
	while (!suggested.empty() && fail_counter > 0)
	{
		read_message(s, recv_buffer);
		std::cerr << "msg: ";
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << message_name[msg] << std::endl;
		else
			std::cerr << msg << std::endl;
		fail_counter--;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(suggested.begin()
			, suggested.end(), piece);
		TEST_CHECK(i != suggested.end());
		if (i != suggested.end())
			suggested.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		asio::error_code ec;
		asio::write(s, asio::buffer("\0\0\0\x0d", 4), asio::transfer_all(), ec);
		TEST_CHECK(!ec);
		asio::write(s, asio::buffer(recv_buffer, 13), asio::transfer_all(), ec);
		TEST_CHECK(!ec);
	}
	TEST_CHECK(fail_counter > 0);
}

int test_main()
{
	test_reject_fast();
	test_respect_suggest();
	return 0;
}

<commit_msg>more verbose logging in test_fast_extension and avoids infinite loops in case of failures<commit_after>#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/io.hpp"
#include <cstring>
#include <asio/read.hpp>
#include <asio/write.hpp>
#include <boost/bind.hpp>

using namespace libtorrent;

int read_message(stream_socket& s, char* buffer)
{
	using namespace libtorrent::detail;
	asio::error_code ec;
	asio::read(s, asio::buffer(buffer, 4), asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << ec.message() << std::endl;
		exit(1);
	}
	char* ptr = buffer;
	int length = read_int32(ptr);

	asio::read(s, asio::buffer(buffer, length), asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << ec.message() << std::endl;
		exit(1);
	}
	return length;
}

char const* message_name[] = {"choke", "unchoke", "interested", "not_interested"
	, "have", "bitfield", "request", "piece", "cancel", "dht_port", "", "", ""
	, "suggest_piece", "have_all", "have_none", "reject_request", "allowed_fast"};

void send_allow_fast(stream_socket& s, int piece)
{
	std::cout << "send allow fast: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x11\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	asio::error_code ec;
	asio::write(s, asio::buffer(msg, 9), asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << ec.message() << std::endl;
		exit(1);
	}
}

void send_suggest_piece(stream_socket& s, int piece)
{
	std::cout << "send suggest piece: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x0d\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	asio::error_code ec;
	asio::write(s, asio::buffer(msg, 9), asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << ec.message() << std::endl;
		exit(1);
	}
}

void send_unchoke(stream_socket& s)
{
	std::cout << "send unchoke" << std::endl;
	char msg[] = "\0\0\0\x01\x01";
	asio::error_code ec;
	asio::write(s, asio::buffer(msg, 5), asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << ec.message() << std::endl;
		exit(1);
	}
}

void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer)
{
	char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
		"                    " // space for info-hash
		"aaaaaaaaaaaaaaaaaaaa" // peer-id
		"\0\0\0\x01\x0e"; // have_all
	std::cout << "send handshake" << std::endl;
	asio::error_code ec;
	std::memcpy(handshake + 28, ih.begin(), 20);
	asio::write(s, asio::buffer(handshake, sizeof(handshake) - 1), asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << ec.message() << std::endl;
		exit(1);
	}

	// read handshake
	asio::read(s, asio::buffer(buffer, 68), asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << ec.message() << std::endl;
		exit(1);
	}
	std::cout << "received handshake" << std::endl;

	TEST_CHECK(buffer[0] == 19);
	TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0);

	char* extensions = buffer + 20;
	// check for fast extension support
	TEST_CHECK(extensions[7] & 0x4);

#ifndef TORRENT_DISABLE_EXTENSIONS
	// check for extension protocol support
	TEST_CHECK(extensions[5] & 0x10);
#endif

#ifndef TORRENT_DISABLE_DHT
	// check for DHT support
	TEST_CHECK(extensions[7] & 0x1);
#endif

	TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0);
}

// makes sure that pieces that are allowed and then
// rejected aren't requested again
void test_reject_fast()
{
	boost::intrusive_ptr<torrent_info> t = create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
	ses1.add_torrent(t, "./tmp1");

	test_sleep(1000000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1"), ses1.listen_port()));

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> allowed_fast;
	allowed_fast.push_back(0);
	allowed_fast.push_back(1);
	allowed_fast.push_back(2);
	allowed_fast.push_back(3);

	std::for_each(allowed_fast.begin(), allowed_fast.end()
		, bind(&send_allow_fast, boost::ref(s), _1));

	while (!allowed_fast.empty())
	{
		read_message(s, recv_buffer);
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << message_name[msg] << std::endl;
		else
			std::cerr << msg << std::endl;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(allowed_fast.begin()
			, allowed_fast.end(), piece);
		TEST_CHECK(i != allowed_fast.end());
		if (i != allowed_fast.end())
			allowed_fast.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		asio::error_code ec;
		asio::write(s, asio::buffer("\0\0\0\x0d", 4), asio::transfer_all(), ec);
		if (ec)
		{
			std::cout << ec.message() << std::endl;
			exit(1);
		}
		asio::write(s, asio::buffer(recv_buffer, 13), asio::transfer_all(), ec);
		std::cout << ec.message() << std::endl;
		if (ec)
		{
			std::cout << ec.message() << std::endl;
			exit(1);
		}
	}
}

void test_respect_suggest()
{
	boost::intrusive_ptr<torrent_info> t = create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
	ses1.add_torrent(t, "./tmp1");

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1"), ses1.listen_port()));

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> suggested;
	suggested.push_back(0);
	suggested.push_back(1);
	suggested.push_back(2);
	suggested.push_back(3);

	std::for_each(suggested.begin(), suggested.end()
		, bind(&send_suggest_piece, boost::ref(s), _1));

	send_unchoke(s);

	int fail_counter = 100;
	while (!suggested.empty() && fail_counter > 0)
	{
		read_message(s, recv_buffer);
		std::cerr << "msg: ";
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << message_name[msg] << std::endl;
		else
			std::cerr << msg << std::endl;
		fail_counter--;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(suggested.begin()
			, suggested.end(), piece);
		TEST_CHECK(i != suggested.end());
		if (i != suggested.end())
			suggested.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		asio::error_code ec;
		asio::write(s, asio::buffer("\0\0\0\x0d", 4), asio::transfer_all(), ec);
		if (ec)
		{
			std::cout << ec.message() << std::endl;
			exit(1);
		}
		asio::write(s, asio::buffer(recv_buffer, 13), asio::transfer_all(), ec);
		if (ec)
		{
			std::cout << ec.message() << std::endl;
			exit(1);
		}
	}
	TEST_CHECK(fail_counter > 0);
}

int test_main()
{
	test_reject_fast();
	test_respect_suggest();
	return 0;
}

<|endoftext|>


<commit_before>//  (C) Copyright Gennadiy Rozental 2001-2012.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : tests floating point comparison algorithms
// ***************************************************************************

// Boost.Test
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

// Boost
#include <boost/mpl/list.hpp>
#include <boost/bind.hpp>

// STL
#include <functional>

using namespace boost;
using namespace boost::unit_test;
using namespace boost::test_tools;

bool not_func( bool argb ) { return !argb; }

//____________________________________________________________________________//

typedef boost::mpl::list<float,double,long double> test_types;

BOOST_AUTO_TEST_CASE_TEMPLATE( test_BOOST_CHECK_CLOSE, FPT, test_types )
{
#define CHECK_CLOSE( first, second, e )     \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_CHECK_CLOSE( fp1, fp2, epsilon ); \
/**/

#ifdef BOOST_TEST_NO_OLD_TOOLS

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_TEST( fp1 != fp2, fpc::percent_tolerance( epsilon ) ); \

#else

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_CHECK( !check_is_close( fp1, fp2, ::fpc::percent_tolerance( epsilon ) ) ); \
/**/
#endif

    FPT fp1, fp2, epsilon;

    CHECK_CLOSE( 1, 1, 0 );

    CHECK_NOT_CLOSE( 0, 1e-20, 1e-5 );
    CHECK_NOT_CLOSE( 0, 1e-30, 1e-5 );
    CHECK_NOT_CLOSE( 0, -1e-10, 0.1 );
    CHECK_NOT_CLOSE( 0.123456, 0.123457, 1e-4 );

    CHECK_CLOSE( 0.123456, 0.123457, 1e-3 );

    CHECK_NOT_CLOSE( 0.123456, -0.123457, 1e-3 );

    CHECK_CLOSE( 1.23456e28, 1.23457e28, 1e-3 );

    CHECK_CLOSE( 1.23456e-10, 1.23457e-10, 1e-3 );
    CHECK_NOT_CLOSE( 1.111e-10, 1.112e-10, 0.08999 );
    CHECK_CLOSE( 1.112e-10, 1.111e-10, 0.1 );

    CHECK_CLOSE( 1, 1.0001, 1.1e-2 );
    CHECK_CLOSE( 1.0002, 1.0001, 1.1e-2 );

    CHECK_NOT_CLOSE( 1, 1.0002, 1.1e-2 );

#undef CHECK_CLOSE
#undef CHECK_NOT_CLOSE
}

//____________________________________________________________________________//

BOOST_AUTO_TEST_CASE_TEMPLATE( test_CHECK_CLOSE_FRACTION, FPT, test_types )
{
#define CHECK_CLOSE( first, second, e )     \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_CHECK_CLOSE( fp1, fp2, epsilon ); \
/**/

#ifdef BOOST_TEST_NO_OLD_TOOLS

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_TEST( fp1 != fp2, epsilon );      \

#else

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_CHECK( !check_is_close( fp1, fp2, epsilon ) ); \
/**/
#endif

    FPT fp1, fp2, epsilon;

    CHECK_CLOSE( 1, 1, 0 );

    CHECK_NOT_CLOSE( 0, 1e-20, 1e-5 );
    CHECK_NOT_CLOSE( 0, 1e-30, 1e-5 );
    CHECK_NOT_CLOSE( 0, -1e-10, 0.1 );
    CHECK_NOT_CLOSE( 0.123456, 0.123457, 1e-6 );

    CHECK_CLOSE( 0.123456, 0.123457, 1e-3 );

    CHECK_NOT_CLOSE( 0.123456, -0.123457, 1e-3 );

    CHECK_CLOSE( 1.23456e28, 1.23457e28, 1e-3 );

    CHECK_CLOSE( 1.23456e-10, 1.23457e-10, 1e-3 );
    CHECK_NOT_CLOSE( 1.111e-10, 1.112e-10, 0.0008999 );
    CHECK_CLOSE( 1.112e-10, 1.111e-10, 0.1 );

    CHECK_CLOSE( 1, 1.0001, 1.1e-2 );
    CHECK_CLOSE( 1.0002, 1.0001, 1.1e-2 );

    CHECK_NOT_CLOSE( 1, 1.0002, 1.1e-4 );

#undef CHECK_CLOSE
#undef CHECK_NOT_CLOSE
}

//____________________________________________________________________________//

BOOST_AUTO_TEST_CASE( test_type_mismatch )
{
    BOOST_CHECK_CLOSE_FRACTION( 2., 2.1, 0.06 );
    BOOST_CHECK_CLOSE( 2.1, 2., 6. );
    BOOST_CHECK_CLOSE( 2.1, 2.f, 6. );
}

//____________________________________________________________________________//

BOOST_AUTO_TEST_CASE( test_CHECK_SMALL )
{
    BOOST_CHECK_SMALL( 1e-6, 1e-5 );
    BOOST_CHECK_SMALL( -1e-6, 1e-5 );

    BOOST_TEST( 1e-6 != 0., 1e-7 );
}

//____________________________________________________________________________//

namespace fpc = boost::math::fpc;

BOOST_AUTO_TEST_CASE( test_close_at_tolerance )
{
    double fp1     = 1.00000001;
    double fp2     = 1.00000002;
    double epsilon = 1e-6;

//    ::fpc::close_at_tolerance<double> pred( ::fpc::percent_tolerance( epsilon ), ::fpc::FPC_WEAK );
//    BOOST_CHECK_PREDICATE( pred, (fp1)(fp2) );

//    BOOST_CHECK_PREDICATE( bind(not_func, bind(check_is_close, _1, _2, _3)),
//                           (fp1)(fp2)( ::fpc::percent_tolerance( epsilon )) );

    fp1     = 1.23456e-10;
    fp2     = 1.23457e-10;
    epsilon = 8.1e-4;

//    BOOST_CHECK_PREDICATE( ::fpc::close_at_tolerance<double>( ::fpc::percent_tolerance( epsilon ), ::fpc::FPC_WEAK ), (fp1)(fp2) );
//    BOOST_CHECK_PREDICATE(
//        bind(not_func,
//             bind( ::fpc::close_at_tolerance<double>( ::fpc::percent_tolerance( epsilon ) ), _1, _2)), (fp1)(fp2) );
}

//____________________________________________________________________________//

// EOF
<commit_msg>ifdef new tool usage<commit_after>//  (C) Copyright Gennadiy Rozental 2001-2012.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : tests floating point comparison algorithms
// ***************************************************************************

// Boost.Test
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

// Boost
#include <boost/mpl/list.hpp>
#include <boost/bind.hpp>

// STL
#include <functional>

using namespace boost;
using namespace boost::unit_test;
using namespace boost::test_tools;

bool not_func( bool argb ) { return !argb; }

//____________________________________________________________________________//

typedef boost::mpl::list<float,double,long double> test_types;

BOOST_AUTO_TEST_CASE_TEMPLATE( test_BOOST_CHECK_CLOSE, FPT, test_types )
{
#define CHECK_CLOSE( first, second, e )     \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_CHECK_CLOSE( fp1, fp2, epsilon ); \
/**/

#ifdef BOOST_TEST_NO_OLD_TOOLS

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_TEST( fp1 != fp2, fpc::percent_tolerance( epsilon ) ); \

#else

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_TEST( !check_is_close( fp1, fp2, ::fpc::percent_tolerance( epsilon ) ) ); \
/**/
#endif

    FPT fp1, fp2, epsilon;

    CHECK_CLOSE( 1, 1, 0 );

    CHECK_NOT_CLOSE( 0, 1e-20, 1e-5 );
    CHECK_NOT_CLOSE( 0, 1e-30, 1e-5 );
    CHECK_NOT_CLOSE( 0, -1e-10, 0.1 );
    CHECK_NOT_CLOSE( 0.123456, 0.123457, 1e-4 );

    CHECK_CLOSE( 0.123456, 0.123457, 1e-3 );

    CHECK_NOT_CLOSE( 0.123456, -0.123457, 1e-3 );

    CHECK_CLOSE( 1.23456e28, 1.23457e28, 1e-3 );

    CHECK_CLOSE( 1.23456e-10, 1.23457e-10, 1e-3 );
    CHECK_NOT_CLOSE( 1.111e-10, 1.112e-10, 0.08999 );
    CHECK_CLOSE( 1.112e-10, 1.111e-10, 0.1 );

    CHECK_CLOSE( 1, 1.0001, 1.1e-2 );
    CHECK_CLOSE( 1.0002, 1.0001, 1.1e-2 );

    CHECK_NOT_CLOSE( 1, 1.0002, 1.1e-2 );

#undef CHECK_CLOSE
#undef CHECK_NOT_CLOSE
}

//____________________________________________________________________________//

BOOST_AUTO_TEST_CASE_TEMPLATE( test_CHECK_CLOSE_FRACTION, FPT, test_types )
{
#define CHECK_CLOSE( first, second, e )     \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_CHECK_CLOSE( fp1, fp2, epsilon ); \
/**/

#ifdef BOOST_TEST_NO_OLD_TOOLS

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_TEST( fp1 != fp2, epsilon );      \

#else

#define CHECK_NOT_CLOSE( first, second, e ) \
    fp1     = static_cast<FPT>(first);      \
    fp2     = static_cast<FPT>(second);     \
    epsilon = static_cast<FPT>(e);          \
                                            \
    BOOST_TEST( !check_is_close( fp1, fp2, epsilon ) ); \
/**/
#endif

    FPT fp1, fp2, epsilon;

    CHECK_CLOSE( 1, 1, 0 );

    CHECK_NOT_CLOSE( 0, 1e-20, 1e-5 );
    CHECK_NOT_CLOSE( 0, 1e-30, 1e-5 );
    CHECK_NOT_CLOSE( 0, -1e-10, 0.1 );
    CHECK_NOT_CLOSE( 0.123456, 0.123457, 1e-6 );

    CHECK_CLOSE( 0.123456, 0.123457, 1e-3 );

    CHECK_NOT_CLOSE( 0.123456, -0.123457, 1e-3 );

    CHECK_CLOSE( 1.23456e28, 1.23457e28, 1e-3 );

    CHECK_CLOSE( 1.23456e-10, 1.23457e-10, 1e-3 );
    CHECK_NOT_CLOSE( 1.111e-10, 1.112e-10, 0.0008999 );
    CHECK_CLOSE( 1.112e-10, 1.111e-10, 0.1 );

    CHECK_CLOSE( 1, 1.0001, 1.1e-2 );
    CHECK_CLOSE( 1.0002, 1.0001, 1.1e-2 );

    CHECK_NOT_CLOSE( 1, 1.0002, 1.1e-4 );

#undef CHECK_CLOSE
#undef CHECK_NOT_CLOSE
}

//____________________________________________________________________________//

BOOST_AUTO_TEST_CASE( test_type_mismatch )
{
    BOOST_CHECK_CLOSE_FRACTION( 2., 2.1, 0.06 );
    BOOST_CHECK_CLOSE( 2.1, 2., 6. );
    BOOST_CHECK_CLOSE( 2.1, 2.f, 6. );
}

//____________________________________________________________________________//

BOOST_AUTO_TEST_CASE( test_CHECK_SMALL )
{
    BOOST_CHECK_SMALL( 1e-6, 1e-5 );
    BOOST_CHECK_SMALL( -1e-6, 1e-5 );

#ifndef BOOST_TEST_NO_NEW_TOOLS
    BOOST_TEST( 1e-6 != 0., 1e-7 );
#endif
}

//____________________________________________________________________________//

namespace fpc = boost::math::fpc;

BOOST_AUTO_TEST_CASE( test_close_at_tolerance )
{
    double fp1     = 1.00000001;
    double fp2     = 1.00000002;
    double epsilon = 1e-6;

//    ::fpc::close_at_tolerance<double> pred( ::fpc::percent_tolerance( epsilon ), ::fpc::FPC_WEAK );
//    BOOST_CHECK_PREDICATE( pred, (fp1)(fp2) );

//    BOOST_CHECK_PREDICATE( bind(not_func, bind(check_is_close, _1, _2, _3)),
//                           (fp1)(fp2)( ::fpc::percent_tolerance( epsilon )) );

    fp1     = 1.23456e-10;
    fp2     = 1.23457e-10;
    epsilon = 8.1e-4;

//    BOOST_CHECK_PREDICATE( ::fpc::close_at_tolerance<double>( ::fpc::percent_tolerance( epsilon ), ::fpc::FPC_WEAK ), (fp1)(fp2) );
//    BOOST_CHECK_PREDICATE(
//        bind(not_func,
//             bind( ::fpc::close_at_tolerance<double>( ::fpc::percent_tolerance( epsilon ) ), _1, _2)), (fp1)(fp2) );
}

//____________________________________________________________________________//

// EOF
<|endoftext|>