<commit_before>#include "TSVFileStream.h"
#include "Helper.h"
#include <QStringList>

TSVFileStream::TSVFileStream(QString filename, char separator, char comment)
	: filename_(filename)
	, separator_(separator)
	, comment_(comment)
	, file_(filename)
	, line_(0)
{
	//open
	bool open_status = true;
	if (filename=="")
	{
		open_status = file_.open(stdin, QFile::ReadOnly | QFile::Text);
	}
	else
	{
		open_status = file_.open(QFile::ReadOnly | QFile::Text);
	}
	if (!open_status)
	{
		THROW(FileAccessException, "Could not open file for reading: '" + filename + "'!");
	}

	//read comments and headers
	QByteArray double_quote = QByteArray(2, comment);
	next_line_ = double_quote;
	while(next_line_.startsWith(comment))
	{
		if (next_line_.startsWith(double_quote))
		{
			if (next_line_.trimmed()!=double_quote)
			{
				comments_.append(next_line_);
			}
		}
		else if (next_line_.startsWith(comment))
		{
			header_ = next_line_.mid(1).split(separator);
		}

		next_line_ = file_.readLine();
		while (next_line_.endsWith('\n') || next_line_.endsWith('\r')) next_line_.chop(1);
		++line_;
	}

	//no first line
	if (file_.atEnd() && next_line_=="") next_line_ = QByteArray();

	//determine number of columns if no header is present
	if (header_.isEmpty())
	{
		for(int i=0; i<next_line_.split(separator).count(); ++i)
		{
			header_.append("");
		}
	}
}

TSVFileStream::~TSVFileStream()
{
	file_.close();
}

QByteArrayList TSVFileStream::readLine()
{
	//handle first content line
	if (!next_line_.isNull())
	{
		if (next_line_=="")
		{
			next_line_ = QByteArray();
			return QByteArrayList();
		}
		QByteArrayList parts = next_line_.split(separator_);
		if (parts.count()!=columns())
		{
			THROW(FileParseException, "Expected " + QString::number(columns()) + " columns, but got " + QString::number(parts.count()) + " columns in line 1 of file " + filename_);
		}
		next_line_ = QByteArray();
		return parts;
	}

	//handle second to last content line
	QByteArray line = file_.readLine();
	while (line.endsWith('\n') || line.endsWith('\r')) line.chop(1);
	++line_;

	if (line=="")
	{
		return QByteArrayList();
	}
	QByteArrayList parts = line.split(separator_);
	if (parts.count()!=columns())
	{
		THROW(FileParseException, "Expected " + QString::number(columns()) + " columns, but got " + QString::number(parts.count()) + " columns in line " + QString::number(line_) + " of file " + filename_);
	}
	return parts;
}

int TSVFileStream::colIndex(QByteArray name, bool error_when_missing)
{
	//find matching indices
	QVector<int> hits;
	for (int i=0; i<columns(); ++i)
	{
		if (header_[i]==name)
		{
			hits.append(i);
		}
	}

	//error handling
	if (hits.count()!=1)
	{
		if (error_when_missing)
		{
			if (hits.count()==0)
			{
				THROW(CommandLineParsingException, "Could not find column name '" + name + "' in column headers!");
			}
			if (hits.count()>1)
			{
				THROW(CommandLineParsingException, "Found column name '" + name + "' more than once in column headers!");
			}
		}
		else
		{
			return -1;
		}
	}

	return hits[0];
}

QVector<int> TSVFileStream::checkColumns(const QByteArrayList& col_names, bool numeric)
{
	QVector<int> col_indices;

	if (numeric)
	{
		foreach(const QByteArray& part, col_names)
		{
			int col = Helper::toInt(part, "column number");
			if (col<1 || col>columns())
			{
				THROW(CommandLineParsingException, "1-based column number '" + part + "' out of range (max is " + QString::number(columns()) + ")!");
			}
			col_indices.append(col-1);
		}
	}
	else
	{
		foreach(const QByteArray& part, col_names)
		{
			col_indices.append(colIndex(part, true));
		}
	}

	return col_indices;
}
<commit_msg>TSVFileStream: minor performance tweaks.<commit_after>#include "TSVFileStream.h"
#include "Helper.h"
#include <QStringList>

TSVFileStream::TSVFileStream(QString filename, char separator, char comment)
	: filename_(filename)
	, separator_(separator)
	, comment_(comment)
	, file_(filename)
	, line_(0)
{
	//open
	bool open_status = true;
	if (filename.isEmpty())
	{
		open_status = file_.open(stdin, QFile::ReadOnly | QFile::Text);
	}
	else
	{
		open_status = file_.open(QFile::ReadOnly | QFile::Text);
	}
	if (!open_status)
	{
		THROW(FileAccessException, "Could not open file for reading: '" + filename + "'!");
	}

	//read comments and headers
	QByteArray double_quote = QByteArray(2, comment);
	next_line_ = double_quote;
	while(next_line_.startsWith(comment))
	{
		if (next_line_.startsWith(double_quote))
		{
			if (next_line_.trimmed()!=double_quote)
			{
				comments_.append(next_line_);
			}
		}
		else if (next_line_.startsWith(comment))
		{
			header_ = next_line_.mid(1).split(separator);
		}

		next_line_ = file_.readLine();
		while (next_line_.endsWith('\n') || next_line_.endsWith('\r')) next_line_.chop(1);
		++line_;
	}

	//no first line
	if (file_.atEnd() && next_line_.isEmpty()) next_line_ = QByteArray();

	//determine number of columns if no header is present
	if (header_.isEmpty())
	{
		for(int i=0; i<next_line_.split(separator).count(); ++i)
		{
			header_.append("");
		}
	}
}

TSVFileStream::~TSVFileStream()
{
	file_.close();
}

QByteArrayList TSVFileStream::readLine()
{
	//handle first content line
	if (!next_line_.isNull())
	{
		if (next_line_.isEmpty())
		{
			next_line_ = QByteArray();
			return QByteArrayList();
		}
		QByteArrayList parts = next_line_.split(separator_);
		if (parts.count()!=columns())
		{
			THROW(FileParseException, "Expected " + QString::number(columns()) + " columns, but got " + QString::number(parts.count()) + " columns in line 1 of file " + filename_);
		}
		next_line_ = QByteArray();
		return parts;
	}

	//handle second to last content line
	QByteArray line = file_.readLine();
	while (line.endsWith('\n') || line.endsWith('\r')) line.chop(1);
	++line_;

	if (line.isEmpty())
	{
		return QByteArrayList();
	}
	QByteArrayList parts = line.split(separator_);
	if (parts.count()!=columns())
	{
		THROW(FileParseException, "Expected " + QString::number(columns()) + " columns, but got " + QString::number(parts.count()) + " columns in line " + QString::number(line_) + " of file " + filename_);
	}
	return parts;
}

int TSVFileStream::colIndex(QByteArray name, bool error_when_missing)
{
	//find matching indices
	QVector<int> hits;
	for (int i=0; i<columns(); ++i)
	{
		if (header_[i]==name)
		{
			hits.append(i);
		}
	}

	//error handling
	if (hits.count()!=1)
	{
		if (error_when_missing)
		{
			if (hits.count()==0)
			{
				THROW(CommandLineParsingException, "Could not find column name '" + name + "' in column headers!");
			}
			if (hits.count()>1)
			{
				THROW(CommandLineParsingException, "Found column name '" + name + "' more than once in column headers!");
			}
		}
		else
		{
			return -1;
		}
	}

	return hits[0];
}

QVector<int> TSVFileStream::checkColumns(const QByteArrayList& col_names, bool numeric)
{
	QVector<int> col_indices;

	if (numeric)
	{
		foreach(const QByteArray& part, col_names)
		{
			int col = Helper::toInt(part, "column number");
			if (col<1 || col>columns())
			{
				THROW(CommandLineParsingException, "1-based column number '" + part + "' out of range (max is " + QString::number(columns()) + ")!");
			}
			col_indices.append(col-1);
		}
	}
	else
	{
		foreach(const QByteArray& part, col_names)
		{
			col_indices.append(colIndex(part, true));
		}
	}

	return col_indices;
}
<|endoftext|>


<commit_before>//----------------------------  rt_normal_02.cc  ---------------------------
//    rt_normal_02.cc,v 1.3 2003/06/09 16:00:38 wolf Exp
//    Version:
//
//    Copyright (C) 2003, 2005, 2006 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  rt_normal_02.cc  ---------------------------

/*
 * Small test to analyse the equivalence of the normal component
 * on the element edges for the Raviart-Thomas elements.
 */

#include "../tests.h"
#include <base/logstream.h>

#define PRECISION 2

#include <fstream>

#include <grid/grid_generator.h>
#include <grid/grid_out.h>
#include <fe/mapping_q.h>
#include <fe/mapping_q1_eulerian.h>

#include <numerics/vectors.h>
#include <numerics/data_out.h>
#include <lac/vector.h>
#include <base/function.h>
#include <base/quadrature.h>
#include <base/quadrature_lib.h>
#include <dofs/dof_constraints.h>
#include <dofs/dof_tools.h>

#include <fe/fe_system.h>
#include <fe/fe.h>
#include <fe/fe_q.h>
#include <fe/fe_values.h>
#include <fe/fe_raviart_thomas.h>
#include <fe/fe_dgq.h>

std::ofstream logfile ("rt_normal_02/output");

/*
 * Check if the normal component is continuous over element edges.
 */

void EvaluateNormal2 (DoFHandler<2> *dof_handler,
		      Vector<double> &solution)
{
    // This quadrature rule determines the points, where the
    // continuity will be tested.
    QGauss<1> quad (6);
    Quadrature<2> qproject = QProjector<2>::project_to_all_faces (quad);

    FEFaceValues<2> fe_v_face (dof_handler->get_fe (), quad,
			       UpdateFlags(update_values    |
					   update_q_points  |
					   update_gradients |
					   update_normal_vectors |
					   update_JxW_values));

    FEValues<2> fe_v (dof_handler->get_fe (), qproject,
		      UpdateFlags(update_values    |
				  update_q_points  |
				  update_gradients |
				  update_JxW_values));

    FEValues<2> fe_v_n (dof_handler->get_fe (), qproject,
			UpdateFlags(update_values    |
				    update_q_points  |
				    update_gradients |
				    update_JxW_values));

    const unsigned int   n_q_face    = quad.n_quadrature_points;
    const unsigned int   n_q_proj    = qproject.n_quadrature_points;
    const unsigned int   n_components   = dof_handler->get_fe().n_components();
    const unsigned int   dofs_per_cell = dof_handler->get_fe().dofs_per_cell;

    deallog << "Quad Points Face " << n_q_face
	    << ", Quad Points Proj. " << n_q_proj
	    << std::endl;

    // Cell iterators
    DoFHandler<2>::active_cell_iterator cell = dof_handler->begin_active(),
	endc = dof_handler->end();

    std::vector<unsigned int> local_dof_indices (dofs_per_cell);

    for (; cell!=endc; ++cell)
    {
	cell->get_dof_indices (local_dof_indices);
	fe_v.reinit (cell);

	for (unsigned int f = 0; f < GeometryInfo<2>::faces_per_cell; ++f)
	{
	    if (!cell->face(f)->at_boundary ())
	    {
		const QProjector<2>::DataSetDescriptor offset
		    = (QProjector<2>::DataSetDescriptor::
		       face (f, cell->face_orientation(f),
			     quad.n_quadrature_points));
		fe_v_face.reinit (cell, f);

		DoFHandler<2>::active_cell_iterator cell_n = cell->neighbor (f);
		const unsigned int neighbor=cell->neighbor_of_neighbor(f);
		fe_v_n.reinit (cell_n);

		const QProjector<2>::DataSetDescriptor offset_n
		    = (QProjector<2>::DataSetDescriptor::
		       face (neighbor, cell_n->face_orientation(neighbor),
			     quad.n_quadrature_points));

		// Get values from solution vector (For Trap.Rule)
		std::vector<Vector<double> > this_value
		    (n_q_proj, Vector<double>(n_components));
		fe_v.get_function_values (solution, this_value);

		// Same for neighbor cell
		std::vector<Vector<double> > this_value_n
		    (n_q_proj, Vector<double>(n_components));
		fe_v_n.get_function_values (solution, this_value_n);

		for (unsigned int q_point=0; q_point<n_q_face; ++q_point)
		{
		    Point<2> vn = fe_v_face.normal_vector (q_point);
		    double nx = vn(0);
		    double ny = vn(1);

		    double u = this_value[q_point + offset](0);
		    double v = this_value[q_point + offset](1);

		    double u_n = this_value_n[q_point + offset_n](0);
		    double v_n = this_value_n[q_point + offset_n](1);
		    double un1 = u * nx + v * ny,
			un2 = u_n * nx + v_n * ny;

		    deallog << "QP " << q_point
			    << ", Error: "
			    << (u-u_n) * nx + (v-v_n) * ny
			    << ", u " << un1
			    << ", un " << un2
			    << ", Rat " << un2 / un1
			    << std::endl;

		    Assert (std::fabs((u-u_n) * nx + (v-v_n) * ny) < 1e-12,
			    ExcInternalError());
		}
	    }
	}
    }
}

/*
 * Check if the normal component is continuous over element edges.
 */

void EvaluateNormal (DoFHandler<2> *dof_handler,
		     Vector<double> &solution)
{
    // This quadrature rule determines the points, where the
    // continuity will be tested.
    QGauss<1> quad (6);
    FEFaceValues<2> fe_v_face (dof_handler->get_fe (), quad,
			       UpdateFlags(update_values    |
					   update_q_points  |
					   update_gradients |
					   update_normal_vectors |
					   update_JxW_values));

    FEFaceValues<2> fe_v_face_n (dof_handler->get_fe (), quad,
				 UpdateFlags(update_values    |
					     update_q_points  |
					     update_gradients |
					     update_normal_vectors |
					     update_JxW_values));

    const unsigned int   n_q_face    = quad.n_quadrature_points;
    const unsigned int   n_components   = dof_handler->get_fe().n_components();
    const unsigned int   dofs_per_cell = dof_handler->get_fe().dofs_per_cell;

    // Cell iterators
    DoFHandler<2>::active_cell_iterator cell = dof_handler->begin_active(),
	endc = dof_handler->end();

    std::vector<unsigned int> local_dof_indices (dofs_per_cell);

    for (; cell!=endc; ++cell)
    {
	cell->get_dof_indices (local_dof_indices);

	for (unsigned int f = 0; f < GeometryInfo<2>::faces_per_cell; ++f)
	{
	    if (!cell->face(f)->at_boundary ())
	    {
		fe_v_face.reinit (cell, f);

		const unsigned int neighbor=cell->neighbor_of_neighbor(f);
		fe_v_face_n.reinit (cell->neighbor (f), neighbor);

		// Get values from solution vector (For Trap.Rule)
		std::vector<Vector<double> > this_value
		    (n_q_face, Vector<double>(n_components));
		fe_v_face.get_function_values (solution, this_value);

		// Same for neighbor cell
		std::vector<Vector<double> > this_value_n
		    (n_q_face, Vector<double>(n_components));
		fe_v_face_n.get_function_values (solution, this_value_n);

		for (unsigned int q_point=0; q_point<n_q_face; ++q_point)
		{
		    Point<2> vn = fe_v_face.normal_vector (q_point);
		    double nx = vn(0);
		    double ny = vn(1);

		    double u = this_value[q_point](0);
		    double v = this_value[q_point](1);

		    double u_n = this_value_n[q_point](0);
		    double v_n = this_value_n[q_point](1);
		    double un1 = u * nx + v * ny,
			un2 = u_n * nx + v_n * ny;

		    deallog << "QP " << q_point
			    << ", Error: "
			    << (u-u_n) * nx + (v-v_n) * ny
			    << ", u " << un1
			    << ", un " << un2
			    << ", Rat " << un2 / un1
			    << std::endl;

		    Assert (std::fabs((u-u_n) * nx + (v-v_n) * ny) < 1e-12,
			    ExcInternalError());
		}
	    }
	}
    }
}

int main (int /*argc*/, char **/*argv*/)
{
  logfile.precision (PRECISION);
  logfile.setf(std::ios::fixed);
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  Triangulation<2> tria_test;
  DoFHandler<2> *dof_handler;
  Point<2> p1 (0,0),
    p2 (1, 1);
  std::vector<unsigned int> sub_div;

  sub_div.push_back (1);
  sub_div.push_back (4);

  GridGenerator::subdivided_hyper_rectangle (tria_test, sub_div, p1, p2);
  tria_test.refine_global (2);
  tria_test.distort_random (0.05);

  // Create a DoFHandler
  FE_RaviartThomas<2> fe (1);
  dof_handler = new DoFHandler<2> (tria_test);
  dof_handler->distribute_dofs (fe);

  // Alloc some DoFs
  Vector<double> solution;
  solution.reinit (dof_handler->n_dofs ());

  // Fill solution vector with random values between 0 and 1.
  for (unsigned int i = 0; i < dof_handler->n_dofs (); ++i)
      solution(i) = (double) rand () / (double) RAND_MAX;

  // Now check if the function is continuous in normal
  // direction.
  EvaluateNormal2 (dof_handler, solution);

  delete (dof_handler);
  return (0);
}
<commit_msg>Adjust to new interface of QProjector.<commit_after>//----------------------------  rt_normal_02.cc  ---------------------------
//    rt_normal_02.cc,v 1.3 2003/06/09 16:00:38 wolf Exp
//    Version:
//
//    Copyright (C) 2003, 2005, 2006 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  rt_normal_02.cc  ---------------------------

/*
 * Small test to analyse the equivalence of the normal component
 * on the element edges for the Raviart-Thomas elements.
 */

#include "../tests.h"
#include <base/logstream.h>

#define PRECISION 2

#include <fstream>

#include <grid/grid_generator.h>
#include <grid/grid_out.h>
#include <fe/mapping_q.h>
#include <fe/mapping_q1_eulerian.h>

#include <numerics/vectors.h>
#include <numerics/data_out.h>
#include <lac/vector.h>
#include <base/function.h>
#include <base/quadrature.h>
#include <base/quadrature_lib.h>
#include <dofs/dof_constraints.h>
#include <dofs/dof_tools.h>

#include <fe/fe_system.h>
#include <fe/fe.h>
#include <fe/fe_q.h>
#include <fe/fe_values.h>
#include <fe/fe_raviart_thomas.h>
#include <fe/fe_dgq.h>

std::ofstream logfile ("rt_normal_02/output");

/*
 * Check if the normal component is continuous over element edges.
 */

void EvaluateNormal2 (DoFHandler<2> *dof_handler,
		      Vector<double> &solution)
{
    // This quadrature rule determines the points, where the
    // continuity will be tested.
    QGauss<1> quad (6);
    Quadrature<2> qproject = QProjector<2>::project_to_all_faces (quad);

    FEFaceValues<2> fe_v_face (dof_handler->get_fe (), quad,
			       UpdateFlags(update_values    |
					   update_q_points  |
					   update_gradients |
					   update_normal_vectors |
					   update_JxW_values));

    FEValues<2> fe_v (dof_handler->get_fe (), qproject,
		      UpdateFlags(update_values    |
				  update_q_points  |
				  update_gradients |
				  update_JxW_values));

    FEValues<2> fe_v_n (dof_handler->get_fe (), qproject,
			UpdateFlags(update_values    |
				    update_q_points  |
				    update_gradients |
				    update_JxW_values));

    const unsigned int   n_q_face    = quad.n_quadrature_points;
    const unsigned int   n_q_proj    = qproject.n_quadrature_points;
    const unsigned int   n_components   = dof_handler->get_fe().n_components();
    const unsigned int   dofs_per_cell = dof_handler->get_fe().dofs_per_cell;

    deallog << "Quad Points Face " << n_q_face
	    << ", Quad Points Proj. " << n_q_proj
	    << std::endl;

    // Cell iterators
    DoFHandler<2>::active_cell_iterator cell = dof_handler->begin_active(),
	endc = dof_handler->end();

    std::vector<unsigned int> local_dof_indices (dofs_per_cell);

    for (; cell!=endc; ++cell)
    {
	cell->get_dof_indices (local_dof_indices);
	fe_v.reinit (cell);

	for (unsigned int f = 0; f < GeometryInfo<2>::faces_per_cell; ++f)
	{
	    if (!cell->face(f)->at_boundary ())
	    {
		const QProjector<2>::DataSetDescriptor offset
		    = (QProjector<2>::DataSetDescriptor::
		       face (f,
			     cell->face_orientation(f),
			     cell->face_flip(f),
			     cell->face_rotation(f),
			     quad.n_quadrature_points));
		fe_v_face.reinit (cell, f);

		DoFHandler<2>::active_cell_iterator cell_n = cell->neighbor (f);
		const unsigned int neighbor=cell->neighbor_of_neighbor(f);
		fe_v_n.reinit (cell_n);

		const QProjector<2>::DataSetDescriptor offset_n
		    = (QProjector<2>::DataSetDescriptor::
		       face (neighbor,
			     cell_n->face_orientation(neighbor),
			     cell_n->face_flip(neighbor),
			     cell_n->face_rotation(neighbor),
			     quad.n_quadrature_points));

		// Get values from solution vector (For Trap.Rule)
		std::vector<Vector<double> > this_value
		    (n_q_proj, Vector<double>(n_components));
		fe_v.get_function_values (solution, this_value);

		// Same for neighbor cell
		std::vector<Vector<double> > this_value_n
		    (n_q_proj, Vector<double>(n_components));
		fe_v_n.get_function_values (solution, this_value_n);

		for (unsigned int q_point=0; q_point<n_q_face; ++q_point)
		{
		    Point<2> vn = fe_v_face.normal_vector (q_point);
		    double nx = vn(0);
		    double ny = vn(1);

		    double u = this_value[q_point + offset](0);
		    double v = this_value[q_point + offset](1);

		    double u_n = this_value_n[q_point + offset_n](0);
		    double v_n = this_value_n[q_point + offset_n](1);
		    double un1 = u * nx + v * ny,
			un2 = u_n * nx + v_n * ny;

		    deallog << "QP " << q_point
			    << ", Error: "
			    << (u-u_n) * nx + (v-v_n) * ny
			    << ", u " << un1
			    << ", un " << un2
			    << ", Rat " << un2 / un1
			    << std::endl;

		    Assert (std::fabs((u-u_n) * nx + (v-v_n) * ny) < 1e-12,
			    ExcInternalError());
		}
	    }
	}
    }
}

/*
 * Check if the normal component is continuous over element edges.
 */

void EvaluateNormal (DoFHandler<2> *dof_handler,
		     Vector<double> &solution)
{
    // This quadrature rule determines the points, where the
    // continuity will be tested.
    QGauss<1> quad (6);
    FEFaceValues<2> fe_v_face (dof_handler->get_fe (), quad,
			       UpdateFlags(update_values    |
					   update_q_points  |
					   update_gradients |
					   update_normal_vectors |
					   update_JxW_values));

    FEFaceValues<2> fe_v_face_n (dof_handler->get_fe (), quad,
				 UpdateFlags(update_values    |
					     update_q_points  |
					     update_gradients |
					     update_normal_vectors |
					     update_JxW_values));

    const unsigned int   n_q_face    = quad.n_quadrature_points;
    const unsigned int   n_components   = dof_handler->get_fe().n_components();
    const unsigned int   dofs_per_cell = dof_handler->get_fe().dofs_per_cell;

    // Cell iterators
    DoFHandler<2>::active_cell_iterator cell = dof_handler->begin_active(),
	endc = dof_handler->end();

    std::vector<unsigned int> local_dof_indices (dofs_per_cell);

    for (; cell!=endc; ++cell)
    {
	cell->get_dof_indices (local_dof_indices);

	for (unsigned int f = 0; f < GeometryInfo<2>::faces_per_cell; ++f)
	{
	    if (!cell->face(f)->at_boundary ())
	    {
		fe_v_face.reinit (cell, f);

		const unsigned int neighbor=cell->neighbor_of_neighbor(f);
		fe_v_face_n.reinit (cell->neighbor (f), neighbor);

		// Get values from solution vector (For Trap.Rule)
		std::vector<Vector<double> > this_value
		    (n_q_face, Vector<double>(n_components));
		fe_v_face.get_function_values (solution, this_value);

		// Same for neighbor cell
		std::vector<Vector<double> > this_value_n
		    (n_q_face, Vector<double>(n_components));
		fe_v_face_n.get_function_values (solution, this_value_n);

		for (unsigned int q_point=0; q_point<n_q_face; ++q_point)
		{
		    Point<2> vn = fe_v_face.normal_vector (q_point);
		    double nx = vn(0);
		    double ny = vn(1);

		    double u = this_value[q_point](0);
		    double v = this_value[q_point](1);

		    double u_n = this_value_n[q_point](0);
		    double v_n = this_value_n[q_point](1);
		    double un1 = u * nx + v * ny,
			un2 = u_n * nx + v_n * ny;

		    deallog << "QP " << q_point
			    << ", Error: "
			    << (u-u_n) * nx + (v-v_n) * ny
			    << ", u " << un1
			    << ", un " << un2
			    << ", Rat " << un2 / un1
			    << std::endl;

		    Assert (std::fabs((u-u_n) * nx + (v-v_n) * ny) < 1e-12,
			    ExcInternalError());
		}
	    }
	}
    }
}

int main (int /*argc*/, char **/*argv*/)
{
  logfile.precision (PRECISION);
  logfile.setf(std::ios::fixed);
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  Triangulation<2> tria_test;
  DoFHandler<2> *dof_handler;
  Point<2> p1 (0,0),
    p2 (1, 1);
  std::vector<unsigned int> sub_div;

  sub_div.push_back (1);
  sub_div.push_back (4);

  GridGenerator::subdivided_hyper_rectangle (tria_test, sub_div, p1, p2);
  tria_test.refine_global (2);
  tria_test.distort_random (0.05);

  // Create a DoFHandler
  FE_RaviartThomas<2> fe (1);
  dof_handler = new DoFHandler<2> (tria_test);
  dof_handler->distribute_dofs (fe);

  // Alloc some DoFs
  Vector<double> solution;
  solution.reinit (dof_handler->n_dofs ());

  // Fill solution vector with random values between 0 and 1.
  for (unsigned int i = 0; i < dof_handler->n_dofs (); ++i)
      solution(i) = (double) rand () / (double) RAND_MAX;

  // Now check if the function is continuous in normal
  // direction.
  EvaluateNormal2 (dof_handler, solution);

  delete (dof_handler);
  return (0);
}
<|endoftext|>


<commit_before>#include "btree/backfill.hpp"

#include <algorithm>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/coroutines.hpp"
#include "buffer_cache/co_functions.hpp"
#include "btree/btree_data_provider.hpp"
#include "btree/node.hpp"
#include "btree/internal_node.hpp"
#include "btree/leaf_node.hpp"
#include "btree/parallel_traversal.hpp"
#include "btree/slice.hpp"

class btree_slice_t;

struct backfill_traversal_helper_t : public btree_traversal_helper_t, public home_thread_mixin_t {

    // The deletes have to go first (since they get overridden by
    // newer sets)
    void preprocess_btree_superblock(transaction_t *txn, const btree_superblock_t *superblock) {
        assert_thread();
        if (!dump_keys_from_delete_queue(txn, superblock->delete_queue_block, since_when_, callback_)) {
            // Set since_when_ to the minimum timestamp, so that we backfill everything.
            since_when_.time = 0;
        }
    }

    void process_a_leaf(transaction_t *txn, buf_t *leaf_node_buf) {
        assert_thread();
        const leaf_node_t *data = reinterpret_cast<const leaf_node_t *>(leaf_node_buf->get_data_read());

        // Remember, we only want to process recent keys.

        int npairs = data->npairs;

        for (int i = 0; i < npairs; ++i) {
            uint16_t offset = data->pair_offsets[i];
            memcached_value_sizer_t sizer(txn->get_cache()->get_block_size());
            repli_timestamp_t recency = leaf::get_timestamp_value(&sizer, data, offset);
            const btree_leaf_pair *pair = leaf::get_pair(data, offset);

            if (recency.time >= since_when_.time) {
                const btree_value_t *value = reinterpret_cast<const btree_value_t *>(pair->value());
                boost::shared_ptr<value_data_provider_t> data_provider(value_data_provider_t::create(value, txn));
                backfill_atom_t atom;
                atom.key.assign(pair->key.size, pair->key.contents);
                atom.value = data_provider;
                atom.flags = value->mcflags();
                atom.exptime = value->exptime();
                atom.recency = recency;
                atom.cas_or_zero = value->has_cas() ? value->cas() : 0;
                callback_->on_keyvalue(atom);
            }
        }
    }

    void postprocess_internal_node(UNUSED buf_t *internal_node_buf) {
        assert_thread();
        // do nothing
    }
    void postprocess_btree_superblock(UNUSED buf_t *superblock_buf) {
        assert_thread();
        // do nothing
    }

    access_t btree_superblock_mode() { return rwi_read; }
    access_t btree_node_mode() { return rwi_read; }

    struct annoying_t : public get_subtree_recencies_callback_t {
        interesting_children_callback_t *cb;
        boost::scoped_array<block_id_t> block_ids;
        int num_block_ids;
        boost::scoped_array<repli_timestamp_t> recencies;
        repli_timestamp_t since_when;

        void got_subtree_recencies() {
            coro_t::spawn(boost::bind(&annoying_t::do_got_subtree_recencies, this));
        }

        void do_got_subtree_recencies() {
            rassert(coro_t::self());
            boost::scoped_array<block_id_t> local_block_ids;
            local_block_ids.swap(block_ids);
            int j = 0;
            for (int i = 0; i < num_block_ids; ++i) {
                if (recencies[i].time >= since_when.time) {
                    local_block_ids[j] = local_block_ids[i];
                    ++j;
                }
            }
            int num_surviving_block_ids = j;
            interesting_children_callback_t *local_cb = cb;
            delete this;
            local_cb->receive_interesting_children(local_block_ids, num_surviving_block_ids);
        }
    };

    void filter_interesting_children(transaction_t *txn, const block_id_t *block_ids, int num_block_ids, interesting_children_callback_t *cb) {
        assert_thread();
        annoying_t *fsm = new annoying_t;
        fsm->cb = cb;
        fsm->block_ids.reset(new block_id_t[num_block_ids]);
        std::copy(block_ids, block_ids + num_block_ids, fsm->block_ids.get());
        fsm->num_block_ids = num_block_ids;
        fsm->since_when = since_when_;
        fsm->recencies.reset(new repli_timestamp_t[num_block_ids]);

        txn->get_subtree_recencies(fsm->block_ids.get(), num_block_ids, fsm->recencies.get(), fsm);
    }

    backfill_callback_t *callback_;
    repli_timestamp_t since_when_;

    backfill_traversal_helper_t(backfill_callback_t *callback, repli_timestamp_t since_when)
        : callback_(callback), since_when_(since_when) { }
};

void btree_backfill(btree_slice_t *slice, repli_timestamp_t since_when, boost::shared_ptr<cache_account_t> backfill_account, backfill_callback_t *callback, order_token_t token) {
    {
        rassert(coro_t::self());

        backfill_traversal_helper_t helper(callback, since_when);

        slice->pre_begin_transaction_sink_.check_out(token);
        order_token_t begin_transaction_token = slice->pre_begin_transaction_write_mode_source_.check_in(token.tag() + "+begin_transaction_token").with_read_mode();

        transaction_t txn(slice->cache(), rwi_read_sync);

	txn.set_token(slice->post_begin_transaction_checkpoint_.check_through(token).with_read_mode());

#ifndef NDEBUG
        boost::scoped_ptr<assert_no_coro_waiting_t> no_coro_waiting(new assert_no_coro_waiting_t());
#endif

        txn.set_account(backfill_account);
        txn.snapshot();

#ifndef NDEBUG
        no_coro_waiting.reset();
#endif

        btree_parallel_traversal(&txn, slice, &helper);
    }

    callback->done_backfill();
}
<commit_msg>Made agnostic_btree_backfill.<commit_after>#include "btree/backfill.hpp"

#include <algorithm>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/coroutines.hpp"
#include "buffer_cache/co_functions.hpp"
#include "btree/btree_data_provider.hpp"
#include "btree/node.hpp"
#include "btree/internal_node.hpp"
#include "btree/leaf_node.hpp"
#include "btree/parallel_traversal.hpp"
#include "btree/slice.hpp"

class btree_slice_t;

class agnostic_backfill_callback_t : public replication::deletion_key_stream_receiver_t {
public:
    virtual void on_pair(transaction_t *txn, repli_timestamp_t recency, const btree_key_t *key, const value_type_t *value) = 0;
    virtual void done_backfill() = 0;
    virtual ~agnostic_backfill_callback_t() { }
};

struct backfill_traversal_helper_t : public btree_traversal_helper_t, public home_thread_mixin_t {

    // The deletes have to go first (since they get overridden by
    // newer sets)
    void preprocess_btree_superblock(transaction_t *txn, const btree_superblock_t *superblock) {
        assert_thread();
        if (!dump_keys_from_delete_queue(txn, superblock->delete_queue_block, since_when_, callback_)) {
            // Set since_when_ to the minimum timestamp, so that we backfill everything.
            since_when_.time = 0;
        }
    }

    void process_a_leaf(transaction_t *txn, buf_t *leaf_node_buf) {
        assert_thread();
        const leaf_node_t *data = reinterpret_cast<const leaf_node_t *>(leaf_node_buf->get_data_read());

        // Remember, we only want to process recent keys.

        int npairs = data->npairs;

        for (int i = 0; i < npairs; ++i) {
            uint16_t offset = data->pair_offsets[i];
            memcached_value_sizer_t sizer(txn->get_cache()->get_block_size());
            repli_timestamp_t recency = leaf::get_timestamp_value(&sizer, data, offset);
            const btree_leaf_pair *pair = leaf::get_pair(data, offset);

            if (recency.time >= since_when_.time) {
                callback_->on_pair(txn, recency, &pair->key, pair->value());
            }
        }
    }

    void postprocess_internal_node(UNUSED buf_t *internal_node_buf) {
        assert_thread();
        // do nothing
    }
    void postprocess_btree_superblock(UNUSED buf_t *superblock_buf) {
        assert_thread();
        // do nothing
    }

    access_t btree_superblock_mode() { return rwi_read; }
    access_t btree_node_mode() { return rwi_read; }

    struct annoying_t : public get_subtree_recencies_callback_t {
        interesting_children_callback_t *cb;
        boost::scoped_array<block_id_t> block_ids;
        int num_block_ids;
        boost::scoped_array<repli_timestamp_t> recencies;
        repli_timestamp_t since_when;

        void got_subtree_recencies() {
            coro_t::spawn(boost::bind(&annoying_t::do_got_subtree_recencies, this));
        }

        void do_got_subtree_recencies() {
            rassert(coro_t::self());
            boost::scoped_array<block_id_t> local_block_ids;
            local_block_ids.swap(block_ids);
            int j = 0;
            for (int i = 0; i < num_block_ids; ++i) {
                if (recencies[i].time >= since_when.time) {
                    local_block_ids[j] = local_block_ids[i];
                    ++j;
                }
            }
            int num_surviving_block_ids = j;
            interesting_children_callback_t *local_cb = cb;
            delete this;
            local_cb->receive_interesting_children(local_block_ids, num_surviving_block_ids);
        }
    };

    void filter_interesting_children(transaction_t *txn, const block_id_t *block_ids, int num_block_ids, interesting_children_callback_t *cb) {
        assert_thread();
        annoying_t *fsm = new annoying_t;
        fsm->cb = cb;
        fsm->block_ids.reset(new block_id_t[num_block_ids]);
        std::copy(block_ids, block_ids + num_block_ids, fsm->block_ids.get());
        fsm->num_block_ids = num_block_ids;
        fsm->since_when = since_when_;
        fsm->recencies.reset(new repli_timestamp_t[num_block_ids]);

        txn->get_subtree_recencies(fsm->block_ids.get(), num_block_ids, fsm->recencies.get(), fsm);
    }

    agnostic_backfill_callback_t *callback_;
    repli_timestamp_t since_when_;

    backfill_traversal_helper_t(agnostic_backfill_callback_t *callback, repli_timestamp_t since_when)
        : callback_(callback), since_when_(since_when) { }
};

void agnostic_btree_backfill(btree_slice_t *slice, repli_timestamp_t since_when, boost::shared_ptr<cache_account_t> backfill_account, agnostic_backfill_callback_t *callback, order_token_t token) {
    {
        rassert(coro_t::self());

        backfill_traversal_helper_t helper(callback, since_when);

        slice->pre_begin_transaction_sink_.check_out(token);
        order_token_t begin_transaction_token = slice->pre_begin_transaction_write_mode_source_.check_in(token.tag() + "+begin_transaction_token").with_read_mode();

        transaction_t txn(slice->cache(), rwi_read_sync);

	txn.set_token(slice->post_begin_transaction_checkpoint_.check_through(token).with_read_mode());

#ifndef NDEBUG
        boost::scoped_ptr<assert_no_coro_waiting_t> no_coro_waiting(new assert_no_coro_waiting_t());
#endif

        txn.set_account(backfill_account);
        txn.snapshot();

#ifndef NDEBUG
        no_coro_waiting.reset();
#endif

        btree_parallel_traversal(&txn, slice, &helper);
    }

    callback->done_backfill();
}

class agnostic_memcached_backfill_callback_t : public agnostic_backfill_callback_t {
public:
    agnostic_memcached_backfill_callback_t(backfill_callback_t *cb) : cb_(cb) { }

    void on_pair(transaction_t *txn, repli_timestamp_t recency, const btree_key_t *key, const value_type_t *val) {
        const btree_value_t *value = reinterpret_cast<const btree_value_t *>(val);
        boost::shared_ptr<value_data_provider_t> data_provider(value_data_provider_t::create(value, txn));
        backfill_atom_t atom;
        atom.key.assign(key->size, key->contents);
        atom.value = data_provider;
        atom.flags = value->mcflags();
        atom.exptime = value->exptime();
        atom.recency = recency;
        atom.cas_or_zero = value->has_cas() ? value->cas() : 0;
        cb_->on_keyvalue(atom);
    }

    void done_backfill() {
        cb_->done_backfill();
    }

    bool should_send_deletion_keys(bool can_send_deletion_keys) {
        return cb_->should_send_deletion_keys(can_send_deletion_keys);
    }

    void deletion_key(const btree_key_t *key) {
        cb_->deletion_key(key);
    }

    void done_deletion_keys() {
        cb_->done_deletion_keys();
    }

    backfill_callback_t *cb_;
};

void btree_backfill(btree_slice_t *slice, repli_timestamp_t since_when, boost::shared_ptr<cache_account_t> backfill_account, backfill_callback_t *callback, order_token_t token) {
    agnostic_memcached_backfill_callback_t agnostic_cb(callback);

    agnostic_btree_backfill(slice, since_when, backfill_account, &agnostic_cb, token);
}
<|endoftext|>


<commit_before>#include <chrono>
#include <mutex>
#include <sstream>
#include <thread>

#include <cstdio>
#include <cstring>

#include <webview.h>

class Timer {
public:
  int get() {
    this->mutex.lock();
    int n = this->ticks;
    this->mutex.unlock();
    return n;
  }
  void set(int ticks) {
    this->mutex.lock();
    this->ticks = ticks;
    this->mutex.unlock();
  }
  void incr(int n = 1) {
    this->mutex.lock();
    this->ticks = this->ticks + n;
    this->mutex.unlock();
  }
  void start(struct webview *w) {
    this->thread = std::thread(&Timer::run, this, w);
  }
  void render(struct webview *w) {
    auto n = this->get();
    std::ostringstream jscode;
    jscode << "updateTicks(" << n << ")";
    webview_eval(w, jscode.str().c_str());
  }

private:
  void run(struct webview *w) {
    for (;;) {
      std::this_thread::sleep_for(std::chrono::microseconds(100000));
      this->incr();
      webview_dispatch(w,
                       [](struct webview *w, void *arg) {
                         Timer *timer = static_cast<Timer *>(arg);
                         timer->render(w);
                       },
                       this);
    }
  }
  std::thread thread;
  std::mutex mutex;
  int ticks = 0;
  struct webview *w;
};

class TempFile {
public:
  TempFile(std::string contents) {
    this->path = std::tmpnam(nullptr);
    FILE *f = fopen(this->path.c_str(), "wb");
    fwrite(contents.c_str(), contents.length(), 1, f);
    fclose(f);
  }
  ~TempFile() { unlink(this->path.c_str()); }
  std::string url() { return "file://" + path; }

private:
  std::string path;
};

static const char *html = R"html(

    <button onclick='external.invoke_("reset")'>reset</button>
    <button onclick='external.invoke_("exit")'>exit</button>

)html";

static void timer_cb(struct webview *w, const char *arg) {
  Timer *timer = static_cast<Timer *>(w->userdata);
  if (strcmp(arg, "reset") == 0) {
    timer->set(0);
    timer->render(w);
  } else if (strcmp(arg, "exit") == 0) {
    webview_terminate(w);
  }
}

#ifdef WIN32
int WINAPI WinMain(HINSTANCE hInt, HINSTANCE hPrevInst, LPSTR lpCmdLine,
                   int nCmdShow) {
#else
int main() {
#endif
  Timer timer;
  TempFile tmp(html);
  struct webview webview = {};

  std::string url = tmp.url();

  webview.title = "Timer";
  webview.url = url.c_str();
  webview.width = 400;
  webview.height = 300;
  webview.resizable = 0;
  webview.external_invoke_cb = timer_cb;
  webview.userdata = &timer;

  webview_init(&webview);
  timer.start(&webview);
  while (webview_loop(&webview, 1) == 0)
    ;
  webview_exit(&webview);
  return 0;
}
<commit_msg>timer: detach thread to avoid crashes on exit<commit_after>#include <chrono>
#include <mutex>
#include <sstream>
#include <thread>

#include <cstdio>
#include <cstring>

#include <webview.h>

class Timer {
public:
  int get() {
    this->mutex.lock();
    int n = this->ticks;
    this->mutex.unlock();
    return n;
  }
  void set(int ticks) {
    this->mutex.lock();
    this->ticks = ticks;
    this->mutex.unlock();
  }
  void incr(int n = 1) {
    this->mutex.lock();
    this->ticks = this->ticks + n;
    this->mutex.unlock();
  }
  void start(struct webview *w) {
    this->thread = std::thread(&Timer::run, this, w);
    this->thread.detach();
  }
  void render(struct webview *w) {
    auto n = this->get();
    std::ostringstream jscode;
    jscode << "updateTicks(" << n << ")";
    webview_eval(w, jscode.str().c_str());
  }

private:
  void run(struct webview *w) {
    for (;;) {
      std::this_thread::sleep_for(std::chrono::microseconds(100000));
      this->incr();
      webview_dispatch(w,
                       [](struct webview *w, void *arg) {
                         Timer *timer = static_cast<Timer *>(arg);
                         timer->render(w);
                       },
                       this);
    }
  }
  std::thread thread;
  std::mutex mutex;
  int ticks = 0;
  struct webview *w;
};

class TempFile {
public:
  TempFile(std::string contents) {
    this->path = std::tmpnam(nullptr);
    FILE *f = fopen(this->path.c_str(), "wb");
    fwrite(contents.c_str(), contents.length(), 1, f);
    fclose(f);
  }
  ~TempFile() { unlink(this->path.c_str()); }
  std::string url() { return "file://" + path; }

private:
  std::string path;
};

static const char *html = R"html(

    <button onclick='external.invoke_("reset")'>reset</button>
    <button onclick='external.invoke_("exit")'>exit</button>

)html";

static void timer_cb(struct webview *w, const char *arg) {
  Timer *timer = static_cast<Timer *>(w->userdata);
  if (strcmp(arg, "reset") == 0) {
    timer->set(0);
    timer->render(w);
  } else if (strcmp(arg, "exit") == 0) {
    webview_terminate(w);
  }
}

#ifdef WIN32
int WINAPI WinMain(HINSTANCE hInt, HINSTANCE hPrevInst, LPSTR lpCmdLine,
                   int nCmdShow) {
#else
int main() {
#endif
  Timer timer;
  TempFile tmp(html);
  struct webview webview = {};

  std::string url = tmp.url();

  webview.title = "Timer";
  webview.url = url.c_str();
  webview.width = 400;
  webview.height = 300;
  webview.resizable = 0;
  webview.external_invoke_cb = timer_cb;
  webview.userdata = &timer;

  webview_init(&webview);
  timer.start(&webview);
  while (webview_loop(&webview, 1) == 0)
    ;
  webview_exit(&webview);
  return 0;
}
<|endoftext|>


<commit_before>#include "config.h"

#include "systemintfcmds.hpp"

#include "host-cmd-manager.hpp"
#include "host-interface.hpp"

#include <cstring>
#include <ipmid-host/cmd.hpp>
#include <ipmid/api.hpp>

void register_netfn_app_functions() __attribute__((constructor));

using namespace sdbusplus::xyz::openbmc_project::Control::server;

// For accessing Host command manager
using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
extern cmdManagerPtr& ipmid_get_host_cmd_manager();

// global enables
// bit0   - Message Receive Queue enable
// bit1   - Enable Event Message Buffer Full Interrupt
// bit2   - Enable Event Message Buffer
// bit3   - Enable System Event Logging
// bit4   - reserved
// bit5-7 - OEM 0~2 enables
static constexpr uint8_t selEnable = 0x08;
static constexpr uint8_t recvMsgQueueEnable = 0x01;
static constexpr uint8_t globalEnablesDefault = selEnable | recvMsgQueueEnable;

//-------------------------------------------------------------------
// Called by Host post response from Get_Message_Flags
//-------------------------------------------------------------------
ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                               ipmi_request_t request, ipmi_response_t response,
                               ipmi_data_len_t data_len, ipmi_context_t context)
{
    ipmi_ret_t rc = IPMI_CC_OK;

    struct oem_sel_timestamped oem_sel = {0};
    *data_len = sizeof(struct oem_sel_timestamped);

    // either id[0] -or- id[1] can be filled in. We will use id[0]
    oem_sel.id[0] = SEL_OEM_ID_0;
    oem_sel.id[1] = SEL_OEM_ID_0;
    oem_sel.type = SEL_RECORD_TYPE_OEM;

    // Following 3 bytes are from IANA Manufactre_Id field. See below
    oem_sel.manuf_id[0] = 0x41;
    oem_sel.manuf_id[1] = 0xA7;
    oem_sel.manuf_id[2] = 0x00;

    // per IPMI spec NetFuntion for OEM
    oem_sel.netfun = 0x3A;

    // Read from the Command Manager queue. What gets returned is a
    // pair of <command, data> that can be directly used here
    auto hostCmd = ipmid_get_host_cmd_manager()->getNextCommand();
    oem_sel.cmd = hostCmd.first;
    oem_sel.data[0] = hostCmd.second;

    // All '0xFF' since unused.
    std::memset(&oem_sel.data[1], 0xFF, 3);

    // Pack the actual response
    std::memcpy(response, &oem_sel, *data_len);
    return rc;
}

//---------------------------------------------------------------------
// Called by Host on seeing a SMS_ATN bit set. Return a hardcoded
// value of 0x2 indicating we need Host read some data.
//-------------------------------------------------------------------
ipmi::RspType<uint8_t> ipmiAppGetMessageFlags()
{
    // From IPMI spec V2.0 for Get Message Flags Command :
    // bit:[1] from LSB : 1b = Event Message Buffer Full.
    // Return as 0 if Event Message Buffer is not supported,
    // or when the Event Message buffer is disabled.
    // This path is used to communicate messages to the host
    // from within the phosphor::host::command::Manager
    constexpr uint8_t setEventMsgBufferFull = 0x2;
    return ipmi::responseSuccess(setEventMsgBufferFull);
}

ipmi_ret_t ipmi_app_get_bmc_global_enables(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                           ipmi_request_t request,
                                           ipmi_response_t response,
                                           ipmi_data_len_t data_len,
                                           ipmi_context_t context)
{
    ipmi_ret_t rc = IPMI_CC_OK;
    if (0 != *data_len)
    {
        *data_len = 0;
        return IPMI_CC_REQ_DATA_LEN_INVALID;
    }
    *data_len = sizeof(globalEnablesDefault);
    *reinterpret_cast<uint8_t*>(response) = globalEnablesDefault;
    return rc;
}

ipmi::RspType<> ipmiAppSetBMCGlobalEnable(
    ipmi::Context::ptr ctx, bool receiveMessageQueueInterruptEnabled,
    bool eventMessageBufferFullInterruptEnabled, bool eventMessageBufferEnabled,
    bool systemEventLogEnable, uint1_t reserved, bool OEM0Enabled,
    bool OEM1Enabled, bool OEM2Enabled)
{
    // Recv Message Queue and SEL are enabled by default.
    // Event Message buffer are disabled by default (not supported).
    // Any request that try to change the mask will be rejected
    if (!receiveMessageQueueInterruptEnabled || !systemEventLogEnable ||
        eventMessageBufferFullInterruptEnabled || eventMessageBufferEnabled ||
        OEM0Enabled || OEM1Enabled || OEM2Enabled || reserved)
    {
        return ipmi::responseInvalidFieldRequest();
    }

    return ipmi::responseSuccess();
}

namespace
{
// Static storage to keep the object alive during process life
std::unique_ptr<phosphor::host::command::Host> host
    __attribute__((init_priority(101)));
std::unique_ptr<sdbusplus::server::manager::manager> objManager
    __attribute__((init_priority(101)));
} // namespace

void register_netfn_app_functions()
{

    // <Read Event Message Buffer>
    ipmi_register_callback(NETFUN_APP, IPMI_CMD_READ_EVENT, NULL,
                           ipmi_app_read_event, SYSTEM_INTERFACE);

    // <Set BMC Global Enables>
    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
                          ipmi::app::cmdSetBmcGlobalEnables,
                          ipmi::Privilege::Admin, ipmiAppSetBMCGlobalEnable);

    // <Get BMC Global Enables>
    ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_BMC_GLOBAL_ENABLES, NULL,
                           ipmi_app_get_bmc_global_enables, SYSTEM_INTERFACE);

    // <Get Message Flags>
    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
                          ipmi::app::cmdGetMessageFlags, ipmi::Privilege::Admin,
                          ipmiAppGetMessageFlags);

    // Create new xyz.openbmc_project.host object on the bus
    auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0';

    std::unique_ptr<sdbusplus::asio::connection>& sdbusp =
        ipmid_get_sdbus_plus_handler();

    // Add sdbusplus ObjectManager.
    objManager = std::make_unique<sdbusplus::server::manager::manager>(
        *sdbusp, CONTROL_HOST_OBJ_MGR);

    host = std::make_unique<phosphor::host::command::Host>(*sdbusp,
                                                           objPath.c_str());
    sdbusp->request_name(CONTROL_HOST_BUSNAME);

    return;
}
<commit_msg>Limit the set bmc global command to system interface only<commit_after>#include "config.h"

#include "systemintfcmds.hpp"

#include "host-cmd-manager.hpp"
#include "host-interface.hpp"

#include <cstring>
#include <ipmid-host/cmd.hpp>
#include <ipmid/api.hpp>

void register_netfn_app_functions() __attribute__((constructor));

using namespace sdbusplus::xyz::openbmc_project::Control::server;

// For accessing Host command manager
using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
extern cmdManagerPtr& ipmid_get_host_cmd_manager();

// global enables
// bit0   - Message Receive Queue enable
// bit1   - Enable Event Message Buffer Full Interrupt
// bit2   - Enable Event Message Buffer
// bit3   - Enable System Event Logging
// bit4   - reserved
// bit5-7 - OEM 0~2 enables
static constexpr uint8_t selEnable = 0x08;
static constexpr uint8_t recvMsgQueueEnable = 0x01;
static constexpr uint8_t globalEnablesDefault = selEnable | recvMsgQueueEnable;

//-------------------------------------------------------------------
// Called by Host post response from Get_Message_Flags
//-------------------------------------------------------------------
ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                               ipmi_request_t request, ipmi_response_t response,
                               ipmi_data_len_t data_len, ipmi_context_t context)
{
    ipmi_ret_t rc = IPMI_CC_OK;

    struct oem_sel_timestamped oem_sel = {0};
    *data_len = sizeof(struct oem_sel_timestamped);

    // either id[0] -or- id[1] can be filled in. We will use id[0]
    oem_sel.id[0] = SEL_OEM_ID_0;
    oem_sel.id[1] = SEL_OEM_ID_0;
    oem_sel.type = SEL_RECORD_TYPE_OEM;

    // Following 3 bytes are from IANA Manufactre_Id field. See below
    oem_sel.manuf_id[0] = 0x41;
    oem_sel.manuf_id[1] = 0xA7;
    oem_sel.manuf_id[2] = 0x00;

    // per IPMI spec NetFuntion for OEM
    oem_sel.netfun = 0x3A;

    // Read from the Command Manager queue. What gets returned is a
    // pair of <command, data> that can be directly used here
    auto hostCmd = ipmid_get_host_cmd_manager()->getNextCommand();
    oem_sel.cmd = hostCmd.first;
    oem_sel.data[0] = hostCmd.second;

    // All '0xFF' since unused.
    std::memset(&oem_sel.data[1], 0xFF, 3);

    // Pack the actual response
    std::memcpy(response, &oem_sel, *data_len);
    return rc;
}

//---------------------------------------------------------------------
// Called by Host on seeing a SMS_ATN bit set. Return a hardcoded
// value of 0x2 indicating we need Host read some data.
//-------------------------------------------------------------------
ipmi::RspType<uint8_t> ipmiAppGetMessageFlags()
{
    // From IPMI spec V2.0 for Get Message Flags Command :
    // bit:[1] from LSB : 1b = Event Message Buffer Full.
    // Return as 0 if Event Message Buffer is not supported,
    // or when the Event Message buffer is disabled.
    // This path is used to communicate messages to the host
    // from within the phosphor::host::command::Manager
    constexpr uint8_t setEventMsgBufferFull = 0x2;
    return ipmi::responseSuccess(setEventMsgBufferFull);
}

ipmi_ret_t ipmi_app_get_bmc_global_enables(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                           ipmi_request_t request,
                                           ipmi_response_t response,
                                           ipmi_data_len_t data_len,
                                           ipmi_context_t context)
{
    ipmi_ret_t rc = IPMI_CC_OK;
    if (0 != *data_len)
    {
        *data_len = 0;
        return IPMI_CC_REQ_DATA_LEN_INVALID;
    }
    *data_len = sizeof(globalEnablesDefault);
    *reinterpret_cast<uint8_t*>(response) = globalEnablesDefault;
    return rc;
}

ipmi::RspType<> ipmiAppSetBMCGlobalEnable(
    ipmi::Context::ptr ctx, bool receiveMessageQueueInterruptEnabled,
    bool eventMessageBufferFullInterruptEnabled, bool eventMessageBufferEnabled,
    bool systemEventLogEnable, uint1_t reserved, bool OEM0Enabled,
    bool OEM1Enabled, bool OEM2Enabled)
{
    ipmi::ChannelInfo chInfo;

    if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
    {
        phosphor::logging::log<phosphor::logging::level::ERR>(
            "Failed to get Channel Info",
            phosphor::logging::entry("CHANNEL=%d", ctx->channel));
        return ipmi::responseUnspecifiedError();
    }

    if (chInfo.mediumType !=
        static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface))
    {
        phosphor::logging::log<phosphor::logging::level::ERR>(
            "Error - supported only in system interface");
        return ipmi::responseCommandNotAvailable();
    }

    // Recv Message Queue and SEL are enabled by default.
    // Event Message buffer are disabled by default (not supported).
    // Any request that try to change the mask will be rejected
    if (!receiveMessageQueueInterruptEnabled || !systemEventLogEnable ||
        eventMessageBufferFullInterruptEnabled || eventMessageBufferEnabled ||
        OEM0Enabled || OEM1Enabled || OEM2Enabled || reserved)
    {
        return ipmi::responseInvalidFieldRequest();
    }

    return ipmi::responseSuccess();
}

namespace
{
// Static storage to keep the object alive during process life
std::unique_ptr<phosphor::host::command::Host> host
    __attribute__((init_priority(101)));
std::unique_ptr<sdbusplus::server::manager::manager> objManager
    __attribute__((init_priority(101)));
} // namespace

void register_netfn_app_functions()
{

    // <Read Event Message Buffer>
    ipmi_register_callback(NETFUN_APP, IPMI_CMD_READ_EVENT, NULL,
                           ipmi_app_read_event, SYSTEM_INTERFACE);

    // <Set BMC Global Enables>
    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
                          ipmi::app::cmdSetBmcGlobalEnables,
                          ipmi::Privilege::Admin, ipmiAppSetBMCGlobalEnable);

    // <Get BMC Global Enables>
    ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_BMC_GLOBAL_ENABLES, NULL,
                           ipmi_app_get_bmc_global_enables, SYSTEM_INTERFACE);

    // <Get Message Flags>
    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
                          ipmi::app::cmdGetMessageFlags, ipmi::Privilege::Admin,
                          ipmiAppGetMessageFlags);

    // Create new xyz.openbmc_project.host object on the bus
    auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0';

    std::unique_ptr<sdbusplus::asio::connection>& sdbusp =
        ipmid_get_sdbus_plus_handler();

    // Add sdbusplus ObjectManager.
    objManager = std::make_unique<sdbusplus::server::manager::manager>(
        *sdbusp, CONTROL_HOST_OBJ_MGR);

    host = std::make_unique<phosphor::host::command::Host>(*sdbusp,
                                                           objPath.c_str());
    sdbusp->request_name(CONTROL_HOST_BUSNAME);

    return;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * glosm is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <glosm/OrthoViewer.hh>

#include <glosm/Projection.hh>
#include <glosm/geomath.h>

#include <glosm/util/gl.h>

OrthoViewer::OrthoViewer() : bbox_(BBoxi::ForEarth()), skew_(0.0f) {
}

void OrthoViewer::SetupViewerMatrix(const Projection& projection) const {
	Vector3i center = GetPos(projection);

	float xspan = fabs(projection.Project(Vector2i(bbox_.left, 0), center).x);
	float yspan = fabs(projection.Project(Vector2i(0, bbox_.top), center).y);

	/* Take +/- 1km as Z range */
	float zspan = fabs(projection.Project(Vector3i(center.x, center.y, 1000 * GEOM_UNITSINMETER), Vector3i(center.x, center.y, 0)).z);

	/* undefined which is aspect: x/y or y/x */
	float perspective[] = {
		1.0f/xspan, 0.0f, 0.0f, 0.0f,
		0.0f, 1.0f/yspan, 0.0f, 0.0f,
		0.0f, skew_/yspan, -1.0/zspan, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f,
	};

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(perspective);
}

Vector3i OrthoViewer::GetPos(const Projection& projection) const {
	/* `naive' center that doesn't take projection into account */
	Vector2i nearcenter = bbox_.GetCenter();

	/* real center that takes projectino into account; to minimize error, calculated relative to nearcenter */
	return projection.UnProject((projection.Project(bbox_.GetBottomLeft(), nearcenter) + projection.Project(bbox_.GetTopRight(), nearcenter))/2.0, nearcenter);
}

void OrthoViewer::SetBBox(const BBoxi& bbox) {
	bbox_ = bbox;
}

void OrthoViewer::SetBBoxForTile(int nx, int ny, int zoom) {
	bbox_.left = round(((double)nx) / pow(2.0, zoom) * GEOM_LONSPAN - GEOM_MAXLON);
	bbox_.right = round(((double)nx + 1.0) / pow(2.0, zoom) * GEOM_LONSPAN - GEOM_MAXLON);
	bbox_.bottom = round(-unmercator(((float)ny) / powf(2.0, zoom) * M_PI * 2.0 - M_PI) * GEOM_RAD_TO_DEG);
	bbox_.top = round(-unmercator(((float)ny + 1.0) / powf(2.0, zoom) * M_PI * 2.0 - M_PI) * GEOM_RAD_TO_DEG);
}

void OrthoViewer::SetSkew(float skew) {
	skew_ = skew;
}
<commit_msg>Remove unneeded OrthoViewer method<commit_after>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * glosm is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <glosm/OrthoViewer.hh>

#include <glosm/Projection.hh>
#include <glosm/geomath.h>

#include <glosm/util/gl.h>

OrthoViewer::OrthoViewer() : bbox_(BBoxi::ForEarth()), skew_(0.0f) {
}

void OrthoViewer::SetupViewerMatrix(const Projection& projection) const {
	Vector3i center = GetPos(projection);

	float xspan = fabs(projection.Project(Vector2i(bbox_.left, 0), center).x);
	float yspan = fabs(projection.Project(Vector2i(0, bbox_.top), center).y);

	/* Take +/- 1km as Z range */
	float zspan = fabs(projection.Project(Vector3i(center.x, center.y, 1000 * GEOM_UNITSINMETER), Vector3i(center.x, center.y, 0)).z);

	/* undefined which is aspect: x/y or y/x */
	float perspective[] = {
		1.0f/xspan, 0.0f, 0.0f, 0.0f,
		0.0f, 1.0f/yspan, 0.0f, 0.0f,
		0.0f, skew_/yspan, -1.0/zspan, 0.0f,
		0.0f, 0.0f, 0.0f, 1.0f,
	};

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(perspective);
}

Vector3i OrthoViewer::GetPos(const Projection& projection) const {
	/* `naive' center that doesn't take projection into account */
	Vector2i nearcenter = bbox_.GetCenter();

	/* real center that takes projectino into account; to minimize error, calculated relative to nearcenter */
	return projection.UnProject((projection.Project(bbox_.GetBottomLeft(), nearcenter) + projection.Project(bbox_.GetTopRight(), nearcenter))/2.0, nearcenter);
}

void OrthoViewer::SetBBox(const BBoxi& bbox) {
	bbox_ = bbox;
}

void OrthoViewer::SetSkew(float skew) {
	skew_ = skew;
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions Inc. 1990-2013.  All rights reserved
 */
//  TEST    Foundation::Memory
#include    "Stroika/Foundation/StroikaPreComp.h"

#include    "Stroika/Foundation/Containers/Mapping.h"
#include    "Stroika/Foundation/Debug/Assertions.h"
#include    "Stroika/Foundation/Debug/Trace.h"

#include    "Stroika/Foundation/Memory/AnyVariantValue.h"
#include    "Stroika/Foundation/Memory/Optional.h"
#include    "Stroika/Foundation/Memory/SharedByValue.h"
#include    "Stroika/Foundation/Memory/VariantValue.h"

#include    "../TestHarness/SimpleClass.h"
#include    "../TestHarness/TestHarness.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Memory;

//TODO: DOES IT EVEN NEED TO BE SAID? THese tests are a bit sparse ;-)

namespace   {
    void    Test1_Optional ()
    {
        {
            Optional<int>   x;
            VerifyTestResult (x.empty ());
            x = 1;
            VerifyTestResult (not x.empty ());
            VerifyTestResult (*x == 1);
        }
        {
            // Careful about self-assignment
            Optional<int>   x;
            x = 3;
            x = max (*x, 1);
            VerifyTestResult (x == 3);
        }
    }
    void    Test2_SharedByValue ()
    {
    }
    void    Test3_VariantValue ()
    {
        {
            VariantValue v;
            VerifyTestResult (v.empty ());
            v = String (L"hi");
            VerifyTestResult (v == L"hi");
        }
    }
    void    Test_4_Optional_Of_Mapping_Copy_Problem_ ()
    {
        using   namespace   Stroika::Foundation::Memory;
        using   namespace   Stroika::Foundation::Containers;
        Mapping<int, float>  ml1, ml2;
        ml1 = ml2;

        Optional<Mapping<int, float>>  ol1, ol2;
        if (ol2.IsPresent ()) {
            ml1 = *ol2;
        }
        ol1 = ml1;
        Optional<Mapping<int, float>>  xxxx2 (ml1);

        // fails to compile prior to 2013-09-09
        Optional<Mapping<int, float>>  xxxx1 (ol1);
        // fails to compile prior to 2013-09-09
        ol1 = ol2;
    }
    void    Test_5_AnyVariantValue_ ()
    {
        {
            VerifyTestResult (AnyVariantValue ().empty ());
            VerifyTestResult (not AnyVariantValue (1).empty ());
            VerifyTestResult (not AnyVariantValue ("1").empty ());
            //VerifyTestResult (AnyVariantValue ("1").GetType () == typeid ("1"));  // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (AnyVariantValue (1).As<int> () == 1);
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            VerifyTestResult (not v.empty ());
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (L"a");
            //VerifyTestResult (v.GetType () == typeid (L"a")); // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (not v.empty ());
            v.clear ();
            VerifyTestResult (v.empty ());
            VerifyTestResult (v.GetType () == typeid (void));
        }
        {
            struct JIM {
                int a;
            };
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (JIM ());
            VerifyTestResult (v.GetType () == typeid (JIM));
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            v = v;
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (v);
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
        }
        {
            static int nCopies = 0;
            struct Copyable {
                Copyable () {
                    ++nCopies;
                }
                Copyable (const Copyable&) {
                    ++nCopies;
                }
                ~Copyable () {
                    --nCopies;
                }
                NO_ASSIGNMENT_OPERATOR(Copyable);
            };
            {
                AnyVariantValue v;
                VerifyTestResult (v.empty ());
                v = AnyVariantValue (Copyable ());
                v = v;
                v = AnyVariantValue (AnyVariantValue (v));
                v = AnyVariantValue (AnyVariantValue (Copyable ()));
                VerifyTestResult (v.GetType () == typeid (Copyable));
            }
            VerifyTestResult (0 == nCopies);
        }
    }
}

namespace   {

    void    DoRegressionTests_ ()
    {
        Test1_Optional ();
        Test2_SharedByValue ();
        Test3_VariantValue ();
        Test_4_Optional_Of_Mapping_Copy_Problem_ ();
        Test_5_AnyVariantValue_ ();
    }
}

int main (int argc, const char* argv[])
{
    Stroika::TestHarness::Setup ();
    Stroika::TestHarness::PrintPassOrFail (DoRegressionTests_);
    return EXIT_SUCCESS;
}

<commit_msg>fixed test code for lack of NO_ASSIGNMENT_OPERATOR() macro<commit_after>/*
 * Copyright(c) Sophist Solutions Inc. 1990-2013.  All rights reserved
 */
//  TEST    Foundation::Memory
#include    "Stroika/Foundation/StroikaPreComp.h"

#include    "Stroika/Foundation/Containers/Mapping.h"
#include    "Stroika/Foundation/Debug/Assertions.h"
#include    "Stroika/Foundation/Debug/Trace.h"

#include    "Stroika/Foundation/Memory/AnyVariantValue.h"
#include    "Stroika/Foundation/Memory/Optional.h"
#include    "Stroika/Foundation/Memory/SharedByValue.h"
#include    "Stroika/Foundation/Memory/VariantValue.h"

#include    "../TestHarness/SimpleClass.h"
#include    "../TestHarness/TestHarness.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Memory;

//TODO: DOES IT EVEN NEED TO BE SAID? THese tests are a bit sparse ;-)

namespace   {
    void    Test1_Optional ()
    {
        {
            Optional<int>   x;
            VerifyTestResult (x.empty ());
            x = 1;
            VerifyTestResult (not x.empty ());
            VerifyTestResult (*x == 1);
        }
        {
            // Careful about self-assignment
            Optional<int>   x;
            x = 3;
            x = max (*x, 1);
            VerifyTestResult (x == 3);
        }
    }
    void    Test2_SharedByValue ()
    {
    }
    void    Test3_VariantValue ()
    {
        {
            VariantValue v;
            VerifyTestResult (v.empty ());
            v = String (L"hi");
            VerifyTestResult (v == L"hi");
        }
    }
    void    Test_4_Optional_Of_Mapping_Copy_Problem_ ()
    {
        using   namespace   Stroika::Foundation::Memory;
        using   namespace   Stroika::Foundation::Containers;
        Mapping<int, float>  ml1, ml2;
        ml1 = ml2;

        Optional<Mapping<int, float>>  ol1, ol2;
        if (ol2.IsPresent ()) {
            ml1 = *ol2;
        }
        ol1 = ml1;
        Optional<Mapping<int, float>>  xxxx2 (ml1);

        // fails to compile prior to 2013-09-09
        Optional<Mapping<int, float>>  xxxx1 (ol1);
        // fails to compile prior to 2013-09-09
        ol1 = ol2;
    }
    void    Test_5_AnyVariantValue_ ()
    {
        {
            VerifyTestResult (AnyVariantValue ().empty ());
            VerifyTestResult (not AnyVariantValue (1).empty ());
            VerifyTestResult (not AnyVariantValue ("1").empty ());
            //VerifyTestResult (AnyVariantValue ("1").GetType () == typeid ("1"));  // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (AnyVariantValue (1).As<int> () == 1);
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            VerifyTestResult (not v.empty ());
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (L"a");
            //VerifyTestResult (v.GetType () == typeid (L"a")); // not sure why this fails but not worthy worrying about yet
            VerifyTestResult (not v.empty ());
            v.clear ();
            VerifyTestResult (v.empty ());
            VerifyTestResult (v.GetType () == typeid (void));
        }
        {
            struct JIM {
                int a;
            };
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (JIM ());
            VerifyTestResult (v.GetType () == typeid (JIM));
        }
        {
            AnyVariantValue v;
            VerifyTestResult (v.empty ());
            v = AnyVariantValue (1);
            v = v;
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
            v = AnyVariantValue (v);
            VerifyTestResult (v.GetType () == typeid (1));
            VerifyTestResult (v.As<int> () == 1);
        }
        {
            static int nCopies = 0;
            struct Copyable {
                Copyable () {
                    ++nCopies;
                }
                Copyable (const Copyable&) {
                    ++nCopies;
                }
                ~Copyable () {
                    --nCopies;
                }
                const Copyable& operator= (const Copyable&) = delete;
            };
            {
                AnyVariantValue v;
                VerifyTestResult (v.empty ());
                v = AnyVariantValue (Copyable ());
                v = v;
                v = AnyVariantValue (AnyVariantValue (v));
                v = AnyVariantValue (AnyVariantValue (Copyable ()));
                VerifyTestResult (v.GetType () == typeid (Copyable));
            }
            VerifyTestResult (0 == nCopies);
        }
    }
}

namespace   {

    void    DoRegressionTests_ ()
    {
        Test1_Optional ();
        Test2_SharedByValue ();
        Test3_VariantValue ();
        Test_4_Optional_Of_Mapping_Copy_Problem_ ();
        Test_5_AnyVariantValue_ ();
    }
}

int main (int argc, const char* argv[])
{
    Stroika::TestHarness::Setup ();
    Stroika::TestHarness::PrintPassOrFail (DoRegressionTests_);
    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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.

*/

#include <stdlib.h>
#include "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"

void print_alert(libtorrent::alert const* a)
{
	using namespace libtorrent;

	if (alert_cast<portmap_error_alert>(a))
	{
		printf("%s","\x1b[32m");
	}
	else if (alert_cast<portmap_alert>(a))
	{
		printf("%s","\x1b[33m");
	}

	printf("[%s] %s\n", time_now_string(), a->message().c_str());
	printf("%s", "\x1b[0m");
}

int main(int argc, char* argv[])
{
	using namespace libtorrent;

	if (argc != 1)
	{
		fputs("usage: ./upnp_test\n", stderr);
		return 1;
	}

	session* s = new session;
	s->set_alert_mask(alert::port_mapping_notification);

	for (;;)
	{
		alert const* a = s->wait_for_alert(seconds(5));
		if (a == 0)
		{
			s->stop_upnp();
			break;
		}
		std::auto_ptr<alert> holder = s->pop_alert();
		print_alert(holder.get());
	}

	printf("\x1b[1m\n\n===================== done mapping. Now deleting mappings ========================\n\n\n\x1b[0m");

	for (;;)
	{
		alert const* a = s->wait_for_alert(seconds(5));
		if (a == 0) break;
		std::auto_ptr<alert> holder = s->pop_alert();
		print_alert(holder.get());
	}

	delete s;
	s = 0;

	return 0;
}

<commit_msg>update to upnp test<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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.

*/

#include <stdlib.h>
#include "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"

void print_alert(libtorrent::alert const* a)
{
	using namespace libtorrent;

	if (alert_cast<portmap_error_alert>(a))
	{
		printf("%s","\x1b[32m");
	}
	else if (alert_cast<portmap_alert>(a))
	{
		printf("%s","\x1b[33m");
	}

	printf("[%s] %s\n", time_now_string(), a->message().c_str());
	printf("%s", "\x1b[0m");
}

int main(int argc, char* argv[])
{
	using namespace libtorrent;

	if (argc != 1)
	{
		fputs("usage: ./upnp_test\n", stderr);
		return 1;
	}

	session s;
	s.set_alert_mask(alert::port_mapping_notification);

	for (;;)
	{
		alert const* a = s.wait_for_alert(seconds(5));
		if (a == 0)
		{
			s.stop_upnp();
			break;
		}
		std::auto_ptr<alert> holder = s.pop_alert();
		print_alert(holder.get());
	}

	printf("\x1b[1m\n\n===================== done mapping. Now deleting mappings ========================\n\n\n\x1b[0m");

	for (;;)
	{
		alert const* a = s.wait_for_alert(seconds(5));
		if (a == 0) break;
		std::auto_ptr<alert> holder = s.pop_alert();
		print_alert(holder.get());
	}

	return 0;
}

<|endoftext|>


<commit_before>#ifndef _C4_YML_WRITER_HPP_
#define _C4_YML_WRITER_HPP_

#include <stdio.h> // fwrite(), fputc()
#include <string.h> // memcpy()

#ifndef _C4_YML_COMMON_HPP_
#include "./common.hpp"
#endif
#ifndef _C4_YML_SPAN_HPP_
#include "./span.hpp"
#endif

namespace c4 {
namespace yml {

/** A character to be written a number of times. */
struct RepC
{
    char c;
    size_t num_times;
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A writer that outputs to a file. Defaults to stdout. */
struct WriterFile
{
    FILE *m_file;
    size_t m_pos;

    WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {}

    inline span _get(bool /*error_on_excess*/)
    {
        span sp;
        sp.str = nullptr;
        sp.len = m_pos;
        return sp;
    }

    inline void _do_write(const char c)
    {
        fwrite(&c, sizeof(char), 1, m_file);
        ++m_pos;
    }

    inline void _do_write(RepC const rc)
    {
        //fwrite(&rc.c, sizeof(char), rc.num_times, m_file); // this fails... need to investigate
        for(size_t i = 0; i < rc.num_times; ++i)
        {
            fputc(rc.c, m_file);
        }
        m_pos += rc.num_times;
    }

    inline void _do_write(cspan const& sp)
    {
        if(sp.empty()) return;
        if(m_file)
        {
            fwrite(sp.str, sp.len, 1, m_file);
        }
        m_pos += sp.len;
    }
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a writer to a string span */
struct WriterSpan
{
    span   m_span;
    size_t m_pos;

    WriterSpan(span const& sp) : m_span(sp), m_pos(0) {}

    inline span _get(bool error_on_excess)
    {
        span sp = m_span;
        if(m_pos > sp.len)
        {
            sp.len = m_pos;
            sp.str = nullptr;
            if(error_on_excess)
            {
                c4::yml::error("not enough space in the given span");
            }
        }
        sp = sp.range(0, m_pos);
        return sp;
    }

    inline void _do_write(const char c)
    {
        if(m_pos + 1 <= m_span.len)
        {
            m_span[m_pos] = c;
        }
        ++m_pos;
    }

    inline void _do_write(RepC const rc)
    {
        if(m_pos + rc.num_times <= m_span.len)
        {
            for(size_t i = 0; i < rc.num_times; ++i)
            {
                m_span[m_pos + i] = rc.c;
            }
        }
        m_pos += rc.num_times;
    }

    inline void _do_write(cspan const& sp)
    {
        if(sp.empty()) return;
        if(m_pos + sp.len <= m_span.len)
        {
            memcpy(&(m_span[m_pos]), sp.str, sp.len);
        }
        m_pos += sp.len;
    }
};

} // namespace yml
} // namespace c4

#endif /* _C4_YML_WRITER_HPP_ */
<commit_msg>fix bug in emitter<commit_after>#ifndef _C4_YML_WRITER_HPP_
#define _C4_YML_WRITER_HPP_

#include <stdio.h> // fwrite(), fputc()
#include <string.h> // memcpy()

#ifndef _C4_YML_COMMON_HPP_
#include "./common.hpp"
#endif
#ifndef _C4_YML_SPAN_HPP_
#include "./span.hpp"
#endif

namespace c4 {
namespace yml {

/** A character to be written a number of times. */
struct RepC
{
    char c;
    size_t num_times;
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A writer that outputs to a file. Defaults to stdout. */
struct WriterFile
{
    FILE *m_file;
    size_t m_pos;

    WriterFile(FILE *f = nullptr) : m_file(f ? f : stdout), m_pos(0) {}

    inline span _get(bool /*error_on_excess*/)
    {
        span sp;
        sp.str = nullptr;
        sp.len = m_pos;
        return sp;
    }

    inline void _do_write(const char c)
    {
        fwrite(&c, sizeof(char), 1, m_file);
        ++m_pos;
    }

    inline void _do_write(RepC const rc)
    {
        //fwrite(&rc.c, sizeof(char), rc.num_times, m_file); // this fails... need to investigate
        for(size_t i = 0; i < rc.num_times; ++i)
        {
            fputc(rc.c, m_file);
        }
        m_pos += rc.num_times;
    }

    inline void _do_write(cspan const& sp)
    {
        if(sp.empty()) return;
        if(m_file)
        {
            fwrite(sp.str, sp.len, 1, m_file);
        }
        m_pos += sp.len;
    }
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a writer to a string span */
struct WriterSpan
{
    span   m_span;
    size_t m_pos;

    WriterSpan(span const& sp) : m_span(sp), m_pos(0) {}

    inline span _get(bool error_on_excess)
    {
        span sp = m_span;
        if(m_pos > sp.len)
        {
            sp.len = m_pos;
            sp.str = nullptr;
            if(error_on_excess)
            {
                c4::yml::error("not enough space in the given span");
            }
            return sp;
        }
        sp = sp.range(0, m_pos);
        return sp;
    }

    inline void _do_write(const char c)
    {
        if(m_pos + 1 <= m_span.len)
        {
            m_span[m_pos] = c;
        }
        ++m_pos;
    }

    inline void _do_write(RepC const rc)
    {
        if(m_pos + rc.num_times <= m_span.len)
        {
            for(size_t i = 0; i < rc.num_times; ++i)
            {
                m_span[m_pos + i] = rc.c;
            }
        }
        m_pos += rc.num_times;
    }

    inline void _do_write(cspan const& sp)
    {
        if(sp.empty()) return;
        if(m_pos + sp.len <= m_span.len)
        {
            memcpy(&(m_span[m_pos]), sp.str, sp.len);
        }
        m_pos += sp.len;
    }
};

} // namespace yml
} // namespace c4

#endif /* _C4_YML_WRITER_HPP_ */
<|endoftext|>


<commit_before>#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include "cmm_conn_bootstrapper.h"
#include "cmm_socket.private.h"
#include "csocket_mapping.h"
#include "debug.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>

ConnBootstrapper::ConnBootstrapper(CMMSocketImpl *sk_,
                                   int bootstrap_sock_,
                                   const struct sockaddr *remote_addr_,
                                   socklen_t addrlen_)
    : sk(sk_), bootstrap_sock(bootstrap_sock_), status_(EINPROGRESS),
      addrlen(addrlen_), retry(false)
{
    remote_addr = new char[addrlen];
    memcpy(remote_addr, remote_addr_, addrlen);
}

ConnBootstrapper::~ConnBootstrapper()
{
    delete [] remote_addr;
}

void
ConnBootstrapper::stop()
{
    dbgprintf("Aborting bootstrapper for multisocket %d\n",
              sk->sock);
    shutdown(bootstrap_sock, SHUT_RDWR);
}

void
ConnBootstrapper::Finish()
{
    PthreadScopedRWLock sock_lock(&sk->my_lock, true);
    close(bootstrap_sock);
    bootstrap_sock = -1;
    dbgprintf("Exiting.\n");
}

void ConnBootstrapper::Run()
{
    char name[MAX_NAME_LEN+1];
    memset(name, 0, MAX_NAME_LEN+1);
    snprintf(name, MAX_NAME_LEN, "Bootstrapper %d", sk->sock);
    set_thread_name(name);

    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGPIPE); // ignore SIGPIPE
    pthread_sigmask(SIG_BLOCK, &sigset, NULL);

    {
        PthreadScopedRWLock sock_lock(&sk->my_lock, false);
        if (sk->is_non_blocking()) {
            dbgprintf("Non-blocking bootstrap. Bootstrap thread detaching.\n");
            detach();
        }
    }

    do {
        retry = false;

        try {
            if (bootstrap_sock != -1) {
                /* we are accepting a connection */
                dbgprintf("Accepting connection; using socket %d "
                          "to bootstrap\n", bootstrap_sock);
                int num_ifaces = sk->recv_hello(bootstrap_sock);
                sk->send_hello(bootstrap_sock);

                // connecter will connect on all of its local ifaces
                //  before sending bw/latency info.
                sk->recv_remote_listeners(bootstrap_sock, num_ifaces);

                // wait for the connecter to finish, then fill in any
                //  missing connections before sending my ifaces.
                sk->startup_csocks();
                sk->wait_for_connections();
                sk->send_local_listeners(bootstrap_sock);
            } else {
                /* we are connecting */
                assert(remote_addr);

                {
                    PthreadScopedRWLock sock_lock(&sk->my_lock, false);
                    bootstrap_sock = socket(sk->sock_family, sk->sock_type,
                                            sk->sock_protocol);
                    if (bootstrap_sock < 0) {
                        dbgprintf("Error creating bootstrap socket: %s\n",
                                  strerror(errno));
                        return;
                    }

                    if (sk->local_ifaces.empty()) {
                        dbgprintf("Error connecting bootstrap socket: no local ifaces\n");
                        return;
                    }
                    struct sockaddr_in local_addr;
                    memset(&local_addr, 0, sizeof(local_addr));
                    local_addr.sin_family = AF_INET;
                    memcpy(&local_addr.sin_addr, &sk->local_ifaces.begin()->ip_addr,
                           sizeof(local_addr.sin_addr));
                    int rc = bind(bootstrap_sock,
                                  (struct sockaddr*)&local_addr, sizeof(local_addr));

                    struct sockaddr *addr = (struct sockaddr *)remote_addr;
                    pthread_rwlock_unlock(&sk->my_lock);
                    rc = connect(bootstrap_sock, addr, addrlen);
                    pthread_rwlock_rdlock(&sk->my_lock);
                    if (rc < 0) {
                        status_ = errno;
                        dbgprintf("Error connecting bootstrap socket: %s\n",
                                  strerror(errno));
                        throw rc;
                    }
                }

                dbgprintf("Initiating connection; using socket %d "
                          "to bootstrap\n", bootstrap_sock);

                sk->send_hello(bootstrap_sock);
                int num_ifaces = sk->recv_hello(bootstrap_sock);

                // Before sending iface info, just make connections from all
                //  my local ifaces.  This way, the accept()-side will have
                //  all the connections before it needs to use any of them,
                //  and it won't try to create them.  This should avoid
                //  the race between both sides creating the same connection.
                sk->startup_csocks();
                sk->wait_for_connections();
                // After the connections are done, we still need to
                //  tell the remote side about the bw/latency of our
                //  ifaces.
                sk->send_local_listeners(bootstrap_sock);
                // during this time, the remote side will connect from
                //  all of its interfaces, if it has any besides the
                //  bootstrapping iface.
                sk->recv_remote_listeners(bootstrap_sock, num_ifaces);
            }

            // no errors; must have succeeded
            status_ = 0;
        } catch (int error_rc) {
            PthreadScopedRWLock sock_lock(&sk->my_lock, true);
            if (retry) {
                // we were interrupted by the scout bringing down this interface.
                close(bootstrap_sock);
                bootstrap_sock = -1;
                status_ = EINPROGRESS;
            } else if (status_ != EINPROGRESS) {
                status_ = ECONNREFUSED;
            }
            // fall through so write-select returns
        }
    } while (retry);

    char ch = 42;
    int rc = write(sk->write_ready_pipe[1], &ch, 1);
    assert(rc == 1);
}

void
ConnBootstrapper::restart(struct net_interface down_iface,
                          bool already_locked)
{
    /* if I'm trying to bootstrap on this interface and
     * it just went away, try another interface. */

    auto_ptr<PthreadScopedRWLock> lock;
    if (!already_locked) {
        lock.reset(new PthreadScopedRWLock(&sk->my_lock, true));
    }

    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);
    if (bootstrap_sock == -1) {
        return;
    }
    int rc = getsockname(bootstrap_sock,
                         (struct sockaddr*)&addr, &addrlen);
    if (rc == 0 && addr.sin_addr.s_addr == down_iface.ip_addr.s_addr) {
        retry = true;
        shutdown(bootstrap_sock, SHUT_RDWR);
    }
}

bool
ConnBootstrapper::succeeded()
{
    return status_ == 0;
}

bool
ConnBootstrapper::done()
{
    return status_ != EINPROGRESS;
}

int
ConnBootstrapper::status()
{
    return status_;
}
<commit_msg>Make the accepting side of the bootstrapper retry up to 3 times.<commit_after>#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include "cmm_conn_bootstrapper.h"
#include "cmm_socket.private.h"
#include "csocket_mapping.h"
#include "debug.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>

ConnBootstrapper::ConnBootstrapper(CMMSocketImpl *sk_,
                                   int bootstrap_sock_,
                                   const struct sockaddr *remote_addr_,
                                   socklen_t addrlen_)
    : sk(sk_), bootstrap_sock(bootstrap_sock_), status_(EINPROGRESS),
      addrlen(addrlen_), retry(false)
{
    remote_addr = new char[addrlen];
    memcpy(remote_addr, remote_addr_, addrlen);
}

ConnBootstrapper::~ConnBootstrapper()
{
    delete [] remote_addr;
}

void
ConnBootstrapper::stop()
{
    dbgprintf("Aborting bootstrapper for multisocket %d\n",
              sk->sock);
    shutdown(bootstrap_sock, SHUT_RDWR);
}

void
ConnBootstrapper::Finish()
{
    PthreadScopedRWLock sock_lock(&sk->my_lock, true);
    close(bootstrap_sock);
    bootstrap_sock = -1;
    dbgprintf("Exiting.\n");
}

void ConnBootstrapper::Run()
{
    char name[MAX_NAME_LEN+1];
    memset(name, 0, MAX_NAME_LEN+1);
    snprintf(name, MAX_NAME_LEN, "Bootstrapper %d", sk->sock);
    set_thread_name(name);

    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGPIPE); // ignore SIGPIPE
    pthread_sigmask(SIG_BLOCK, &sigset, NULL);

    {
        PthreadScopedRWLock sock_lock(&sk->my_lock, false);
        if (sk->is_non_blocking()) {
            dbgprintf("Non-blocking bootstrap. Bootstrap thread detaching.\n");
            detach();
        }
    }

    do {
        retry = false;
        int accept_retries = 3;
        bool accepting = (bootstrap_sock != -1);

        try {
            if (bootstrap_sock != -1) {
                /* we are accepting a connection */
                dbgprintf("Accepting connection; using socket %d "
                          "to bootstrap\n", bootstrap_sock);
                int num_ifaces = sk->recv_hello(bootstrap_sock);
                sk->send_hello(bootstrap_sock);

                // connecter will connect on all of its local ifaces
                //  before sending bw/latency info.
                sk->recv_remote_listeners(bootstrap_sock, num_ifaces);

                // wait for the connecter to finish, then fill in any
                //  missing connections before sending my ifaces.
                sk->startup_csocks();
                sk->wait_for_connections();
                sk->send_local_listeners(bootstrap_sock);
            } else {
                /* we are connecting */
                assert(remote_addr);

                {
                    PthreadScopedRWLock sock_lock(&sk->my_lock, false);
                    bootstrap_sock = socket(sk->sock_family, sk->sock_type,
                                            sk->sock_protocol);
                    if (bootstrap_sock < 0) {
                        dbgprintf("Error creating bootstrap socket: %s\n",
                                  strerror(errno));
                        return;
                    }

                    if (sk->local_ifaces.empty()) {
                        dbgprintf("Error connecting bootstrap socket: no local ifaces\n");
                        return;
                    }
                    struct sockaddr_in local_addr;
                    memset(&local_addr, 0, sizeof(local_addr));
                    local_addr.sin_family = AF_INET;
                    memcpy(&local_addr.sin_addr, &sk->local_ifaces.begin()->ip_addr,
                           sizeof(local_addr.sin_addr));
                    int rc = bind(bootstrap_sock,
                                  (struct sockaddr*)&local_addr, sizeof(local_addr));

                    struct sockaddr *addr = (struct sockaddr *)remote_addr;
                    pthread_rwlock_unlock(&sk->my_lock);
                    rc = connect(bootstrap_sock, addr, addrlen);
                    pthread_rwlock_rdlock(&sk->my_lock);
                    if (rc < 0) {
                        status_ = errno;
                        dbgprintf("Error connecting bootstrap socket: %s\n",
                                  strerror(errno));
                        throw rc;
                    }
                }

                dbgprintf("Initiating connection; using socket %d "
                          "to bootstrap\n", bootstrap_sock);

                sk->send_hello(bootstrap_sock);
                int num_ifaces = sk->recv_hello(bootstrap_sock);

                // Before sending iface info, just make connections from all
                //  my local ifaces.  This way, the accept()-side will have
                //  all the connections before it needs to use any of them,
                //  and it won't try to create them.  This should avoid
                //  the race between both sides creating the same connection.
                sk->startup_csocks();
                sk->wait_for_connections();
                // After the connections are done, we still need to
                //  tell the remote side about the bw/latency of our
                //  ifaces.
                sk->send_local_listeners(bootstrap_sock);
                // during this time, the remote side will connect from
                //  all of its interfaces, if it has any besides the
                //  bootstrapping iface.
                sk->recv_remote_listeners(bootstrap_sock, num_ifaces);
            }

            // no errors; must have succeeded
            status_ = 0;
        } catch (int error_rc) {
            if (accepting) {
                retry = ((--accept_retries) > 0);
            }

            PthreadScopedRWLock sock_lock(&sk->my_lock, true);
            if (retry) {
                // we were interrupted by the scout bringing down this interface.
                dbgprintf("Bootstrap failed; retrying\n");
                close(bootstrap_sock);
                bootstrap_sock = -1;
                status_ = EINPROGRESS;
            } else if (status_ != EINPROGRESS) {
                status_ = ECONNREFUSED;
            }
            // fall through so write-select returns
        }
    } while (retry);

    char ch = 42;
    int rc = write(sk->write_ready_pipe[1], &ch, 1);
    assert(rc == 1);
}

void
ConnBootstrapper::restart(struct net_interface down_iface,
                          bool already_locked)
{
    /* if I'm trying to bootstrap on this interface and
     * it just went away, try another interface. */

    auto_ptr<PthreadScopedRWLock> lock;
    if (!already_locked) {
        lock.reset(new PthreadScopedRWLock(&sk->my_lock, true));
    }

    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);
    if (bootstrap_sock == -1) {
        return;
    }
    int rc = getsockname(bootstrap_sock,
                         (struct sockaddr*)&addr, &addrlen);
    if (rc == 0 && addr.sin_addr.s_addr == down_iface.ip_addr.s_addr) {
        retry = true;
        shutdown(bootstrap_sock, SHUT_RDWR);
    }
}

bool
ConnBootstrapper::succeeded()
{
    return status_ == 0;
}

bool
ConnBootstrapper::done()
{
    return status_ != EINPROGRESS;
}

int
ConnBootstrapper::status()
{
    return status_;
}
<|endoftext|>